From 63867b5ad6d4cf840e81fb2f6405e7fff23c2e2b Mon Sep 17 00:00:00 2001 From: Adam Walkiewicz Date: Tue, 4 Nov 2025 08:46:55 +0100 Subject: [PATCH 1/3] Transition to UV as package manager --- .github/workflows/black.yml | 23 - .github/workflows/check_format.yml | 31 + .github/workflows/check_types.yml | 31 + .github/workflows/python-package.yml | 41 -- .github/workflows/release.yml | 100 +++ .github/workflows/tests.yml | 37 + Dockerfile | 34 - MANIFEST.in | 3 - Makefile | 61 ++ docker-compose.yaml | 23 - pyproject.toml | 50 ++ pytest.ini | 6 + requirements.txt | 6 - setup.py | 48 -- {cochar => src/cochar}/__init__.py | 0 {cochar => src/cochar}/__main__.py | 0 {cochar => src/cochar}/character.py | 0 {cochar => src/cochar}/cochar.py | 0 {cochar => src/cochar}/data/occupations.json | 0 {cochar => src/cochar}/data/popPyramid.json | 0 {cochar => src/cochar}/data/settings.json | 0 {cochar => src/cochar}/data/skills.json | 0 {cochar => src/cochar}/error.py | 0 {cochar => src/cochar}/interface.py | 0 {cochar => src/cochar}/occup.py | 0 {cochar => src/cochar}/skill.py | 0 {cochar => src/cochar}/utils.py | 0 uv.lock | 712 +++++++++++++++++++ 28 files changed, 1028 insertions(+), 178 deletions(-) delete mode 100644 .github/workflows/black.yml create mode 100644 .github/workflows/check_format.yml create mode 100644 .github/workflows/check_types.yml delete mode 100644 .github/workflows/python-package.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 Dockerfile delete mode 100644 MANIFEST.in create mode 100644 Makefile delete mode 100644 docker-compose.yaml create mode 100644 pyproject.toml create mode 100644 pytest.ini delete mode 100644 requirements.txt delete mode 100644 setup.py rename {cochar => src/cochar}/__init__.py (100%) rename {cochar => src/cochar}/__main__.py (100%) rename {cochar => src/cochar}/character.py (100%) rename {cochar => src/cochar}/cochar.py (100%) rename {cochar => src/cochar}/data/occupations.json (100%) rename {cochar => src/cochar}/data/popPyramid.json (100%) rename {cochar => src/cochar}/data/settings.json (100%) rename {cochar => src/cochar}/data/skills.json (100%) rename {cochar => src/cochar}/error.py (100%) rename {cochar => src/cochar}/interface.py (100%) rename {cochar => src/cochar}/occup.py (100%) rename {cochar => src/cochar}/skill.py (100%) rename {cochar => src/cochar}/utils.py (100%) create mode 100644 uv.lock diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml deleted file mode 100644 index 903d43d..0000000 --- a/.github/workflows/black.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Black - -on: [push] - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.11"] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install black - - name: Analysing the code with black - run: | - black $(git ls-files '*.py') diff --git a/.github/workflows/check_format.yml b/.github/workflows/check_format.yml new file mode 100644 index 0000000..e691330 --- /dev/null +++ b/.github/workflows/check_format.yml @@ -0,0 +1,31 @@ +# This workflow will install Python dependencies and check formatting with Ruff + +name: Format check with ruff + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Setup environment + run: | + make setup + - name: Check formatting with ruff + run: | + make check \ No newline at end of file diff --git a/.github/workflows/check_types.yml b/.github/workflows/check_types.yml new file mode 100644 index 0000000..1594a94 --- /dev/null +++ b/.github/workflows/check_types.yml @@ -0,0 +1,31 @@ +# This workflow will install Python dependencies and check formatting with Ruff + +name: Type check with mypy + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Setup environment + run: | + make setup + - name: Check types with mypy + run: | + make type \ No newline at end of file diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml deleted file mode 100644 index d14687b..0000000 --- a/.github/workflows/python-package.yml +++ /dev/null @@ -1,41 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python - -name: Python package - -on: - push: - branches: ["main"] - pull_request: - branches: ["main"] - -jobs: - build: - name: Test package on ${{ matrix.os }} and ${{ matrix.python-version }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - python-version: ["3.8", "3.9", "3.10", "3.11"] - - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install flake8 pytest - python -m pip install -r requirements.txt - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest - run: | - pytest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..d406727 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,100 @@ +# This workflow will upload a Python Package to PyPI when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + build-package: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Setup project environment + run: | + make setup + + - name: Build project + run: | + make build + + - name: Upload distributions + uses: actions/upload-artifact@v4 + with: + name: release-dists + path: dist/ + + pypi-publish: + runs-on: ubuntu-latest + needs: build-package + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + + # Dedicated environments with protections for publishing are strongly recommended. + # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules + environment: + name: pypi + # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: + # url: https://pypi.org/p/cochar + # + # ALTERNATIVE: if your GitHub Release name is the PyPI project version string + # ALTERNATIVE: exactly, uncomment the following line instead: + url: https://pypi.org/project/cochar/${{ github.event.release.name }} + + steps: + - name: Retrieve release distributions + uses: actions/download-artifact@v4 + with: + name: release-dists + path: dist/ + + - name: Publish release distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ + + update-release: + runs-on: ubuntu-latest + needs: build-package + + permissions: + contents: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Retrieve release distributions + uses: actions/download-artifact@v4 + with: + name: release-dists + path: dist/ + + - name: Upload Release Assets + run: gh release upload ${{ github.event.release.tag_name }} dist/* + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..65a604e --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,37 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Test with pytest + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13", "3.14"] + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + + - name: Setup environment + run: | + make setup + + - name: Test with pytest + run: | + uv run --python ${{ matrix.python-version }} pytest -m "not slow" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b167e72..0000000 --- a/Dockerfile +++ /dev/null @@ -1,34 +0,0 @@ -# Cochar - create a random character for Call of Cthulhu RPG 7th ed. -# Copyright (C) 2023 Adam Walkiewicz - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -FROM ubuntu:20.04 - -# set the working directory -WORKDIR /cochar - -RUN apt-get update -RUN apt-get upgrade --yes -RUN apt-get install python3.8 python3-pip --yes - -# install dependencies -COPY ./requirements.txt . - -RUN pip install --no-cache-dir --upgrade -r requirements.txt - -# copy the scripts to the folder -COPY . /cochar - -RUN pip install -e . diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 68cdb7c..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include LICENSE -recursive-include cochar *.py -recursive-include cochar/data * diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..95e4ba4 --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +.PHONY: setup check-uv build test clean clean_venv clean_build clean_cache format type docs check docs_serve docs_upload + +setup: check-uv uv.lock + @echo "Setting up project..." + uv sync + + +check-uv: + @if ! command -v uv > /dev/null; then \ + echo "UV is not installed"; \ + echo "Installing UV"; \ + curl -LsSf https://astral.sh/uv/install.sh | sh; \ + fi + +build: test clean_build + @echo "Building package..." + uv build + +test: tests/test_*.py + @echo "Running tests..." + @if ! uv run pytest -m "not slow"; then \ + echo "Tests failed. Building project not possible."; \ + exit 1; \ + fi + +test_all: tests/test_*.py + @echo "Running all tests..." + @if ! uv run pytest; then \ + echo "Tests failed. Building project not possible."; \ + exit 1; \ + fi + +clean: clean_venv clean_build clean_cache + +clean_venv: + @echo "Removing virtual environment.." + rm -rf .venv + +clean_build: + @echo "Removing build files..." + rm -rf dist/ + +clean_cache: + @echo "Removing all cache files and directories int the project..." + find . -name "*cache*" -type d | xargs -t -I {} rm -rf "{}" + +format: + @echo "Formatting project files with ruff..." + uv run ruff format + +check: + @echo "Checking project files with ruff..." + uv run ruff check + +type: + @echo "checking typing with mypy..." + uv run mypy . + +docs: + @echo "Building documentation..." + uv run sphinx-build -b html docs/ docs/_build/html \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index cc4ad56..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Cochar - create a random character for Call of Cthulhu RPG 7th ed. -# Copyright (C) 2023 Adam Walkiewicz - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -services: - app: - build: . - container_name: cochar-pkg - command: bash - volumes: - - .:/cochar diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5f13423 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,50 @@ +[project] +name = "cochar" +version = "2.0.0-beta.1" +description = "Add your description here" +readme = "README.md" +authors = [ + { name = "Adam Walkiewicz", email = "aj.walkiewicz@gmail.com" } +] +requires-python = ">=3.11" +dependencies = [ + "rname>=0.3.7", +] + +keywords = ["python", "cthulhu", "lovecraft", "rpg"] +classifiers = [ + # How mature is this project? + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + "Development Status :: 4 - Beta", + "Intended Audience :: Everyone", + "License :: OSI Approved :: GNU Affero General Public License v3", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] + +[project.urls] +Documentation = "https://ajwalkiewicz.github.io/cochar/_build/html/index.html" +Repository = "https://github.com/ajwalkiewicz/cochar" +Issues = "https://github.com/ajwalkiewicz/cochar/issues" + + +[project.scripts] +cochar = "cochar:main" + +[build-system] +requires = ["uv_build>=0.9.7,<0.10.0"] +build-backend = "uv_build" + +[dependency-groups] +dev = [ + "deepdiff>=8.6.1", + "mypy>=1.18.2", + "pytest>=8.4.2", + "ruff>=0.14.3", + "sphinx>=8.2.3", +] diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..a4e4d56 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,6 @@ +# pytest.ini +[pytest] +testpaths = tests +pythonpath = src +markers = + slow: marks tests as slow (deselect with '-m "not slow"') \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 7e0ed72..0000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -black==22.12.0 -deepdiff==6.2.3 -pytest==7.2.1 -rname==0.3.7 -sphinx==6.1.3 -twine==4.0.2 diff --git a/setup.py b/setup.py deleted file mode 100644 index e1fda68..0000000 --- a/setup.py +++ /dev/null @@ -1,48 +0,0 @@ -# Cochar - create a random character for Call of Cthulhu RPG 7th ed. -# Copyright (C) 2023 Adam Walkiewicz - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -import os -from setuptools import setup - -THIS_FOLDER = os.path.dirname(os.path.abspath(__file__)) - -with open(f"{THIS_FOLDER}/docs/readme.md", "r", encoding="utf-8") as fh: - long_description = fh.read() - -setup( - name="cochar", - version="1.0.1", - description="Call of Cthulhu character generator", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/ajwalkiewicz/cochar", - project_urls={ - "Documentation": "https://ajwalkiewicz.github.io/cochar/_build/html/index.html" - }, - author="Adam Walkiewicz", - license="AGPL v3", - classifiers=[ - "License :: OSI Approved :: GNU Affero General Public License v3", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - ], - packages=["cochar"], - include_package_data=True, - install_requires=["rname"], - entry_points={"console_scripts": ["cochar=cochar.__main__:main"]}, -) diff --git a/cochar/__init__.py b/src/cochar/__init__.py similarity index 100% rename from cochar/__init__.py rename to src/cochar/__init__.py diff --git a/cochar/__main__.py b/src/cochar/__main__.py similarity index 100% rename from cochar/__main__.py rename to src/cochar/__main__.py diff --git a/cochar/character.py b/src/cochar/character.py similarity index 100% rename from cochar/character.py rename to src/cochar/character.py diff --git a/cochar/cochar.py b/src/cochar/cochar.py similarity index 100% rename from cochar/cochar.py rename to src/cochar/cochar.py diff --git a/cochar/data/occupations.json b/src/cochar/data/occupations.json similarity index 100% rename from cochar/data/occupations.json rename to src/cochar/data/occupations.json diff --git a/cochar/data/popPyramid.json b/src/cochar/data/popPyramid.json similarity index 100% rename from cochar/data/popPyramid.json rename to src/cochar/data/popPyramid.json diff --git a/cochar/data/settings.json b/src/cochar/data/settings.json similarity index 100% rename from cochar/data/settings.json rename to src/cochar/data/settings.json diff --git a/cochar/data/skills.json b/src/cochar/data/skills.json similarity index 100% rename from cochar/data/skills.json rename to src/cochar/data/skills.json diff --git a/cochar/error.py b/src/cochar/error.py similarity index 100% rename from cochar/error.py rename to src/cochar/error.py diff --git a/cochar/interface.py b/src/cochar/interface.py similarity index 100% rename from cochar/interface.py rename to src/cochar/interface.py diff --git a/cochar/occup.py b/src/cochar/occup.py similarity index 100% rename from cochar/occup.py rename to src/cochar/occup.py diff --git a/cochar/skill.py b/src/cochar/skill.py similarity index 100% rename from cochar/skill.py rename to src/cochar/skill.py diff --git a/cochar/utils.py b/src/cochar/utils.py similarity index 100% rename from cochar/utils.py rename to src/cochar/utils.py diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..05fe61c --- /dev/null +++ b/uv.lock @@ -0,0 +1,712 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "certifi" +version = "2025.10.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "cochar" +version = "2.0.0b1" +source = { editable = "." } +dependencies = [ + { name = "rname" }, +] + +[package.dev-dependencies] +dev = [ + { name = "deepdiff" }, + { name = "mypy" }, + { name = "pytest" }, + { name = "ruff" }, + { name = "sphinx" }, +] + +[package.metadata] +requires-dist = [{ name = "rname", specifier = ">=0.3.7" }] + +[package.metadata.requires-dev] +dev = [ + { name = "deepdiff", specifier = ">=8.6.1" }, + { name = "mypy", specifier = ">=1.18.2" }, + { name = "pytest", specifier = ">=8.4.2" }, + { name = "ruff", specifier = ">=0.14.3" }, + { name = "sphinx", specifier = ">=8.2.3" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "deepdiff" +version = "8.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "orderly-set" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/76/36c9aab3d5c19a94091f7c6c6e784efca50d87b124bf026c36e94719f33c/deepdiff-8.6.1.tar.gz", hash = "sha256:ec56d7a769ca80891b5200ec7bd41eec300ced91ebcc7797b41eb2b3f3ff643a", size = 634054, upload-time = "2025-09-03T19:40:41.461Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/e6/efe534ef0952b531b630780e19cabd416e2032697019d5295defc6ef9bd9/deepdiff-8.6.1-py3-none-any.whl", hash = "sha256:ee8708a7f7d37fb273a541fa24ad010ed484192cd0c4ffc0fa0ed5e2d4b9e78b", size = 91378, upload-time = "2025-09-03T19:40:39.679Z" }, +] + +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mypy" +version = "1.18.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/77/8f0d0001ffad290cef2f7f216f96c814866248a0b92a722365ed54648e7e/mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b", size = 3448846, upload-time = "2025-09-19T00:11:10.519Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/87/cafd3ae563f88f94eec33f35ff722d043e09832ea8530ef149ec1efbaf08/mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f", size = 12731198, upload-time = "2025-09-19T00:09:44.857Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e0/1e96c3d4266a06d4b0197ace5356d67d937d8358e2ee3ffac71faa843724/mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341", size = 11817879, upload-time = "2025-09-19T00:09:47.131Z" }, + { url = "https://files.pythonhosted.org/packages/72/ef/0c9ba89eb03453e76bdac5a78b08260a848c7bfc5d6603634774d9cd9525/mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d", size = 12427292, upload-time = "2025-09-19T00:10:22.472Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/ec4a061dd599eb8179d5411d99775bec2a20542505988f40fc2fee781068/mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86", size = 13163750, upload-time = "2025-09-19T00:09:51.472Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5f/2cf2ceb3b36372d51568f2208c021870fe7834cf3186b653ac6446511839/mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37", size = 13351827, upload-time = "2025-09-19T00:09:58.311Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7d/2697b930179e7277529eaaec1513f8de622818696857f689e4a5432e5e27/mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8", size = 9757983, upload-time = "2025-09-19T00:10:09.071Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/dfdd2bc60c66611dd8335f463818514733bc763e4760dee289dcc33df709/mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34", size = 12908273, upload-time = "2025-09-19T00:10:58.321Z" }, + { url = "https://files.pythonhosted.org/packages/81/14/6a9de6d13a122d5608e1a04130724caf9170333ac5a924e10f670687d3eb/mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764", size = 11920910, upload-time = "2025-09-19T00:10:20.043Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a9/b29de53e42f18e8cc547e38daa9dfa132ffdc64f7250e353f5c8cdd44bee/mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893", size = 12465585, upload-time = "2025-09-19T00:10:33.005Z" }, + { url = "https://files.pythonhosted.org/packages/77/ae/6c3d2c7c61ff21f2bee938c917616c92ebf852f015fb55917fd6e2811db2/mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914", size = 13348562, upload-time = "2025-09-19T00:10:11.51Z" }, + { url = "https://files.pythonhosted.org/packages/4d/31/aec68ab3b4aebdf8f36d191b0685d99faa899ab990753ca0fee60fb99511/mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8", size = 13533296, upload-time = "2025-09-19T00:10:06.568Z" }, + { url = "https://files.pythonhosted.org/packages/9f/83/abcb3ad9478fca3ebeb6a5358bb0b22c95ea42b43b7789c7fb1297ca44f4/mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074", size = 9828828, upload-time = "2025-09-19T00:10:28.203Z" }, + { url = "https://files.pythonhosted.org/packages/5f/04/7f462e6fbba87a72bc8097b93f6842499c428a6ff0c81dd46948d175afe8/mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc", size = 12898728, upload-time = "2025-09-19T00:10:01.33Z" }, + { url = "https://files.pythonhosted.org/packages/99/5b/61ed4efb64f1871b41fd0b82d29a64640f3516078f6c7905b68ab1ad8b13/mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e", size = 11910758, upload-time = "2025-09-19T00:10:42.607Z" }, + { url = "https://files.pythonhosted.org/packages/3c/46/d297d4b683cc89a6e4108c4250a6a6b717f5fa96e1a30a7944a6da44da35/mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986", size = 12475342, upload-time = "2025-09-19T00:11:00.371Z" }, + { url = "https://files.pythonhosted.org/packages/83/45/4798f4d00df13eae3bfdf726c9244bcb495ab5bd588c0eed93a2f2dd67f3/mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d", size = 13338709, upload-time = "2025-09-19T00:11:03.358Z" }, + { url = "https://files.pythonhosted.org/packages/d7/09/479f7358d9625172521a87a9271ddd2441e1dab16a09708f056e97007207/mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba", size = 13529806, upload-time = "2025-09-19T00:10:26.073Z" }, + { url = "https://files.pythonhosted.org/packages/71/cf/ac0f2c7e9d0ea3c75cd99dff7aec1c9df4a1376537cb90e4c882267ee7e9/mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544", size = 9833262, upload-time = "2025-09-19T00:10:40.035Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0c/7d5300883da16f0063ae53996358758b2a2df2a09c72a5061fa79a1f5006/mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce", size = 12893775, upload-time = "2025-09-19T00:10:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/50/df/2cffbf25737bdb236f60c973edf62e3e7b4ee1c25b6878629e88e2cde967/mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d", size = 11936852, upload-time = "2025-09-19T00:10:51.631Z" }, + { url = "https://files.pythonhosted.org/packages/be/50/34059de13dd269227fb4a03be1faee6e2a4b04a2051c82ac0a0b5a773c9a/mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c", size = 12480242, upload-time = "2025-09-19T00:11:07.955Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" }, + { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" }, + { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "orderly-set" +version = "5.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/88/39c83c35d5e97cc203e9e77a4f93bf87ec89cf6a22ac4818fdcc65d66584/orderly_set-5.5.0.tar.gz", hash = "sha256:e87185c8e4d8afa64e7f8160ee2c542a475b738bc891dc3f58102e654125e6ce", size = 27414, upload-time = "2025-07-10T20:10:55.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/27/fb8d7338b4d551900fa3e580acbe7a0cf655d940e164cb5c00ec31961094/orderly_set-5.5.0-py3-none-any.whl", hash = "sha256:46f0b801948e98f427b412fcabb831677194c05c3b699b80de260374baa0b1e7", size = 13068, upload-time = "2025-07-10T20:10:54.377Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "rname" +version = "0.3.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/31/7159cde2d74e8c2890a03439cae691eb3c007bfada93a4910983c973e29b/rname-0.3.7.tar.gz", hash = "sha256:2a5d4dc0a948a82f9a04ea080a5577119651b3d76a7642ba92e0111ff63d1be4", size = 728335, upload-time = "2022-11-23T22:12:26.298Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/46/c115296e1f9ca83e844c1362094ef6dd96c2320282a6a7dbaee2360bcb1d/rname-0.3.7-py3-none-any.whl", hash = "sha256:2e0bcde8f8cec0560ffa743a91effa7a58ca5e5a30aa025da28d35a2ffdde7e2", size = 727640, upload-time = "2022-11-23T22:12:23.649Z" }, +] + +[[package]] +name = "roman-numerals-py" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017, upload-time = "2025-02-22T07:34:54.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742, upload-time = "2025-02-22T07:34:52.422Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.28.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/dc/95f074d43452b3ef5d06276696ece4b3b5d696e7c9ad7173c54b1390cd70/rpds_py-0.28.0.tar.gz", hash = "sha256:abd4df20485a0983e2ca334a216249b6186d6e3c1627e106651943dbdb791aea", size = 27419, upload-time = "2025-10-22T22:24:29.327Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/34/058d0db5471c6be7bef82487ad5021ff8d1d1d27794be8730aad938649cf/rpds_py-0.28.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:03065002fd2e287725d95fbc69688e0c6daf6c6314ba38bdbaa3895418e09296", size = 362344, upload-time = "2025-10-22T22:21:39.713Z" }, + { url = "https://files.pythonhosted.org/packages/5d/67/9503f0ec8c055a0782880f300c50a2b8e5e72eb1f94dfc2053da527444dd/rpds_py-0.28.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28ea02215f262b6d078daec0b45344c89e161eab9526b0d898221d96fdda5f27", size = 348440, upload-time = "2025-10-22T22:21:41.056Z" }, + { url = "https://files.pythonhosted.org/packages/68/2e/94223ee9b32332a41d75b6f94b37b4ce3e93878a556fc5f152cbd856a81f/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25dbade8fbf30bcc551cb352376c0ad64b067e4fc56f90e22ba70c3ce205988c", size = 379068, upload-time = "2025-10-22T22:21:42.593Z" }, + { url = "https://files.pythonhosted.org/packages/b4/25/54fd48f9f680cfc44e6a7f39a5fadf1d4a4a1fd0848076af4a43e79f998c/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c03002f54cc855860bfdc3442928ffdca9081e73b5b382ed0b9e8efe6e5e205", size = 390518, upload-time = "2025-10-22T22:21:43.998Z" }, + { url = "https://files.pythonhosted.org/packages/1b/85/ac258c9c27f2ccb1bd5d0697e53a82ebcf8088e3186d5d2bf8498ee7ed44/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9699fa7990368b22032baf2b2dce1f634388e4ffc03dfefaaac79f4695edc95", size = 525319, upload-time = "2025-10-22T22:21:45.645Z" }, + { url = "https://files.pythonhosted.org/packages/40/cb/c6734774789566d46775f193964b76627cd5f42ecf246d257ce84d1912ed/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9b06fe1a75e05e0713f06ea0c89ecb6452210fd60e2f1b6ddc1067b990e08d9", size = 404896, upload-time = "2025-10-22T22:21:47.544Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/14e37ce83202c632c89b0691185dca9532288ff9d390eacae3d2ff771bae/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9f83e7b326a3f9ec3ef84cda98fb0a74c7159f33e692032233046e7fd15da2", size = 382862, upload-time = "2025-10-22T22:21:49.176Z" }, + { url = "https://files.pythonhosted.org/packages/6a/83/f3642483ca971a54d60caa4449f9d6d4dbb56a53e0072d0deff51b38af74/rpds_py-0.28.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:0d3259ea9ad8743a75a43eb7819324cdab393263c91be86e2d1901ee65c314e0", size = 398848, upload-time = "2025-10-22T22:21:51.024Z" }, + { url = "https://files.pythonhosted.org/packages/44/09/2d9c8b2f88e399b4cfe86efdf2935feaf0394e4f14ab30c6c5945d60af7d/rpds_py-0.28.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a7548b345f66f6695943b4ef6afe33ccd3f1b638bd9afd0f730dd255c249c9e", size = 412030, upload-time = "2025-10-22T22:21:52.665Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f5/e1cec473d4bde6df1fd3738be8e82d64dd0600868e76e92dfeaebbc2d18f/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9a40040aa388b037eb39416710fbcce9443498d2eaab0b9b45ae988b53f5c67", size = 559700, upload-time = "2025-10-22T22:21:54.123Z" }, + { url = "https://files.pythonhosted.org/packages/8d/be/73bb241c1649edbf14e98e9e78899c2c5e52bbe47cb64811f44d2cc11808/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f60c7ea34e78c199acd0d3cda37a99be2c861dd2b8cf67399784f70c9f8e57d", size = 584581, upload-time = "2025-10-22T22:21:56.102Z" }, + { url = "https://files.pythonhosted.org/packages/9c/9c/ffc6e9218cd1eb5c2c7dbd276c87cd10e8c2232c456b554169eb363381df/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1571ae4292649100d743b26d5f9c63503bb1fedf538a8f29a98dce2d5ba6b4e6", size = 549981, upload-time = "2025-10-22T22:21:58.253Z" }, + { url = "https://files.pythonhosted.org/packages/5f/50/da8b6d33803a94df0149345ee33e5d91ed4d25fc6517de6a25587eae4133/rpds_py-0.28.0-cp311-cp311-win32.whl", hash = "sha256:5cfa9af45e7c1140af7321fa0bef25b386ee9faa8928c80dc3a5360971a29e8c", size = 214729, upload-time = "2025-10-22T22:21:59.625Z" }, + { url = "https://files.pythonhosted.org/packages/12/fd/b0f48c4c320ee24c8c20df8b44acffb7353991ddf688af01eef5f93d7018/rpds_py-0.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd8d86b5d29d1b74100982424ba53e56033dc47720a6de9ba0259cf81d7cecaa", size = 223977, upload-time = "2025-10-22T22:22:01.092Z" }, + { url = "https://files.pythonhosted.org/packages/b4/21/c8e77a2ac66e2ec4e21f18a04b4e9a0417ecf8e61b5eaeaa9360a91713b4/rpds_py-0.28.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e27d3a5709cc2b3e013bf93679a849213c79ae0573f9b894b284b55e729e120", size = 217326, upload-time = "2025-10-22T22:22:02.944Z" }, + { url = "https://files.pythonhosted.org/packages/b8/5c/6c3936495003875fe7b14f90ea812841a08fca50ab26bd840e924097d9c8/rpds_py-0.28.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6b4f28583a4f247ff60cd7bdda83db8c3f5b05a7a82ff20dd4b078571747708f", size = 366439, upload-time = "2025-10-22T22:22:04.525Z" }, + { url = "https://files.pythonhosted.org/packages/56/f9/a0f1ca194c50aa29895b442771f036a25b6c41a35e4f35b1a0ea713bedae/rpds_py-0.28.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d678e91b610c29c4b3d52a2c148b641df2b4676ffe47c59f6388d58b99cdc424", size = 348170, upload-time = "2025-10-22T22:22:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/18/ea/42d243d3a586beb72c77fa5def0487daf827210069a95f36328e869599ea/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e819e0e37a44a78e1383bf1970076e2ccc4dc8c2bbaa2f9bd1dc987e9afff628", size = 378838, upload-time = "2025-10-22T22:22:07.932Z" }, + { url = "https://files.pythonhosted.org/packages/e7/78/3de32e18a94791af8f33601402d9d4f39613136398658412a4e0b3047327/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5ee514e0f0523db5d3fb171f397c54875dbbd69760a414dccf9d4d7ad628b5bd", size = 393299, upload-time = "2025-10-22T22:22:09.435Z" }, + { url = "https://files.pythonhosted.org/packages/13/7e/4bdb435afb18acea2eb8a25ad56b956f28de7c59f8a1d32827effa0d4514/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3fa06d27fdcee47f07a39e02862da0100cb4982508f5ead53ec533cd5fe55e", size = 518000, upload-time = "2025-10-22T22:22:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/31/d0/5f52a656875cdc60498ab035a7a0ac8f399890cc1ee73ebd567bac4e39ae/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46959ef2e64f9e4a41fc89aa20dbca2b85531f9a72c21099a3360f35d10b0d5a", size = 408746, upload-time = "2025-10-22T22:22:13.143Z" }, + { url = "https://files.pythonhosted.org/packages/3e/cd/49ce51767b879cde77e7ad9fae164ea15dce3616fe591d9ea1df51152706/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8455933b4bcd6e83fde3fefc987a023389c4b13f9a58c8d23e4b3f6d13f78c84", size = 386379, upload-time = "2025-10-22T22:22:14.602Z" }, + { url = "https://files.pythonhosted.org/packages/6a/99/e4e1e1ee93a98f72fc450e36c0e4d99c35370220e815288e3ecd2ec36a2a/rpds_py-0.28.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:ad50614a02c8c2962feebe6012b52f9802deec4263946cddea37aaf28dd25a66", size = 401280, upload-time = "2025-10-22T22:22:16.063Z" }, + { url = "https://files.pythonhosted.org/packages/61/35/e0c6a57488392a8b319d2200d03dad2b29c0db9996f5662c3b02d0b86c02/rpds_py-0.28.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e5deca01b271492553fdb6c7fd974659dce736a15bae5dad7ab8b93555bceb28", size = 412365, upload-time = "2025-10-22T22:22:17.504Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6a/841337980ea253ec797eb084665436007a1aad0faac1ba097fb906c5f69c/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:735f8495a13159ce6a0d533f01e8674cec0c57038c920495f87dcb20b3ddb48a", size = 559573, upload-time = "2025-10-22T22:22:19.108Z" }, + { url = "https://files.pythonhosted.org/packages/e7/5e/64826ec58afd4c489731f8b00729c5f6afdb86f1df1df60bfede55d650bb/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:961ca621ff10d198bbe6ba4957decca61aa2a0c56695384c1d6b79bf61436df5", size = 583973, upload-time = "2025-10-22T22:22:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ee/44d024b4843f8386a4eeaa4c171b3d31d55f7177c415545fd1a24c249b5d/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2374e16cc9131022e7d9a8f8d65d261d9ba55048c78f3b6e017971a4f5e6353c", size = 553800, upload-time = "2025-10-22T22:22:22.25Z" }, + { url = "https://files.pythonhosted.org/packages/7d/89/33e675dccff11a06d4d85dbb4d1865f878d5020cbb69b2c1e7b2d3f82562/rpds_py-0.28.0-cp312-cp312-win32.whl", hash = "sha256:d15431e334fba488b081d47f30f091e5d03c18527c325386091f31718952fe08", size = 216954, upload-time = "2025-10-22T22:22:24.105Z" }, + { url = "https://files.pythonhosted.org/packages/af/36/45f6ebb3210887e8ee6dbf1bc710ae8400bb417ce165aaf3024b8360d999/rpds_py-0.28.0-cp312-cp312-win_amd64.whl", hash = "sha256:a410542d61fc54710f750d3764380b53bf09e8c4edbf2f9141a82aa774a04f7c", size = 227844, upload-time = "2025-10-22T22:22:25.551Z" }, + { url = "https://files.pythonhosted.org/packages/57/91/f3fb250d7e73de71080f9a221d19bd6a1c1eb0d12a1ea26513f6c1052ad6/rpds_py-0.28.0-cp312-cp312-win_arm64.whl", hash = "sha256:1f0cfd1c69e2d14f8c892b893997fa9a60d890a0c8a603e88dca4955f26d1edd", size = 217624, upload-time = "2025-10-22T22:22:26.914Z" }, + { url = "https://files.pythonhosted.org/packages/d3/03/ce566d92611dfac0085c2f4b048cd53ed7c274a5c05974b882a908d540a2/rpds_py-0.28.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e9e184408a0297086f880556b6168fa927d677716f83d3472ea333b42171ee3b", size = 366235, upload-time = "2025-10-22T22:22:28.397Z" }, + { url = "https://files.pythonhosted.org/packages/00/34/1c61da1b25592b86fd285bd7bd8422f4c9d748a7373b46126f9ae792a004/rpds_py-0.28.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:edd267266a9b0448f33dc465a97cfc5d467594b600fe28e7fa2f36450e03053a", size = 348241, upload-time = "2025-10-22T22:22:30.171Z" }, + { url = "https://files.pythonhosted.org/packages/fc/00/ed1e28616848c61c493a067779633ebf4b569eccaacf9ccbdc0e7cba2b9d/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85beb8b3f45e4e32f6802fb6cd6b17f615ef6c6a52f265371fb916fae02814aa", size = 378079, upload-time = "2025-10-22T22:22:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/11/b2/ccb30333a16a470091b6e50289adb4d3ec656fd9951ba8c5e3aaa0746a67/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d2412be8d00a1b895f8ad827cc2116455196e20ed994bb704bf138fe91a42724", size = 393151, upload-time = "2025-10-22T22:22:33.453Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d0/73e2217c3ee486d555cb84920597480627d8c0240ff3062005c6cc47773e/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf128350d384b777da0e68796afdcebc2e9f63f0e9f242217754e647f6d32491", size = 517520, upload-time = "2025-10-22T22:22:34.949Z" }, + { url = "https://files.pythonhosted.org/packages/c4/91/23efe81c700427d0841a4ae7ea23e305654381831e6029499fe80be8a071/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2036d09b363aa36695d1cc1a97b36865597f4478470b0697b5ee9403f4fe399", size = 408699, upload-time = "2025-10-22T22:22:36.584Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ee/a324d3198da151820a326c1f988caaa4f37fc27955148a76fff7a2d787a9/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8e1e9be4fa6305a16be628959188e4fd5cd6f1b0e724d63c6d8b2a8adf74ea6", size = 385720, upload-time = "2025-10-22T22:22:38.014Z" }, + { url = "https://files.pythonhosted.org/packages/19/ad/e68120dc05af8b7cab4a789fccd8cdcf0fe7e6581461038cc5c164cd97d2/rpds_py-0.28.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0a403460c9dd91a7f23fc3188de6d8977f1d9603a351d5db6cf20aaea95b538d", size = 401096, upload-time = "2025-10-22T22:22:39.869Z" }, + { url = "https://files.pythonhosted.org/packages/99/90/c1e070620042459d60df6356b666bb1f62198a89d68881816a7ed121595a/rpds_py-0.28.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d7366b6553cdc805abcc512b849a519167db8f5e5c3472010cd1228b224265cb", size = 411465, upload-time = "2025-10-22T22:22:41.395Z" }, + { url = "https://files.pythonhosted.org/packages/68/61/7c195b30d57f1b8d5970f600efee72a4fad79ec829057972e13a0370fd24/rpds_py-0.28.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5b43c6a3726efd50f18d8120ec0551241c38785b68952d240c45ea553912ac41", size = 558832, upload-time = "2025-10-22T22:22:42.871Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3d/06f3a718864773f69941d4deccdf18e5e47dd298b4628062f004c10f3b34/rpds_py-0.28.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0cb7203c7bc69d7c1585ebb33a2e6074492d2fc21ad28a7b9d40457ac2a51ab7", size = 583230, upload-time = "2025-10-22T22:22:44.877Z" }, + { url = "https://files.pythonhosted.org/packages/66/df/62fc783781a121e77fee9a21ead0a926f1b652280a33f5956a5e7833ed30/rpds_py-0.28.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a52a5169c664dfb495882adc75c304ae1d50df552fbd68e100fdc719dee4ff9", size = 553268, upload-time = "2025-10-22T22:22:46.441Z" }, + { url = "https://files.pythonhosted.org/packages/84/85/d34366e335140a4837902d3dea89b51f087bd6a63c993ebdff59e93ee61d/rpds_py-0.28.0-cp313-cp313-win32.whl", hash = "sha256:2e42456917b6687215b3e606ab46aa6bca040c77af7df9a08a6dcfe8a4d10ca5", size = 217100, upload-time = "2025-10-22T22:22:48.342Z" }, + { url = "https://files.pythonhosted.org/packages/3c/1c/f25a3f3752ad7601476e3eff395fe075e0f7813fbb9862bd67c82440e880/rpds_py-0.28.0-cp313-cp313-win_amd64.whl", hash = "sha256:e0a0311caedc8069d68fc2bf4c9019b58a2d5ce3cd7cb656c845f1615b577e1e", size = 227759, upload-time = "2025-10-22T22:22:50.219Z" }, + { url = "https://files.pythonhosted.org/packages/e0/d6/5f39b42b99615b5bc2f36ab90423ea404830bdfee1c706820943e9a645eb/rpds_py-0.28.0-cp313-cp313-win_arm64.whl", hash = "sha256:04c1b207ab8b581108801528d59ad80aa83bb170b35b0ddffb29c20e411acdc1", size = 217326, upload-time = "2025-10-22T22:22:51.647Z" }, + { url = "https://files.pythonhosted.org/packages/5c/8b/0c69b72d1cee20a63db534be0df271effe715ef6c744fdf1ff23bb2b0b1c/rpds_py-0.28.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f296ea3054e11fc58ad42e850e8b75c62d9a93a9f981ad04b2e5ae7d2186ff9c", size = 355736, upload-time = "2025-10-22T22:22:53.211Z" }, + { url = "https://files.pythonhosted.org/packages/f7/6d/0c2ee773cfb55c31a8514d2cece856dd299170a49babd50dcffb15ddc749/rpds_py-0.28.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5a7306c19b19005ad98468fcefeb7100b19c79fc23a5f24a12e06d91181193fa", size = 342677, upload-time = "2025-10-22T22:22:54.723Z" }, + { url = "https://files.pythonhosted.org/packages/e2/1c/22513ab25a27ea205144414724743e305e8153e6abe81833b5e678650f5a/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5d9b86aa501fed9862a443c5c3116f6ead8bc9296185f369277c42542bd646b", size = 371847, upload-time = "2025-10-22T22:22:56.295Z" }, + { url = "https://files.pythonhosted.org/packages/60/07/68e6ccdb4b05115ffe61d31afc94adef1833d3a72f76c9632d4d90d67954/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e5bbc701eff140ba0e872691d573b3d5d30059ea26e5785acba9132d10c8c31d", size = 381800, upload-time = "2025-10-22T22:22:57.808Z" }, + { url = "https://files.pythonhosted.org/packages/73/bf/6d6d15df80781d7f9f368e7c1a00caf764436518c4877fb28b029c4624af/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5690671cd672a45aa8616d7374fdf334a1b9c04a0cac3c854b1136e92374fe", size = 518827, upload-time = "2025-10-22T22:22:59.826Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d3/2decbb2976cc452cbf12a2b0aaac5f1b9dc5dd9d1f7e2509a3ee00421249/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f1d92ecea4fa12f978a367c32a5375a1982834649cdb96539dcdc12e609ab1a", size = 399471, upload-time = "2025-10-22T22:23:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/b1/2c/f30892f9e54bd02e5faca3f6a26d6933c51055e67d54818af90abed9748e/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d252db6b1a78d0a3928b6190156042d54c93660ce4d98290d7b16b5296fb7cc", size = 377578, upload-time = "2025-10-22T22:23:03.52Z" }, + { url = "https://files.pythonhosted.org/packages/f0/5d/3bce97e5534157318f29ac06bf2d279dae2674ec12f7cb9c12739cee64d8/rpds_py-0.28.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d61b355c3275acb825f8777d6c4505f42b5007e357af500939d4a35b19177259", size = 390482, upload-time = "2025-10-22T22:23:05.391Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f0/886bd515ed457b5bd93b166175edb80a0b21a210c10e993392127f1e3931/rpds_py-0.28.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:acbe5e8b1026c0c580d0321c8aae4b0a1e1676861d48d6e8c6586625055b606a", size = 402447, upload-time = "2025-10-22T22:23:06.93Z" }, + { url = "https://files.pythonhosted.org/packages/42/b5/71e8777ac55e6af1f4f1c05b47542a1eaa6c33c1cf0d300dca6a1c6e159a/rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8aa23b6f0fc59b85b4c7d89ba2965af274346f738e8d9fc2455763602e62fd5f", size = 552385, upload-time = "2025-10-22T22:23:08.557Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cb/6ca2d70cbda5a8e36605e7788c4aa3bea7c17d71d213465a5a675079b98d/rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7b14b0c680286958817c22d76fcbca4800ddacef6f678f3a7c79a1fe7067fe37", size = 575642, upload-time = "2025-10-22T22:23:10.348Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d4/407ad9960ca7856d7b25c96dcbe019270b5ffdd83a561787bc682c797086/rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:bcf1d210dfee61a6c86551d67ee1031899c0fdbae88b2d44a569995d43797712", size = 544507, upload-time = "2025-10-22T22:23:12.434Z" }, + { url = "https://files.pythonhosted.org/packages/51/31/2f46fe0efcac23fbf5797c6b6b7e1c76f7d60773e525cb65fcbc582ee0f2/rpds_py-0.28.0-cp313-cp313t-win32.whl", hash = "sha256:3aa4dc0fdab4a7029ac63959a3ccf4ed605fee048ba67ce89ca3168da34a1342", size = 205376, upload-time = "2025-10-22T22:23:13.979Z" }, + { url = "https://files.pythonhosted.org/packages/92/e4/15947bda33cbedfc134490a41841ab8870a72a867a03d4969d886f6594a2/rpds_py-0.28.0-cp313-cp313t-win_amd64.whl", hash = "sha256:7b7d9d83c942855e4fdcfa75d4f96f6b9e272d42fffcb72cd4bb2577db2e2907", size = 215907, upload-time = "2025-10-22T22:23:15.5Z" }, + { url = "https://files.pythonhosted.org/packages/08/47/ffe8cd7a6a02833b10623bf765fbb57ce977e9a4318ca0e8cf97e9c3d2b3/rpds_py-0.28.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:dcdcb890b3ada98a03f9f2bb108489cdc7580176cb73b4f2d789e9a1dac1d472", size = 353830, upload-time = "2025-10-22T22:23:17.03Z" }, + { url = "https://files.pythonhosted.org/packages/f9/9f/890f36cbd83a58491d0d91ae0db1702639edb33fb48eeb356f80ecc6b000/rpds_py-0.28.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f274f56a926ba2dc02976ca5b11c32855cbd5925534e57cfe1fda64e04d1add2", size = 341819, upload-time = "2025-10-22T22:23:18.57Z" }, + { url = "https://files.pythonhosted.org/packages/09/e3/921eb109f682aa24fb76207698fbbcf9418738f35a40c21652c29053f23d/rpds_py-0.28.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fe0438ac4a29a520ea94c8c7f1754cdd8feb1bc490dfda1bfd990072363d527", size = 373127, upload-time = "2025-10-22T22:23:20.216Z" }, + { url = "https://files.pythonhosted.org/packages/23/13/bce4384d9f8f4989f1a9599c71b7a2d877462e5fd7175e1f69b398f729f4/rpds_py-0.28.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8a358a32dd3ae50e933347889b6af9a1bdf207ba5d1a3f34e1a38cd3540e6733", size = 382767, upload-time = "2025-10-22T22:23:21.787Z" }, + { url = "https://files.pythonhosted.org/packages/23/e1/579512b2d89a77c64ccef5a0bc46a6ef7f72ae0cf03d4b26dcd52e57ee0a/rpds_py-0.28.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e80848a71c78aa328fefaba9c244d588a342c8e03bda518447b624ea64d1ff56", size = 517585, upload-time = "2025-10-22T22:23:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/62/3c/ca704b8d324a2591b0b0adcfcaadf9c862375b11f2f667ac03c61b4fd0a6/rpds_py-0.28.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f586db2e209d54fe177e58e0bc4946bea5fb0102f150b1b2f13de03e1f0976f8", size = 399828, upload-time = "2025-10-22T22:23:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/da/37/e84283b9e897e3adc46b4c88bb3f6ec92a43bd4d2f7ef5b13459963b2e9c/rpds_py-0.28.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ae8ee156d6b586e4292491e885d41483136ab994e719a13458055bec14cf370", size = 375509, upload-time = "2025-10-22T22:23:27.32Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c2/a980beab869d86258bf76ec42dec778ba98151f253a952b02fe36d72b29c/rpds_py-0.28.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:a805e9b3973f7e27f7cab63a6b4f61d90f2e5557cff73b6e97cd5b8540276d3d", size = 392014, upload-time = "2025-10-22T22:23:29.332Z" }, + { url = "https://files.pythonhosted.org/packages/da/b5/b1d3c5f9d3fa5aeef74265f9c64de3c34a0d6d5cd3c81c8b17d5c8f10ed4/rpds_py-0.28.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5d3fd16b6dc89c73a4da0b4ac8b12a7ecc75b2864b95c9e5afed8003cb50a728", size = 402410, upload-time = "2025-10-22T22:23:31.14Z" }, + { url = "https://files.pythonhosted.org/packages/74/ae/cab05ff08dfcc052afc73dcb38cbc765ffc86f94e966f3924cd17492293c/rpds_py-0.28.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6796079e5d24fdaba6d49bda28e2c47347e89834678f2bc2c1b4fc1489c0fb01", size = 553593, upload-time = "2025-10-22T22:23:32.834Z" }, + { url = "https://files.pythonhosted.org/packages/70/80/50d5706ea2a9bfc9e9c5f401d91879e7c790c619969369800cde202da214/rpds_py-0.28.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:76500820c2af232435cbe215e3324c75b950a027134e044423f59f5b9a1ba515", size = 576925, upload-time = "2025-10-22T22:23:34.47Z" }, + { url = "https://files.pythonhosted.org/packages/ab/12/85a57d7a5855a3b188d024b099fd09c90db55d32a03626d0ed16352413ff/rpds_py-0.28.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bbdc5640900a7dbf9dd707fe6388972f5bbd883633eb68b76591044cfe346f7e", size = 542444, upload-time = "2025-10-22T22:23:36.093Z" }, + { url = "https://files.pythonhosted.org/packages/6c/65/10643fb50179509150eb94d558e8837c57ca8b9adc04bd07b98e57b48f8c/rpds_py-0.28.0-cp314-cp314-win32.whl", hash = "sha256:adc8aa88486857d2b35d75f0640b949759f79dc105f50aa2c27816b2e0dd749f", size = 207968, upload-time = "2025-10-22T22:23:37.638Z" }, + { url = "https://files.pythonhosted.org/packages/b4/84/0c11fe4d9aaea784ff4652499e365963222481ac647bcd0251c88af646eb/rpds_py-0.28.0-cp314-cp314-win_amd64.whl", hash = "sha256:66e6fa8e075b58946e76a78e69e1a124a21d9a48a5b4766d15ba5b06869d1fa1", size = 218876, upload-time = "2025-10-22T22:23:39.179Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e0/3ab3b86ded7bb18478392dc3e835f7b754cd446f62f3fc96f4fe2aca78f6/rpds_py-0.28.0-cp314-cp314-win_arm64.whl", hash = "sha256:a6fe887c2c5c59413353b7c0caff25d0e566623501ccfff88957fa438a69377d", size = 212506, upload-time = "2025-10-22T22:23:40.755Z" }, + { url = "https://files.pythonhosted.org/packages/51/ec/d5681bb425226c3501eab50fc30e9d275de20c131869322c8a1729c7b61c/rpds_py-0.28.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7a69df082db13c7070f7b8b1f155fa9e687f1d6aefb7b0e3f7231653b79a067b", size = 355433, upload-time = "2025-10-22T22:23:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/be/ec/568c5e689e1cfb1ea8b875cffea3649260955f677fdd7ddc6176902d04cd/rpds_py-0.28.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b1cde22f2c30ebb049a9e74c5374994157b9b70a16147d332f89c99c5960737a", size = 342601, upload-time = "2025-10-22T22:23:44.372Z" }, + { url = "https://files.pythonhosted.org/packages/32/fe/51ada84d1d2a1d9d8f2c902cfddd0133b4a5eb543196ab5161d1c07ed2ad/rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5338742f6ba7a51012ea470bd4dc600a8c713c0c72adaa0977a1b1f4327d6592", size = 372039, upload-time = "2025-10-22T22:23:46.025Z" }, + { url = "https://files.pythonhosted.org/packages/07/c1/60144a2f2620abade1a78e0d91b298ac2d9b91bc08864493fa00451ef06e/rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e1460ebde1bcf6d496d80b191d854adedcc619f84ff17dc1c6d550f58c9efbba", size = 382407, upload-time = "2025-10-22T22:23:48.098Z" }, + { url = "https://files.pythonhosted.org/packages/45/ed/091a7bbdcf4038a60a461df50bc4c82a7ed6d5d5e27649aab61771c17585/rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e3eb248f2feba84c692579257a043a7699e28a77d86c77b032c1d9fbb3f0219c", size = 518172, upload-time = "2025-10-22T22:23:50.16Z" }, + { url = "https://files.pythonhosted.org/packages/54/dd/02cc90c2fd9c2ef8016fd7813bfacd1c3a1325633ec8f244c47b449fc868/rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3bbba5def70b16cd1c1d7255666aad3b290fbf8d0fe7f9f91abafb73611a91", size = 399020, upload-time = "2025-10-22T22:23:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/ab/81/5d98cc0329bbb911ccecd0b9e19fbf7f3a5de8094b4cda5e71013b2dd77e/rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3114f4db69ac5a1f32e7e4d1cbbe7c8f9cf8217f78e6e002cedf2d54c2a548ed", size = 377451, upload-time = "2025-10-22T22:23:53.711Z" }, + { url = "https://files.pythonhosted.org/packages/b4/07/4d5bcd49e3dfed2d38e2dcb49ab6615f2ceb9f89f5a372c46dbdebb4e028/rpds_py-0.28.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:4b0cb8a906b1a0196b863d460c0222fb8ad0f34041568da5620f9799b83ccf0b", size = 390355, upload-time = "2025-10-22T22:23:55.299Z" }, + { url = "https://files.pythonhosted.org/packages/3f/79/9f14ba9010fee74e4f40bf578735cfcbb91d2e642ffd1abe429bb0b96364/rpds_py-0.28.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf681ac76a60b667106141e11a92a3330890257e6f559ca995fbb5265160b56e", size = 403146, upload-time = "2025-10-22T22:23:56.929Z" }, + { url = "https://files.pythonhosted.org/packages/39/4c/f08283a82ac141331a83a40652830edd3a4a92c34e07e2bbe00baaea2f5f/rpds_py-0.28.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1e8ee6413cfc677ce8898d9cde18cc3a60fc2ba756b0dec5b71eb6eb21c49fa1", size = 552656, upload-time = "2025-10-22T22:23:58.62Z" }, + { url = "https://files.pythonhosted.org/packages/61/47/d922fc0666f0dd8e40c33990d055f4cc6ecff6f502c2d01569dbed830f9b/rpds_py-0.28.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b3072b16904d0b5572a15eb9d31c1954e0d3227a585fc1351aa9878729099d6c", size = 576782, upload-time = "2025-10-22T22:24:00.312Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0c/5bafdd8ccf6aa9d3bfc630cfece457ff5b581af24f46a9f3590f790e3df2/rpds_py-0.28.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b670c30fd87a6aec281c3c9896d3bae4b205fd75d79d06dc87c2503717e46092", size = 544671, upload-time = "2025-10-22T22:24:02.297Z" }, + { url = "https://files.pythonhosted.org/packages/2c/37/dcc5d8397caa924988693519069d0beea077a866128719351a4ad95e82fc/rpds_py-0.28.0-cp314-cp314t-win32.whl", hash = "sha256:8014045a15b4d2b3476f0a287fcc93d4f823472d7d1308d47884ecac9e612be3", size = 205749, upload-time = "2025-10-22T22:24:03.848Z" }, + { url = "https://files.pythonhosted.org/packages/d7/69/64d43b21a10d72b45939a28961216baeb721cc2a430f5f7c3bfa21659a53/rpds_py-0.28.0-cp314-cp314t-win_amd64.whl", hash = "sha256:7a4e59c90d9c27c561eb3160323634a9ff50b04e4f7820600a2beb0ac90db578", size = 216233, upload-time = "2025-10-22T22:24:05.471Z" }, + { url = "https://files.pythonhosted.org/packages/ae/bc/b43f2ea505f28119bd551ae75f70be0c803d2dbcd37c1b3734909e40620b/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f5e7101145427087e493b9c9b959da68d357c28c562792300dd21a095118ed16", size = 363913, upload-time = "2025-10-22T22:24:07.129Z" }, + { url = "https://files.pythonhosted.org/packages/28/f2/db318195d324c89a2c57dc5195058cbadd71b20d220685c5bd1da79ee7fe/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:31eb671150b9c62409a888850aaa8e6533635704fe2b78335f9aaf7ff81eec4d", size = 350452, upload-time = "2025-10-22T22:24:08.754Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f2/1391c819b8573a4898cedd6b6c5ec5bc370ce59e5d6bdcebe3c9c1db4588/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b55c1f64482f7d8bd39942f376bfdf2f6aec637ee8c805b5041e14eeb771db", size = 380957, upload-time = "2025-10-22T22:24:10.826Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5c/e5de68ee7eb7248fce93269833d1b329a196d736aefb1a7481d1e99d1222/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24743a7b372e9a76171f6b69c01aedf927e8ac3e16c474d9fe20d552a8cb45c7", size = 391919, upload-time = "2025-10-22T22:24:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/fb/4f/2376336112cbfeb122fd435d608ad8d5041b3aed176f85a3cb32c262eb80/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:389c29045ee8bbb1627ea190b4976a310a295559eaf9f1464a1a6f2bf84dde78", size = 528541, upload-time = "2025-10-22T22:24:14.197Z" }, + { url = "https://files.pythonhosted.org/packages/68/53/5ae232e795853dd20da7225c5dd13a09c0a905b1a655e92bdf8d78a99fd9/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23690b5827e643150cf7b49569679ec13fe9a610a15949ed48b85eb7f98f34ec", size = 405629, upload-time = "2025-10-22T22:24:16.001Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2d/351a3b852b683ca9b6b8b38ed9efb2347596973849ba6c3a0e99877c10aa/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f0c9266c26580e7243ad0d72fc3e01d6b33866cfab5084a6da7576bcf1c4f72", size = 384123, upload-time = "2025-10-22T22:24:17.585Z" }, + { url = "https://files.pythonhosted.org/packages/e0/15/870804daa00202728cc91cb8e2385fa9f1f4eb49857c49cfce89e304eae6/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4c6c4db5d73d179746951486df97fd25e92396be07fc29ee8ff9a8f5afbdfb27", size = 400923, upload-time = "2025-10-22T22:24:19.512Z" }, + { url = "https://files.pythonhosted.org/packages/53/25/3706b83c125fa2a0bccceac951de3f76631f6bd0ee4d02a0ed780712ef1b/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3b695a8fa799dd2cfdb4804b37096c5f6dba1ac7f48a7fbf6d0485bcd060316", size = 413767, upload-time = "2025-10-22T22:24:21.316Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f9/ce43dbe62767432273ed2584cef71fef8411bddfb64125d4c19128015018/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6aa1bfce3f83baf00d9c5fcdbba93a3ab79958b4c7d7d1f55e7fe68c20e63912", size = 561530, upload-time = "2025-10-22T22:24:22.958Z" }, + { url = "https://files.pythonhosted.org/packages/46/c9/ffe77999ed8f81e30713dd38fd9ecaa161f28ec48bb80fa1cd9118399c27/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b0f9dceb221792b3ee6acb5438eb1f02b0cb2c247796a72b016dcc92c6de829", size = 585453, upload-time = "2025-10-22T22:24:24.779Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d2/4a73b18821fd4669762c855fd1f4e80ceb66fb72d71162d14da58444a763/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5d0145edba8abd3db0ab22b5300c99dc152f5c9021fab861be0f0544dc3cbc5f", size = 552199, upload-time = "2025-10-22T22:24:26.54Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/62/50b7727004dfe361104dfbf898c45a9a2fdfad8c72c04ae62900224d6ecf/ruff-0.14.3.tar.gz", hash = "sha256:4ff876d2ab2b161b6de0aa1f5bd714e8e9b4033dc122ee006925fbacc4f62153", size = 5558687, upload-time = "2025-10-31T00:26:26.878Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/8e/0c10ff1ea5d4360ab8bfca4cb2c9d979101a391f3e79d2616c9bf348cd26/ruff-0.14.3-py3-none-linux_armv6l.whl", hash = "sha256:876b21e6c824f519446715c1342b8e60f97f93264012de9d8d10314f8a79c371", size = 12535613, upload-time = "2025-10-31T00:25:44.302Z" }, + { url = "https://files.pythonhosted.org/packages/d3/c8/6724f4634c1daf52409fbf13fefda64aa9c8f81e44727a378b7b73dc590b/ruff-0.14.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6fd8c79b457bedd2abf2702b9b472147cd860ed7855c73a5247fa55c9117654", size = 12855812, upload-time = "2025-10-31T00:25:47.793Z" }, + { url = "https://files.pythonhosted.org/packages/de/03/db1bce591d55fd5f8a08bb02517fa0b5097b2ccabd4ea1ee29aa72b67d96/ruff-0.14.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:71ff6edca490c308f083156938c0c1a66907151263c4abdcb588602c6e696a14", size = 11944026, upload-time = "2025-10-31T00:25:49.657Z" }, + { url = "https://files.pythonhosted.org/packages/0b/75/4f8dbd48e03272715d12c87dc4fcaaf21b913f0affa5f12a4e9c6f8a0582/ruff-0.14.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:786ee3ce6139772ff9272aaf43296d975c0217ee1b97538a98171bf0d21f87ed", size = 12356818, upload-time = "2025-10-31T00:25:51.949Z" }, + { url = "https://files.pythonhosted.org/packages/ec/9b/506ec5b140c11d44a9a4f284ea7c14ebf6f8b01e6e8917734a3325bff787/ruff-0.14.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cd6291d0061811c52b8e392f946889916757610d45d004e41140d81fb6cd5ddc", size = 12336745, upload-time = "2025-10-31T00:25:54.248Z" }, + { url = "https://files.pythonhosted.org/packages/c7/e1/c560d254048c147f35e7f8131d30bc1f63a008ac61595cf3078a3e93533d/ruff-0.14.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a497ec0c3d2c88561b6d90f9c29f5ae68221ac00d471f306fa21fa4264ce5fcd", size = 13101684, upload-time = "2025-10-31T00:25:56.253Z" }, + { url = "https://files.pythonhosted.org/packages/a5/32/e310133f8af5cd11f8cc30f52522a3ebccc5ea5bff4b492f94faceaca7a8/ruff-0.14.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e231e1be58fc568950a04fbe6887c8e4b85310e7889727e2b81db205c45059eb", size = 14535000, upload-time = "2025-10-31T00:25:58.397Z" }, + { url = "https://files.pythonhosted.org/packages/a2/a1/7b0470a22158c6d8501eabc5e9b6043c99bede40fa1994cadf6b5c2a61c7/ruff-0.14.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:469e35872a09c0e45fecf48dd960bfbce056b5db2d5e6b50eca329b4f853ae20", size = 14156450, upload-time = "2025-10-31T00:26:00.889Z" }, + { url = "https://files.pythonhosted.org/packages/0a/96/24bfd9d1a7f532b560dcee1a87096332e461354d3882124219bcaff65c09/ruff-0.14.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d6bc90307c469cb9d28b7cfad90aaa600b10d67c6e22026869f585e1e8a2db0", size = 13568414, upload-time = "2025-10-31T00:26:03.291Z" }, + { url = "https://files.pythonhosted.org/packages/a7/e7/138b883f0dfe4ad5b76b58bf4ae675f4d2176ac2b24bdd81b4d966b28c61/ruff-0.14.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2f8a0bbcffcfd895df39c9a4ecd59bb80dca03dc43f7fb63e647ed176b741e", size = 13315293, upload-time = "2025-10-31T00:26:05.708Z" }, + { url = "https://files.pythonhosted.org/packages/33/f4/c09bb898be97b2eb18476b7c950df8815ef14cf956074177e9fbd40b7719/ruff-0.14.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:678fdd7c7d2d94851597c23ee6336d25f9930b460b55f8598e011b57c74fd8c5", size = 13539444, upload-time = "2025-10-31T00:26:08.09Z" }, + { url = "https://files.pythonhosted.org/packages/9c/aa/b30a1db25fc6128b1dd6ff0741fa4abf969ded161599d07ca7edd0739cc0/ruff-0.14.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1ec1ac071e7e37e0221d2f2dbaf90897a988c531a8592a6a5959f0603a1ecf5e", size = 12252581, upload-time = "2025-10-31T00:26:10.297Z" }, + { url = "https://files.pythonhosted.org/packages/da/13/21096308f384d796ffe3f2960b17054110a9c3828d223ca540c2b7cc670b/ruff-0.14.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:afcdc4b5335ef440d19e7df9e8ae2ad9f749352190e96d481dc501b753f0733e", size = 12307503, upload-time = "2025-10-31T00:26:12.646Z" }, + { url = "https://files.pythonhosted.org/packages/cb/cc/a350bac23f03b7dbcde3c81b154706e80c6f16b06ff1ce28ed07dc7b07b0/ruff-0.14.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:7bfc42f81862749a7136267a343990f865e71fe2f99cf8d2958f684d23ce3dfa", size = 12675457, upload-time = "2025-10-31T00:26:15.044Z" }, + { url = "https://files.pythonhosted.org/packages/cb/76/46346029fa2f2078826bc88ef7167e8c198e58fe3126636e52f77488cbba/ruff-0.14.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a65e448cfd7e9c59fae8cf37f9221585d3354febaad9a07f29158af1528e165f", size = 13403980, upload-time = "2025-10-31T00:26:17.81Z" }, + { url = "https://files.pythonhosted.org/packages/9f/a4/35f1ef68c4e7b236d4a5204e3669efdeefaef21f0ff6a456792b3d8be438/ruff-0.14.3-py3-none-win32.whl", hash = "sha256:f3d91857d023ba93e14ed2d462ab62c3428f9bbf2b4fbac50a03ca66d31991f7", size = 12500045, upload-time = "2025-10-31T00:26:20.503Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/51960ae340823c9859fb60c63301d977308735403e2134e17d1d2858c7fb/ruff-0.14.3-py3-none-win_amd64.whl", hash = "sha256:d7b7006ac0756306db212fd37116cce2bd307e1e109375e1c6c106002df0ae5f", size = 13594005, upload-time = "2025-10-31T00:26:22.533Z" }, + { url = "https://files.pythonhosted.org/packages/b7/73/4de6579bac8e979fca0a77e54dec1f1e011a0d268165eb8a9bc0982a6564/ruff-0.14.3-py3-none-win_arm64.whl", hash = "sha256:26eb477ede6d399d898791d01961e16b86f02bc2486d0d1a7a9bb2379d055dc1", size = 12590017, upload-time = "2025-10-31T00:26:24.52Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "sphinx" +version = "8.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals-py" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] From c47cf266b099b7a15c94d9f6b42f2eec76b29e84 Mon Sep 17 00:00:00 2001 From: Adam Walkiewicz Date: Sun, 9 Nov 2025 15:30:39 +0100 Subject: [PATCH 2/3] Move from Sphinx to Mkdocs * Update Move from Sphinx to Mkdocs * Update Move from Sphinx to Mkdocs * Update Move from Sphinx to Mkdocs * Update Move from Sphinx to Mkdocs * Update Move from Sphinx to Mkdocs * Update Move from Sphinx to Mkdocs * Update Move from Sphinx to Mkdocs * Update documentation --- .github/workflows/release.yml | 31 +- Makefile | 9 +- _config.yml | 1 - docs/.nojekyll | 0 docs/Makefile | 20 - docs/{readme.md => README.md} | 0 docs/_build/doctrees/README.doctree | Bin 22637 -> 0 bytes docs/_build/doctrees/cochar.doctree | Bin 476274 -> 0 bytes docs/_build/doctrees/environment.pickle | Bin 92055 -> 0 bytes docs/_build/doctrees/index.doctree | Bin 4944 -> 0 bytes docs/_build/doctrees/readme.doctree | Bin 23920 -> 0 bytes docs/_build/html/.buildinfo | 4 - docs/_build/html/README.html | 217 - docs/_build/html/_sources/README.md.txt | 105 - docs/_build/html/_sources/cochar.rst.txt | 50 - docs/_build/html/_sources/index.rst.txt | 21 - docs/_build/html/_sources/readme.md.txt | 123 - .../_sphinx_javascript_frameworks_compat.js | 134 - docs/_build/html/_static/basic.css | 900 -- docs/_build/html/_static/classic.css | 269 - docs/_build/html/_static/doctools.js | 156 - .../html/_static/documentation_options.js | 14 - docs/_build/html/_static/file.png | Bin 286 -> 0 bytes docs/_build/html/_static/jquery-3.6.0.js | 10881 ---------------- docs/_build/html/_static/jquery.js | 2 - docs/_build/html/_static/language_data.js | 199 - docs/_build/html/_static/minus.png | Bin 90 -> 0 bytes docs/_build/html/_static/plus.png | Bin 90 -> 0 bytes docs/_build/html/_static/pygments.css | 74 - docs/_build/html/_static/searchtools.js | 566 - docs/_build/html/_static/sidebar.js | 70 - docs/_build/html/_static/sphinx_highlight.js | 144 - docs/_build/html/_static/underscore-1.13.1.js | 2042 --- docs/_build/html/_static/underscore.js | 6 - docs/_build/html/cochar.html | 1615 --- docs/_build/html/genindex.html | 495 - docs/_build/html/index.html | 224 - docs/_build/html/objects.inv | 9 - docs/_build/html/py-modindex.html | 132 - docs/_build/html/readme.html | 259 - docs/_build/html/search.html | 106 - docs/_build/html/searchindex.js | 1 - docs/cochar.rst | 50 - docs/conf.py | 64 - CONTRIBUTION.md => docs/contribution.md | 3 +- docs/documentation.md | 3 + docs/environment.md | 113 + docs/getting-started.md | 138 + docs/index.html | 1 - docs/index.rst | 21 - docs/license.md | 1 + docs/make.bat | 35 - docs/use-make.md | 92 + mkdocs.yml | 34 + pyproject.toml | 4 +- src/cochar/__init__.py | 104 +- src/cochar/__main__.py | 33 +- src/cochar/character.py | 253 +- src/cochar/cochar.py | 424 +- src/cochar/config.py | 96 + src/cochar/error.py | 71 +- src/cochar/interface.py | 49 +- src/cochar/occup.py | 123 +- src/cochar/skill.py | 176 +- src/cochar/utils.py | 31 +- tests/test_character.py | 4 +- tests/test_cochar.py | 80 +- tests/test_cochar_misc.py | 96 +- tests/test_occupations.py | 17 +- tests/test_skills.py | 12 +- upload.sh | 118 - uv.lock | 446 +- 72 files changed, 1561 insertions(+), 20010 deletions(-) delete mode 100644 _config.yml delete mode 100644 docs/.nojekyll delete mode 100644 docs/Makefile rename docs/{readme.md => README.md} (100%) delete mode 100644 docs/_build/doctrees/README.doctree delete mode 100644 docs/_build/doctrees/cochar.doctree delete mode 100644 docs/_build/doctrees/environment.pickle delete mode 100644 docs/_build/doctrees/index.doctree delete mode 100644 docs/_build/doctrees/readme.doctree delete mode 100644 docs/_build/html/.buildinfo delete mode 100644 docs/_build/html/README.html delete mode 100644 docs/_build/html/_sources/README.md.txt delete mode 100644 docs/_build/html/_sources/cochar.rst.txt delete mode 100644 docs/_build/html/_sources/index.rst.txt delete mode 100644 docs/_build/html/_sources/readme.md.txt delete mode 100644 docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js delete mode 100644 docs/_build/html/_static/basic.css delete mode 100644 docs/_build/html/_static/classic.css delete mode 100644 docs/_build/html/_static/doctools.js delete mode 100644 docs/_build/html/_static/documentation_options.js delete mode 100644 docs/_build/html/_static/file.png delete mode 100644 docs/_build/html/_static/jquery-3.6.0.js delete mode 100644 docs/_build/html/_static/jquery.js delete mode 100644 docs/_build/html/_static/language_data.js delete mode 100644 docs/_build/html/_static/minus.png delete mode 100644 docs/_build/html/_static/plus.png delete mode 100644 docs/_build/html/_static/pygments.css delete mode 100644 docs/_build/html/_static/searchtools.js delete mode 100644 docs/_build/html/_static/sidebar.js delete mode 100644 docs/_build/html/_static/sphinx_highlight.js delete mode 100644 docs/_build/html/_static/underscore-1.13.1.js delete mode 100644 docs/_build/html/_static/underscore.js delete mode 100644 docs/_build/html/cochar.html delete mode 100644 docs/_build/html/genindex.html delete mode 100644 docs/_build/html/index.html delete mode 100644 docs/_build/html/objects.inv delete mode 100644 docs/_build/html/py-modindex.html delete mode 100644 docs/_build/html/readme.html delete mode 100644 docs/_build/html/search.html delete mode 100644 docs/_build/html/searchindex.js delete mode 100644 docs/cochar.rst delete mode 100644 docs/conf.py rename CONTRIBUTION.md => docs/contribution.md (97%) create mode 100644 docs/documentation.md create mode 100644 docs/environment.md create mode 100644 docs/getting-started.md delete mode 100644 docs/index.html delete mode 100644 docs/index.rst create mode 120000 docs/license.md delete mode 100644 docs/make.bat create mode 100644 docs/use-make.md create mode 100644 mkdocs.yml create mode 100644 src/cochar/config.py delete mode 100755 upload.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d406727..5334d00 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -97,4 +97,33 @@ jobs: run: gh release upload ${{ github.event.release.tag_name }} dist/* env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - \ No newline at end of file + + upload-gh-page: + runs-on: ubuntu-latest + needs: build-package + + permissions: + contents: write + pages: write + id-token: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Setup environment + run: | + make setup + + - name: Upload to GitHub Pages + run: | + uv run mkdocs gh-deploy --force + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index 95e4ba4..a2b31d7 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,11 @@ type: @echo "checking typing with mypy..." uv run mypy . +docs_serve: docs + uv run mkdocs serve + +docs_upload: docs + uv run mkdocs gh-deploy + docs: - @echo "Building documentation..." - uv run sphinx-build -b html docs/ docs/_build/html \ No newline at end of file + uv run mkdocs build \ No newline at end of file diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c419263..0000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-cayman \ No newline at end of file diff --git a/docs/.nojekyll b/docs/.nojekyll deleted file mode 100644 index e69de29..0000000 diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d4bb2cb..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/readme.md b/docs/README.md similarity index 100% rename from docs/readme.md rename to docs/README.md diff --git a/docs/_build/doctrees/README.doctree b/docs/_build/doctrees/README.doctree deleted file mode 100644 index 682d7fcb9707ed9d2d9569472af00500c6553f3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22637 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

c?&7RG~3v1+R3??(r+m@xFOWmL1x zk>l@V$otzX`AT_|X;mth>lPFAy;@3N16WLSQ&UN;avMu0Dl7O-ZeG#0J~J#rar5da z?E`)AQ{1w0c*LyQSHCvN6)BrlG+|mPYRxN~o@tS?9pq_|A~NIU=o%4*B9*3O`-j{} zaC^KdP3G?6Ze>PaY$dhltdE&l!p%!A=7>jmoR7yi_tnTCwzoW)w7nyDiv#7#5!SvC7cf-3 z$A^8?u3PoWvG#MuOrzR>q6zn`saUwg@Q9K*U=GO{S1es%9#_mkRlMLML#~tq{z9zi zyb%@^X@0LsN|>K&)B7%9my#|alJ_vN`|nCu95lAY0d21vT^uAdIvT~GC6uXBGJ2Gf zwBwvgrprQ%W$^11ZT*^Bc@e^aSNyQ)ALo!LJ@ZC%q{oNtPWy9YFWJ&!q>v^U- zOrtPM*dFcx5P@?E<4YuEtWToP)|V(I*KtZUa1+_d7UTg`b$bD?4dZT}{TtJ6l7drGy zH)g$zE46UVS9}Qfy_IkxJ}Zk;&lBRNE+3&ebObu82IqELxA8hDUjx_1+qCagN_0CI zeZ~EFBj5`cQG^F-j^krwhj5AbBkuN^rdw!QL9?_@GbOt1YcC>Itab_a$I-2N9*R61 zr5Ls$Qc7!0X1-*KX#5jeWVkmfSMk8qN75fM#NmFD z!Goeqs0erAA>wVC!*8JRD&FtIJ%!;x*QhvdwUk;LTcH~ZS~Z9XjabzZhJ!V0y#IE z1M~}(ApVa+qku4#Rt4mHaG_)T3KN~7Rt3wUcq+7lCT;?Fe*bK^w{5gbbUlE$mXCzN zT?%d3J9wwY5kABdS0sCd=;jl#;@b)Dr<{TTld*RW=$Dz-?Zmp6j zo>Eltk8$y|F-#_V+i(k(;nzeRX!g;X94r?5#%M)V-|So&50Anoo29sU#sZY0n8?j= zzqiryu~lwj2O1$?ChT{&O?NhhQyy-a@uOLu2Spte?_$!2mgV3aex%x?ar9i&-k@cn zLQvlh+MP{tE2g+|O8S9Ku~0?JC(1D#AXni9$Hsc^9*133B|DeKQIJvJ0$FAhPl$#PH$OH$fzP~k6z)9D zRpVD&aj{>;J<97-br2p%$u71;#kG@N%r}mpx}K~S@F5^TYD_L}_Mm$!?;@m^5~JU9 zjSt`_8{ehJZ((b!@f-B`7up>7Aw3RYv!=0+9^atH*Xi+jdb~o9-=@cJ(qjd)=EfCz zyiJd{=<&Do_#1k>OvPWP$6b27PLDsN$9s4L;RNwR(H6oU1V@{Kn@z#Vrr=^zaIh(A z-xM`(idr{CjhmvjO;OXPsAW^suo;*~ag(JG(EMg39o-xfNk<{&k#rQY97#vp`H^%K za1}{M;RBI$v^5e*N2|t>bhK6#NkmGv4`XEt9v#=B(rM+W!ng}dCGUxoh4a{B awJLT{MbF{X>2B4@D)q9mLy87{h5rQ!PKTuc diff --git a/docs/_build/doctrees/cochar.doctree b/docs/_build/doctrees/cochar.doctree deleted file mode 100644 index a30e7770c394799021b80cb16030cddbe23417c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 476274 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 diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree deleted file mode 100644 index 6a634286e207a6a06622dfbf3523e58239d8307d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4944 zcmds5U5gyY6)MY)cE*&H`d&r*-beG&gI| z2pEq-Nt65`CbzA==8@Vf4YUFgFTBqh=F>m~j7YDtO*9vY7Zata^u|1*_q{+;qG{-j z&b!5)1|McTI8mBN?Lqki%>6J+y!~%_`}+s`Zy)TxX^(49F_A@~N3<7F?4=usL=&FC2KA&6+Iyr$ zpe3b`ypT&8Xnsofa@Km7vyQp;KAl=8eYFnvIJcOaW=a6C&e^6K5z{4FOAe=jAeIp8 zJX8SRw1S8z1tFdr35koRc9^B}!H5JWl8&8DXBtNbDkYXk?Nm}l~*%z?jEswN7;z5ufdV*MKI|l{BGm-4gBsr%ro{H8$$hlq0aj3-eJofrELii_LhP1lIIjUmKrOjLuYY8kh{OT;RHNWv&oYn%0g=6)xz0l z@3Hr(X~$$5(p0nja2?Zvi$_$_ zFh5)~U5ASjNpud~F4E6@gKk)@!hUAm^<8$?xv2xUeP`LXW~cPb;7pPn`V&|b93blcW?iy7I!X%F5D!$2qBxi2T0z7GI`Ihj%v1^+E-o`$jhs? zRu)aHZ(VT3YzLXN6`fzokIZHzahdeUv=!AFNf$jp&)#pYrXNdpiz72Oe}b|L*Uc>D z4v$O+xt2Hi~6%T_h(McFSQVBaF6iBm1^4w6j>QVQ=^I-0Y4~ zb0&-ln4HFEM%NRvaL|Aq<-0GD42YykkE+Q)-5YzT_>Y*c|c$pl1HCd!O7U4h3D)5e$mWbnCt2st@G4pe8M99TpK1V^*2?F4&MJTLtHC3>V_K^Lq8G$ zDVhm$+kPM*0e~;!4PJIG#M>uXiZaQ5XmEW&nFr8BK*EzTI8Y^qU7IRYHd@l-u_bRL zND+;;K|IO98FU;WLiik8U=%gig}E6(>%^xh-69_!MbM+#{`QIKm3<`08jXvzc45|O za+;%HGVLOrAbvqbo96Au0>7x_T<6=vra&!?tP0wohq8^d*LgD|M51A*?uHTt+uTJM(fr|{b2{5`}4+6_b)K2Rtyp;&O1QWnG;GqD46qwG^b Vo{9a+(G6|ZD-(pRoU+m0e*p%yYD)kB diff --git a/docs/_build/doctrees/readme.doctree b/docs/_build/doctrees/readme.doctree deleted file mode 100644 index 1be78a71878649671187ee5abd121eb64b293be0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23920 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 - - - - - - - Call Of Cthulhu Character Generator — cochar 1.0.0-alpha.5 documentation - - - - - - - - - - - - -

- -
-
-
-
- -

PyPI version -License: GNU GPL v3 -Code style: black -Language: Python -Author: Walu

-
-

Call Of Cthulhu Character Generator¶

-

Fast way of creating a random character for Call of Cthulhu RPG 7th ed.

-
-

Summary¶

-

cochar stands for Call of Cthulhu Character. It’s a python package design to create a full characters for Call of Cthulhu RPG 7th ed.

-

A sample power cochar package can be observed on www.cochar.pl

-
-
-

Table of Contents¶

-
    -
  • Project Title

  • -
  • Summary

  • -
  • Table of Contents

  • -
  • Installation

  • -
  • Usage

  • -
  • Dependencies

  • -
  • Documentation

  • -
  • Contribution

  • -
  • Web version

  • -
  • Author

  • -
  • License

  • -
-
-
-

Installation¶

-
pip3 install cochar
-
-
-
-
-

Usage¶

-
-

Basic¶

-

Example:

-
>>> from cochar import create_character
->>> person = create_character(1925, "US")
->>> person
->>> Character(year=1925, country='US', first_name='Anthem', last_name='Pharr', age=22, sex='M', occupation='doctor of medicine', strength=33, condition=30, size=78, dexterity=40, appearance=23, education=87, intelligence=65, power=50, move_rate=7, luck=38, skills={'first aid': 38, 'language [latin]': 9, 'medicine': 73, 'science [biology]': 48, 'ride': 64, 'anthropology': 6, 'charm': 46, 'intimidate': 32, 'art/craft (sculptor)': 9, 'credit rating': 74, 'doge': 20}, damage_bonus='0', build=0, doge=20, sanity_points=50, magic_points=10, hit_points=10)
-
-
-
-
-

Default settings¶

-

Default settings are defined in ./data/settings.json.

-
{
-  "min_age": 15,
-  "max_age": 90,
-  "max_skill_level": 90,
-  "year": 1925,
-  "age": null,
-  "sex": null,
-  "first_name": null,
-  "last_name": null,
-  "country": "US",
-  "occupation": null,
-  "weights": true,
-  "database": "",
-  "show_warnings": false,
-  "occupation_type": null,
-  "era": null,
-  "tags": null
-}
-
-
-
-
-
-

Dependencies¶

-

cochar depends on randname module for generating random names.

-

For more details please see:

- -
-
-

Documentation¶

-

Detailed documentation of module can by found here: -cochar documentation

-
-
-

Contribution¶

-

If you want to contribute to cochar project read contribution for more information.

-
-
-

Web Version¶

-
-

Web application is not a part of cochar package.

-
-

Web application was design to present the power of cochar package. You can check it out on www.cochar.pl

-
-
-

Author¶

-

Adam Walkiewicz

-
-
-

License¶

-

Cochar is licensed under the terms of the GNU GPL v3

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/_sources/README.md.txt b/docs/_build/html/_sources/README.md.txt deleted file mode 100644 index 213fce2..0000000 --- a/docs/_build/html/_sources/README.md.txt +++ /dev/null @@ -1,105 +0,0 @@ -[![PyPI version](https://badge.fury.io/py/cochar.svg)](https://badge.fury.io/py/cochar) -[![License: GNU GPL v3](https://img.shields.io/badge/License-GNU%20GPL%20v3-red.svg)](https://github.com/ajwalkiewicz/cochar/blob/main/LICENSE) -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -[![Language: Python](https://img.shields.io/badge/Language-Python-blue.svg)](https://shields.io/) -[![Author: Walu](https://img.shields.io/badge/Aurhor-Walu-gray.svg)](https://shields.io/) - -# **C**all **O**f **C**thulhu C**har**acter Generator - -Fast way of creating a random character for Call of Cthulhu RPG 7th ed. - -## Summary - -`cochar` stands for `Call of Cthulhu Character`. It's a python package design to create a full characters for Call of Cthulhu RPG 7th ed. - -A sample power `cochar` package can be observed on [www.cochar.pl](www.cochar.pl) - -## Table of Contents - -- [Project Title](#call-of-cthulhu-character-generator) -- [Summary](#summary) -- [Table of Contents](#table-of-contents) -- [Installation](#installation) -- [Usage](#usage) -- [Dependencies](#dependencies) -- [Documentation](#documentation) -- [Contribution](#contribution) -- [Web version](#web-version) -- [Author](#author) -- [License](#license) - -## Installation - -``` -pip3 install cochar -``` - -## Usage - -### Basic - -Example: - -```Python ->>> from cochar import create_character ->>> person = create_character(1925, "US") ->>> person ->>> Character(year=1925, country='US', first_name='Anthem', last_name='Pharr', age=22, sex='M', occupation='doctor of medicine', strength=33, condition=30, size=78, dexterity=40, appearance=23, education=87, intelligence=65, power=50, move_rate=7, luck=38, skills={'first aid': 38, 'language [latin]': 9, 'medicine': 73, 'science [biology]': 48, 'ride': 64, 'anthropology': 6, 'charm': 46, 'intimidate': 32, 'art/craft (sculptor)': 9, 'credit rating': 74, 'doge': 20}, damage_bonus='0', build=0, doge=20, sanity_points=50, magic_points=10, hit_points=10) -``` - -### Default settings - -Default settings are defined in `./data/settings.json`. - -```json -{ - "min_age": 15, - "max_age": 90, - "max_skill_level": 90, - "year": 1925, - "age": null, - "sex": null, - "first_name": null, - "last_name": null, - "country": "US", - "occupation": null, - "weights": true, - "database": "", - "show_warnings": false, - "occupation_type": null, - "era": null, - "tags": null -} -``` - -## Dependencies - -`cochar` depends on [randname](https://github.com/ajwalkiewicz/randname) module for generating random names. - -For more details please see: - -- [randname github](https://github.com/ajwalkiewicz/randname) -- [randname pypi](https://pypi.org/project/rname/) - -## Documentation - -Detailed documentation of module can by found here: -[cochar documentation](https://ajwalkiewicz.github.io/cochar/_build/html/index.html#) - -## Contribution - -If you want to contribute to `cochar` project read [contribution](https://github.com/ajwalkiewicz/cochar/blob/main/CONTRIBUTION.md) for more information. - -## Web Version - -> Web application is not a part of `cochar` package. - -Web application was design to present the power of `cochar` package. You can check it out on [www.cochar.pl](www.cochar.pl) - -## Author - -Adam Walkiewicz - -## License - -Cochar is licensed under the terms of the [GNU GPL v3](https://github.com/ajwalkiewicz/cochar/blob/main/LICENSE) diff --git a/docs/_build/html/_sources/cochar.rst.txt b/docs/_build/html/_sources/cochar.rst.txt deleted file mode 100644 index b85425d..0000000 --- a/docs/_build/html/_sources/cochar.rst.txt +++ /dev/null @@ -1,50 +0,0 @@ -cochar package -============== - -cochar.cochar module --------------------- - -.. automodule:: cochar.cochar - :members: - :undoc-members: - :show-inheritance: - -cochar.character module ------------------------ - -.. automodule:: cochar.character - :members: - :undoc-members: - :show-inheritance: - -cochar.occupations module -------------------------- - -.. automodule:: cochar.occup - :members: - :undoc-members: - :show-inheritance: - -cochar.skills module --------------------- - -.. automodule:: cochar.skill - :members: - :undoc-members: - :show-inheritance: - -cochar.utils module -------------------- - -.. automodule:: cochar.utils - :members: - :undoc-members: - :show-inheritance: - -cochar.errors module --------------------- - -.. automodule:: cochar.error - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/index.rst.txt b/docs/_build/html/_sources/index.rst.txt deleted file mode 100644 index fa56cbd..0000000 --- a/docs/_build/html/_sources/index.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -.. cochar documentation master file, created by - sphinx-quickstart on Wed Jun 23 22:24:25 2021. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to cochar's documentation! -================================== - -.. toctree:: - :maxdepth: 3 - :caption: Contents: - - readme - cochar - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/_build/html/_sources/readme.md.txt b/docs/_build/html/_sources/readme.md.txt deleted file mode 100644 index 5a803ba..0000000 --- a/docs/_build/html/_sources/readme.md.txt +++ /dev/null @@ -1,123 +0,0 @@ - - -[![PyPI version](https://badge.fury.io/py/cochar.svg)](https://badge.fury.io/py/cochar) -[![License: GNU AGPL v3](https://img.shields.io/badge/License-GNU%20AGPL%20v3-red.svg)](https://github.com/ajwalkiewicz/cochar/blob/main/LICENSE) -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -[![Language: Python](https://img.shields.io/badge/Language-Python-blue.svg)](https://shields.io/) -[![Author: Walu](https://img.shields.io/badge/Aurhor-Walu-gray.svg)](https://shields.io/) - -# **C**all **O**f **C**thulhu C**har**acter Generator - -Fast way of creating a random character for Call of Cthulhu RPG 7th ed. - -## Summary - -`cochar` stands for `Call of Cthulhu Character`. It's a python package design to create a full characters for Call of Cthulhu RPG 7th ed. - -[www.cochar.pl](http://www.cochar.pl) demonstrates a power of `cochar` package. - -## Table of Contents - -- [Project Title](#call-of-cthulhu-character-generator) -- [Summary](#summary) -- [Table of Contents](#table-of-contents) -- [Installation](#installation) -- [Usage](#usage) -- [Dependencies](#dependencies) -- [Documentation](#documentation) -- [Contribution](#contribution) -- [Web version](#web-version) -- [Author](#author) -- [License](#license) - -## Installation - -``` -pip3 install cochar -``` - -## Usage - -### Basic - -Example: - -```Python ->>> from cochar import create_character ->>> person = create_character(1925, "US") ->>> person ->>> Character(year=1925, country='US', first_name='Anthem', last_name='Pharr', age=22, sex='M', occupation='doctor of medicine', strength=33, condition=30, size=78, dexterity=40, appearance=23, education=87, intelligence=65, power=50, move_rate=7, luck=38, skills={'first aid': 38, 'language [latin]': 9, 'medicine': 73, 'science [biology]': 48, 'ride': 64, 'anthropology': 6, 'charm': 46, 'intimidate': 32, 'art/craft (sculptor)': 9, 'credit rating': 74, 'dodge': 20}, damage_bonus='0', build=0, dodge=20, sanity_points=50, magic_points=10, hit_points=10) -``` - -### Default settings - -Default settings are defined in `./data/settings.json`. - -```json -{ - "min_age": 15, - "max_age": 90, - "max_skill_level": 90, - "year": 1925, - "age": null, - "sex": null, - "first_name": null, - "last_name": null, - "country": "US", - "occupation": null, - "weights": true, - "database": "", - "show_warnings": false, - "occupation_type": null, - "era": null, - "tags": null -} -``` - -## Dependencies - -`cochar` depends on [randname](https://github.com/ajwalkiewicz/randname) module for generating random names. - -For more details please see: - -- [randname github](https://github.com/ajwalkiewicz/randname) -- [randname pypi](https://pypi.org/project/rname/) - -## Documentation - -Detailed documentation of module can by found here: -[cochar documentation](https://ajwalkiewicz.github.io/cochar/_build/html/index.html#) - -## Contribution - -If you want to contribute to `cochar` project read [contribution](https://github.com/ajwalkiewicz/cochar/blob/main/CONTRIBUTION.md) for more information. - -## Web Version - -> Web application is not a part of `cochar` package. - -Web application was design to present the power of `cochar` package. You can check it out on [www.cochar.pl](http://www.cochar.pl) - -## Author - -Adam Walkiewicz - -## License - -Cochar is licensed under the terms of the [GNU AGPL v3](https://github.com/ajwalkiewicz/cochar/blob/main/LICENSE) diff --git a/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js b/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js deleted file mode 100644 index 8549469..0000000 --- a/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js +++ /dev/null @@ -1,134 +0,0 @@ -/* - * _sphinx_javascript_frameworks_compat.js - * ~~~~~~~~~~ - * - * Compatability shim for jQuery and underscores.js. - * - * WILL BE REMOVED IN Sphinx 6.0 - * xref RemovedInSphinx60Warning - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - - -/** - * small helper function to urldecode strings - * - * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL - */ -jQuery.urldecode = function(x) { - if (!x) { - return x - } - return decodeURIComponent(x.replace(/\+/g, ' ')); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && - !jQuery(node.parentNode).hasClass(className) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - var bbox = node.parentElement.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css deleted file mode 100644 index 4e9a9f1..0000000 --- a/docs/_build/html/_static/basic.css +++ /dev/null @@ -1,900 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li p.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 360px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, figure.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, figure.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, figure.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, figure.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar, -aside.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} -nav.contents, -aside.topic, -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ -nav.contents, -aside.topic, -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -aside.sidebar > :last-child, -nav.contents > :last-child, -aside.topic > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -aside.sidebar::after, -nav.contents::after, -aside.topic::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure, figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption, figcaption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number, -figcaption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text, -figcaption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - -/* -- object description styles --------------------------------------------- */ - -.sig { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; -} - -.sig-name, code.descname { - background-color: transparent; - font-weight: bold; -} - -.sig-name { - font-size: 1.1em; -} - -code.descname { - font-size: 1.2em; -} - -.sig-prename, code.descclassname { - background-color: transparent; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.sig-param.n { - font-style: italic; -} - -/* C++ specific styling */ - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset; -} - -.sig.c .k, .sig.c .kt, -.sig.cpp .k, .sig.cpp .kt { - color: #0033B3; -} - -.sig.c .m, -.sig.cpp .m { - color: #1750EB; -} - -.sig.c .s, .sig.c .sc, -.sig.cpp .s, .sig.cpp .sc { - color: #067D17; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} -aside.footnote > span, -div.citation > span { - float: left; -} -aside.footnote > span:last-of-type, -div.citation > span:last-of-type { - padding-right: 0.5em; -} -aside.footnote > p { - margin-left: 2em; -} -div.citation > p { - margin-left: 4em; -} -aside.footnote > p:last-of-type, -div.citation > p:last-of-type { - margin-bottom: 0em; -} -aside.footnote > p:last-of-type:after, -div.citation > p:last-of-type:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0 0.5em; - content: ":"; - display: inline-block; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; - white-space: nowrap; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; - -webkit-user-select: text; /* Safari fallback only */ - -webkit-user-select: none; /* Chrome/Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+ */ -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/_build/html/_static/classic.css b/docs/_build/html/_static/classic.css deleted file mode 100644 index 92cac9f..0000000 --- a/docs/_build/html/_static/classic.css +++ /dev/null @@ -1,269 +0,0 @@ -/* - * classic.css_t - * ~~~~~~~~~~~~~ - * - * Sphinx stylesheet -- classic theme. - * - * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -html { - /* CSS hack for macOS's scrollbar (see #1125) */ - background-color: #FFFFFF; -} - -body { - font-family: sans-serif; - font-size: 100%; - background-color: #11303d; - color: #000; - margin: 0; - padding: 0; -} - -div.document { - display: flex; - background-color: #1c4e63; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 230px; -} - -div.body { - background-color: #ffffff; - color: #000000; - padding: 0 20px 30px 20px; -} - -div.footer { - color: #ffffff; - width: 100%; - padding: 9px 0 9px 0; - text-align: center; - font-size: 75%; -} - -div.footer a { - color: #ffffff; - text-decoration: underline; -} - -div.related { - background-color: #133f52; - line-height: 30px; - color: #ffffff; -} - -div.related a { - color: #ffffff; -} - -div.sphinxsidebar { -} - -div.sphinxsidebar h3 { - font-family: 'Trebuchet MS', sans-serif; - color: #ffffff; - font-size: 1.4em; - font-weight: normal; - margin: 0; - padding: 0; -} - -div.sphinxsidebar h3 a { - color: #ffffff; -} - -div.sphinxsidebar h4 { - font-family: 'Trebuchet MS', sans-serif; - color: #ffffff; - font-size: 1.3em; - font-weight: normal; - margin: 5px 0 0 0; - padding: 0; -} - -div.sphinxsidebar p { - color: #ffffff; -} - -div.sphinxsidebar p.topless { - margin: 5px 10px 10px 10px; -} - -div.sphinxsidebar ul { - margin: 10px; - padding: 0; - color: #ffffff; -} - -div.sphinxsidebar a { - color: #98dbcc; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - - - -/* -- hyperlink styles ------------------------------------------------------ */ - -a { - color: #355f7c; - text-decoration: none; -} - -a:visited { - color: #355f7c; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - - - -/* -- body styles ----------------------------------------------------------- */ - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Trebuchet MS', sans-serif; - background-color: #f2f2f2; - font-weight: normal; - color: #20435c; - border-bottom: 1px solid #ccc; - margin: 20px -20px 10px -20px; - padding: 3px 0 3px 10px; -} - -div.body h1 { margin-top: 0; font-size: 200%; } -div.body h2 { font-size: 160%; } -div.body h3 { font-size: 140%; } -div.body h4 { font-size: 120%; } -div.body h5 { font-size: 110%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #c60f0f; - font-size: 0.8em; - padding: 0 4px 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - background-color: #c60f0f; - color: white; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - text-align: justify; - line-height: 130%; -} - -div.admonition p.admonition-title + p { - display: inline; -} - -div.admonition p { - margin-bottom: 5px; -} - -div.admonition pre { - margin-bottom: 5px; -} - -div.admonition ul, div.admonition ol { - margin-bottom: 5px; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} -nav.contents, -aside.topic, - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre { - padding: 5px; - background-color: unset; - color: unset; - line-height: 120%; - border: 1px solid #ac9; - border-left: none; - border-right: none; -} - -code { - background-color: #ecf0f3; - padding: 0 1px 0 1px; - font-size: 0.95em; -} - -th, dl.field-list > dt { - background-color: #ede; -} - -.warning code { - background: #efc2c2; -} - -.note code { - background: #d6d6d6; -} - -.viewcode-back { - font-family: sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} - -div.code-block-caption { - color: #efefef; - background-color: #1c4e63; -} \ No newline at end of file diff --git a/docs/_build/html/_static/doctools.js b/docs/_build/html/_static/doctools.js deleted file mode 100644 index 527b876..0000000 --- a/docs/_build/html/_static/doctools.js +++ /dev/null @@ -1,156 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Base JavaScript utilities for all Sphinx HTML documentation. - * - * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ -"use strict"; - -const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ - "TEXTAREA", - "INPUT", - "SELECT", - "BUTTON", -]); - -const _ready = (callback) => { - if (document.readyState !== "loading") { - callback(); - } else { - document.addEventListener("DOMContentLoaded", callback); - } -}; - -/** - * Small JavaScript module for the documentation. - */ -const Documentation = { - init: () => { - Documentation.initDomainIndexTable(); - Documentation.initOnKeyListeners(); - }, - - /** - * i18n support - */ - TRANSLATIONS: {}, - PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), - LOCALE: "unknown", - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext: (string) => { - const translated = Documentation.TRANSLATIONS[string]; - switch (typeof translated) { - case "undefined": - return string; // no translation - case "string": - return translated; // translation exists - default: - return translated[0]; // (singular, plural) translation tuple exists - } - }, - - ngettext: (singular, plural, n) => { - const translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated !== "undefined") - return translated[Documentation.PLURAL_EXPR(n)]; - return n === 1 ? singular : plural; - }, - - addTranslations: (catalog) => { - Object.assign(Documentation.TRANSLATIONS, catalog.messages); - Documentation.PLURAL_EXPR = new Function( - "n", - `return (${catalog.plural_expr})` - ); - Documentation.LOCALE = catalog.locale; - }, - - /** - * helper function to focus on search bar - */ - focusSearchBar: () => { - document.querySelectorAll("input[name=q]")[0]?.focus(); - }, - - /** - * Initialise the domain index toggle buttons - */ - initDomainIndexTable: () => { - const toggler = (el) => { - const idNumber = el.id.substr(7); - const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); - if (el.src.substr(-9) === "minus.png") { - el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; - toggledRows.forEach((el) => (el.style.display = "none")); - } else { - el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; - toggledRows.forEach((el) => (el.style.display = "")); - } - }; - - const togglerElements = document.querySelectorAll("img.toggler"); - togglerElements.forEach((el) => - el.addEventListener("click", (event) => toggler(event.currentTarget)) - ); - togglerElements.forEach((el) => (el.style.display = "")); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); - }, - - initOnKeyListeners: () => { - // only install a listener if it is really needed - if ( - !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && - !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS - ) - return; - - document.addEventListener("keydown", (event) => { - // bail for input elements - if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; - // bail with special keys - if (event.altKey || event.ctrlKey || event.metaKey) return; - - if (!event.shiftKey) { - switch (event.key) { - case "ArrowLeft": - if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; - - const prevLink = document.querySelector('link[rel="prev"]'); - if (prevLink && prevLink.href) { - window.location.href = prevLink.href; - event.preventDefault(); - } - break; - case "ArrowRight": - if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; - - const nextLink = document.querySelector('link[rel="next"]'); - if (nextLink && nextLink.href) { - window.location.href = nextLink.href; - event.preventDefault(); - } - break; - } - } - - // some keyboard layouts may need Shift to get / - switch (event.key) { - case "/": - if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; - Documentation.focusSearchBar(); - event.preventDefault(); - } - }); - }, -}; - -// quick alias for translations -const _ = Documentation.gettext; - -_ready(Documentation.init); diff --git a/docs/_build/html/_static/documentation_options.js b/docs/_build/html/_static/documentation_options.js deleted file mode 100644 index 114d5bc..0000000 --- a/docs/_build/html/_static/documentation_options.js +++ /dev/null @@ -1,14 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '1.0.1', - LANGUAGE: 'en', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false, - SHOW_SEARCH_SUMMARY: true, - ENABLE_SEARCH_SHORTCUTS: true, -}; \ No newline at end of file diff --git a/docs/_build/html/_static/file.png b/docs/_build/html/_static/file.png deleted file mode 100644 index a858a410e4faa62ce324d814e4b816fff83a6fb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( diff --git a/docs/_build/html/_static/jquery-3.6.0.js b/docs/_build/html/_static/jquery-3.6.0.js deleted file mode 100644 index fc6c299..0000000 --- a/docs/_build/html/_static/jquery-3.6.0.js +++ /dev/null @@ -1,10881 +0,0 @@ -/*! - * jQuery JavaScript Library v3.6.0 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright OpenJS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2021-03-02T17:08Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var flat = arr.flat ? function( array ) { - return arr.flat.call( array ); -} : function( array ) { - return arr.concat.apply( [], array ); -}; - - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 - // Plus for old WebKit, typeof returns "function" for HTML collections - // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) - return typeof obj === "function" && typeof obj.nodeType !== "number" && - typeof obj.item !== "function"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - -var document = window.document; - - - - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true - }; - - function DOMEval( code, node, doc ) { - doc = doc || document; - - var i, val, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[ i ] || node.getAttribute && node.getAttribute( i ); - if ( val ) { - script.setAttribute( i, val ); - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; -} -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.6.0", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - even: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return ( i + 1 ) % 2; - } ) ); - }, - - odd: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return i % 2; - } ) ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - copy = options[ name ]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if ( name === "__proto__" || target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - src = target[ name ]; - - // Ensure proper type for the source value - if ( copyIsArray && !Array.isArray( src ) ) { - clone = []; - } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { - clone = {}; - } else { - clone = src; - } - copyIsArray = false; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a provided context; falls back to the global one - // if not specified. - globalEval: function( code, options, doc ) { - DOMEval( code, { nonce: options && options.nonce }, doc ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return flat( ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), - function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); - } ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType( obj ); - - if ( isFunction( obj ) || isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.6 - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://js.foundation/ - * - * Date: 2021-02-16 - */ -( function( window ) { -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - nonnativeSelectorCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ( {} ).hasOwnProperty, - arr = [], - pop = arr.pop, - pushNative = arr.push, - push = arr.push, - slice = arr.slice, - - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[ i ] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + - "ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram - identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - - // "Attribute values must be CSS identifiers [capture 5] - // or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + - whitespace + "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + - whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + - "*" ), - rdescend = new RegExp( whitespace + "|>" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + - whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + - whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + - "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + - "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rhtml = /HTML$/i, - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), - funescape = function( escape, nonHex ) { - var high = "0x" + escape.slice( 1 ) - 0x10000; - - return nonHex ? - - // Strip the backslash prefix from a non-hex escape sequence - nonHex : - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + - ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - inDisabledFieldset = addCombinator( - function( elem ) { - return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - ( arr = slice.call( preferredDoc.childNodes ) ), - preferredDoc.childNodes - ); - - // Support: Android<4.0 - // Detect silently failing push.apply - // eslint-disable-next-line no-unused-expressions - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - pushNative.apply( target, slice.call( els ) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - - // Can't trust NodeList.length - while ( ( target[ j++ ] = els[ i++ ] ) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - setDocument( context ); - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { - - // ID selector - if ( ( m = match[ 1 ] ) ) { - - // Document context - if ( nodeType === 9 ) { - if ( ( elem = context.getElementById( m ) ) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && ( elem = newContext.getElementById( m ) ) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[ 2 ] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !nonnativeSelectorCache[ selector + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && - - // Support: IE 8 only - // Exclude object elements - ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { - - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // The technique has to be used as well when a leading combinator is used - // as such selectors are not recognized by querySelectorAll. - // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && - ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - - // We can use :scope instead of the ID hack if the browser - // supports it & if we're not changing the context. - if ( newContext !== context || !support.scope ) { - - // Capture the context ID, setting it first if necessary - if ( ( nid = context.getAttribute( "id" ) ) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", ( nid = expando ) ); - } - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + - toSelector( groups[ i ] ); - } - newSelector = groups.join( "," ); - } - - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - nonnativeSelectorCache( selector, true ); - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return ( cache[ key + " " ] = value ); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement( "fieldset" ); - - try { - return !!fn( el ); - } catch ( e ) { - return false; - } finally { - - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split( "|" ), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[ i ] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( ( cur = cur.nextSibling ) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return ( name === "input" || name === "button" ) && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction( function( argument ) { - argument = +argument; - return markFunction( function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ ( j = matchIndexes[ i ] ) ] ) { - seed[ j ] = !( matches[ j ] = seed[ j ] ); - } - } - } ); - } ); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - var namespace = elem && elem.namespaceURI, - docElem = elem && ( elem.ownerDocument || elem ).documentElement; - - // Support: IE <=8 - // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes - // https://bugs.jquery.com/ticket/4833 - return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9 - 11+, Edge 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( preferredDoc != document && - ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, - // Safari 4 - 5 only, Opera <=11.6 - 12.x only - // IE/Edge & older browsers don't support the :scope pseudo-class. - // Support: Safari 6.0 only - // Safari 6.0 supports :scope but it's an alias of :root there. - support.scope = assert( function( el ) { - docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); - return typeof el.querySelectorAll !== "undefined" && - !el.querySelectorAll( ":scope fieldset div" ).length; - } ); - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert( function( el ) { - el.className = "i"; - return !el.getAttribute( "className" ); - } ); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert( function( el ) { - el.appendChild( document.createComment( "" ) ); - return !el.getElementsByTagName( "*" ).length; - } ); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert( function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - } ); - - // ID filter and find - if ( support.getById ) { - Expr.filter[ "ID" ] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute( "id" ) === attrId; - }; - }; - Expr.find[ "ID" ] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter[ "ID" ] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode( "id" ); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find[ "ID" ] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( ( elem = elems[ i++ ] ) ) { - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find[ "TAG" ] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert( function( el ) { - - var input; - - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll( "[selected]" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push( "~=" ); - } - - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement( "input" ); - input.setAttribute( "name", "" ); - el.appendChild( input ); - if ( !el.querySelectorAll( "[name='']" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + - whitespace + "*(?:''|\"\")" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll( ":checked" ).length ) { - rbuggyQSA.push( ":checked" ); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push( ".#.+[+~]" ); - } - - // Support: Firefox <=3.6 - 5 only - // Old Firefox doesn't throw on a badly-escaped identifier. - el.querySelectorAll( "\\\f" ); - rbuggyQSA.push( "[\\r\\n\\f]" ); - } ); - - assert( function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement( "input" ); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll( "[name=d]" ).length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: Opera 10 - 11 only - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll( "*,:x" ); - rbuggyQSA.push( ",.*:" ); - } ); - } - - if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector ) ) ) ) { - - assert( function( el ) { - - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - } ); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - ) ); - } : - function( a, b ) { - if ( b ) { - while ( ( b = b.parentNode ) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { - - // Choose the first element that is related to our preferred document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( a == document || a.ownerDocument == preferredDoc && - contains( preferredDoc, a ) ) { - return -1; - } - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( b == document || b.ownerDocument == preferredDoc && - contains( preferredDoc, b ) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - return a == document ? -1 : - b == document ? 1 : - /* eslint-enable eqeqeq */ - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( ( cur = cur.parentNode ) ) { - ap.unshift( cur ); - } - cur = b; - while ( ( cur = cur.parentNode ) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[ i ] === bp[ i ] ) { - i++; - } - - return i ? - - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[ i ], bp[ i ] ) : - - // Otherwise nodes in our document sort first - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - ap[ i ] == preferredDoc ? -1 : - bp[ i ] == preferredDoc ? 1 : - /* eslint-enable eqeqeq */ - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - setDocument( elem ); - - if ( support.matchesSelector && documentIsHTML && - !nonnativeSelectorCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch ( e ) { - nonnativeSelectorCache( expr, true ); - } - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( context.ownerDocument || context ) != document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( elem.ownerDocument || elem ) != document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - ( val = elem.getAttributeNode( name ) ) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return ( sel + "" ).replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - - // If no nodeType, this is expected to be an array - while ( ( node = elem[ i++ ] ) ) { - - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[ 1 ] = match[ 1 ].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[ 3 ] = ( match[ 3 ] || match[ 4 ] || - match[ 5 ] || "" ).replace( runescape, funescape ); - - if ( match[ 2 ] === "~=" ) { - match[ 3 ] = " " + match[ 3 ] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[ 1 ] = match[ 1 ].toLowerCase(); - - if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { - - // nth-* requires argument - if ( !match[ 3 ] ) { - Sizzle.error( match[ 0 ] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[ 4 ] = +( match[ 4 ] ? - match[ 5 ] + ( match[ 6 ] || 1 ) : - 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); - match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - - // other types prohibit arguments - } else if ( match[ 3 ] ) { - Sizzle.error( match[ 0 ] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[ 6 ] && match[ 2 ]; - - if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[ 3 ] ) { - match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - - // Get excess from tokenize (recursively) - ( excess = tokenize( unquoted, true ) ) && - - // advance to the next closing parenthesis - ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { - - // excess is a negative index - match[ 0 ] = match[ 0 ].slice( 0, excess ); - match[ 2 ] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { - return true; - } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - ( pattern = new RegExp( "(^|" + whitespace + - ")" + className + "(" + whitespace + "|$)" ) ) && classCache( - className, function( elem ) { - return pattern.test( - typeof elem.className === "string" && elem.className || - typeof elem.getAttribute !== "undefined" && - elem.getAttribute( "class" ) || - "" - ); - } ); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - /* eslint-disable max-len */ - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - /* eslint-enable max-len */ - - }; - }, - - "CHILD": function( type, what, _argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, _context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( ( node = node[ dir ] ) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( ( node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - - // Use previously-cached element index if available - if ( useCache ) { - - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - - // Use the same loop as above to seek `elem` from the start - while ( ( node = ++nodeIndex && node && node[ dir ] || - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || - ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction( function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[ i ] ); - seed[ idx ] = !( matches[ idx ] = matched[ i ] ); - } - } ) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - - // Potentially complex pseudos - "not": markFunction( function( selector ) { - - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction( function( seed, matches, _context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( ( elem = unmatched[ i ] ) ) { - seed[ i ] = !( matches[ i ] = elem ); - } - } - } ) : - function( elem, _context, xml ) { - input[ 0 ] = elem; - matcher( input, null, xml, results ); - - // Don't keep the element (issue #299) - input[ 0 ] = null; - return !results.pop(); - }; - } ), - - "has": markFunction( function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - } ), - - "contains": markFunction( function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; - }; - } ), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - - // lang value must be a valid identifier - if ( !ridentifier.test( lang || "" ) ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( ( elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); - return false; - }; - } ), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && - ( !document.hasFocus || document.hasFocus() ) && - !!( elem.type || elem.href || ~elem.tabIndex ); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return ( nodeName === "input" && !!elem.checked ) || - ( nodeName === "option" && !!elem.selected ); - }, - - "selected": function( elem ) { - - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - // eslint-disable-next-line no-unused-expressions - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos[ "empty" ]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( ( attr = elem.getAttribute( "type" ) ) == null || - attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo( function() { - return [ 0 ]; - } ), - - "last": createPositionalPseudo( function( _matchIndexes, length ) { - return [ length - 1 ]; - } ), - - "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - } ), - - "even": createPositionalPseudo( function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "odd": createPositionalPseudo( function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? - argument + length : - argument > length ? - length : - argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ) - } -}; - -Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || ( match = rcomma.exec( soFar ) ) ) { - if ( match ) { - - // Don't consume trailing commas as valid - soFar = soFar.slice( match[ 0 ].length ) || soFar; - } - groups.push( ( tokens = [] ) ); - } - - matched = false; - - // Combinators - if ( ( match = rcombinators.exec( soFar ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - - // Cast descendant combinators to space - type: match[ 0 ].replace( rtrim, " " ) - } ); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || - ( match = preFilters[ type ]( match ) ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - type: type, - matches: match - } ); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[ i ].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || ( elem[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || - ( outerCache[ elem.uniqueID ] = {} ); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( ( oldCache = uniqueCache[ key ] ) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return ( newCache[ 2 ] = oldCache[ 2 ] ); - } else { - - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[ i ]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[ 0 ]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[ i ], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( ( elem = unmatched[ i ] ) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction( function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( - selector || "*", - context.nodeType ? [ context ] : context, - [] - ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( ( elem = temp[ i ] ) ) { - matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) ) { - - // Restore matcherIn since elem is not yet a final match - temp.push( ( matcherIn[ i ] = elem ) ); - } - } - postFinder( null, ( matcherOut = [] ), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) && - ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { - - seed[ temp ] = !( results[ temp ] = elem ); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - } ); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[ 0 ].type ], - implicitRelative = leadingRelative || Expr.relative[ " " ], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - ( checkContext = context ).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { - matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; - } else { - matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[ j ].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens - .slice( 0, i - 1 ) - .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), - - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), - len = elems.length; - - if ( outermost ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - outermostContext = context == document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( !context && elem.ownerDocument != document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( ( matcher = elementMatchers[ j++ ] ) ) { - if ( matcher( elem, context || document, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - - // They will have gone through all possible matchers - if ( ( elem = !matcher && elem ) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( ( matcher = setMatchers[ j++ ] ) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !( unmatched[ i ] || setMatched[ i ] ) ) { - setMatched[ i ] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[ i ] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( - selector, - matcherFromGroupMatchers( elementMatchers, setMatchers ) - ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( ( selector = compiled.selector || selector ) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[ 0 ] = match[ 0 ].slice( 0 ); - if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - - context = ( Expr.find[ "ID" ]( token.matches[ 0 ] - .replace( runescape, funescape ), context ) || [] )[ 0 ]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[ i ]; - - // Abort if we hit a combinator - if ( Expr.relative[ ( type = token.type ) ] ) { - break; - } - if ( ( find = Expr.find[ type ] ) ) { - - // Search, expanding context for leading sibling combinators - if ( ( seed = find( - token.matches[ 0 ].replace( runescape, funescape ), - rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || - context - ) ) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert( function( el ) { - - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; -} ); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert( function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute( "href" ) === "#"; -} ) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - } ); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert( function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -} ) ) { - addHandle( "value", function( elem, _name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - } ); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert( function( el ) { - return el.getAttribute( "disabled" ) == null; -} ) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - ( val = elem.getAttributeNode( name ) ) && val.specified ? - val.value : - null; - } - } ); -} - -return Sizzle; - -} )( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -} -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Filtered directly for both simple and complex selectors - return jQuery.filter( qualifier, elements, not ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, _i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, _i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, _i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( elem.contentDocument != null && - - // Support: IE 11+ - // elements with no `data` attribute has an object - // `contentDocument` with a `null` prototype. - getProto( elem.contentDocument ) ) { - - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && toType( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( _i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[ 3 - i ][ 3 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock, - - // progress_handlers.lock - tuples[ 0 ][ 3 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the primary Deferred - primary = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - primary.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( primary.state() === "pending" || - isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return primary.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); - } - - return primary.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( toType( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, _key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; - - -// Matches dashed string for camelizing -var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; - -// Used by camelCase as callback to replace() -function fcamelCase( _all, letter ) { - return letter.toUpperCase(); -} - -// Convert dashed to camelCase; used by the css and data modules -// Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (#9572) -function camelCase( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -} -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( camelCase ); - } else { - key = camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var documentElement = document.documentElement; - - - - var isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ); - }, - composed = { composed: true }; - - // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only - // Check attachment across shadow DOM boundaries when possible (gh-3504) - // Support: iOS 10.0-10.2 only - // Early iOS 10 versions support `attachShadow` but not `getRootNode`, - // leading to errors. We need to check for `getRootNode`. - if ( documentElement.getRootNode ) { - isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ) || - elem.getRootNode( composed ) === elem.ownerDocument; - }; - } -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - isAttached( elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, scale, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = elem.nodeType && - ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - while ( maxIterations-- ) { - - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style( elem, prop, initialInUnit + unit ); - if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { - maxIterations = 0; - } - initialInUnit = initialInUnit / scale; - - } - - initialInUnit = initialInUnit * 2; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); - -var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); - - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; - - // Support: IE <=9 only - // IE <=9 replaces "; - support.option = !!div.lastChild; -} )(); - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// Support: IE <=9 only -if ( !support.option ) { - wrapMap.optgroup = wrapMap.option = [ 1, "" ]; -} - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, attached, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( toType( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - attached = isAttached( elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( attached ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 - 11+ -// focus() and blur() are asynchronous, except when they are no-op. -// So expect focus to be synchronous when the element is already active, -// and blur to be synchronous when the element is not already active. -// (focus and blur are always synchronous in other supported browsers, -// this just defines when we can count on it). -function expectSync( elem, type ) { - return ( elem === safeActiveElement() ) === ( type === "focus" ); -} - -// Support: IE <=9 only -// Accessing document.activeElement can throw unexpectedly -// https://bugs.jquery.com/ticket/13393 -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Only attach events to objects that accept data - if ( !acceptData( elem ) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = Object.create( null ); - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( nativeEvent ), - - handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // If the event is namespaced, then each handler is only invoked if it is - // specially universal or its namespaces are a superset of the event's. - if ( !event.rnamespace || handleObj.namespace === false || - event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - - // Utilize native event to ensure correct state for checkable inputs - setup: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Claim the first handler - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - // dataPriv.set( el, "click", ... ) - leverageNative( el, "click", returnTrue ); - } - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Force setup before triggering a click - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - leverageNative( el, "click" ); - } - - // Return non-false to allow normal event-path propagation - return true; - }, - - // For cross-browser consistency, suppress native .click() on links - // Also prevent it if we're currently inside a leveraged native-event stack - _default: function( event ) { - var target = event.target; - return rcheckableType.test( target.type ) && - target.click && nodeName( target, "input" ) && - dataPriv.get( target, "click" ) || - nodeName( target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -// Ensure the presence of an event listener that handles manually-triggered -// synthetic events by interrupting progress until reinvoked in response to -// *native* events that it fires directly, ensuring that state changes have -// already occurred before other listeners are invoked. -function leverageNative( el, type, expectSync ) { - - // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add - if ( !expectSync ) { - if ( dataPriv.get( el, type ) === undefined ) { - jQuery.event.add( el, type, returnTrue ); - } - return; - } - - // Register the controller as a special universal handler for all event namespaces - dataPriv.set( el, type, false ); - jQuery.event.add( el, type, { - namespace: false, - handler: function( event ) { - var notAsync, result, - saved = dataPriv.get( this, type ); - - if ( ( event.isTrigger & 1 ) && this[ type ] ) { - - // Interrupt processing of the outer synthetic .trigger()ed event - // Saved data should be false in such cases, but might be a leftover capture object - // from an async native handler (gh-4350) - if ( !saved.length ) { - - // Store arguments for use when handling the inner native event - // There will always be at least one argument (an event object), so this array - // will not be confused with a leftover capture object. - saved = slice.call( arguments ); - dataPriv.set( this, type, saved ); - - // Trigger the native event and capture its result - // Support: IE <=9 - 11+ - // focus() and blur() are asynchronous - notAsync = expectSync( this, type ); - this[ type ](); - result = dataPriv.get( this, type ); - if ( saved !== result || notAsync ) { - dataPriv.set( this, type, false ); - } else { - result = {}; - } - if ( saved !== result ) { - - // Cancel the outer synthetic event - event.stopImmediatePropagation(); - event.preventDefault(); - - // Support: Chrome 86+ - // In Chrome, if an element having a focusout handler is blurred by - // clicking outside of it, it invokes the handler synchronously. If - // that handler calls `.remove()` on the element, the data is cleared, - // leaving `result` undefined. We need to guard against this. - return result && result.value; - } - - // If this is an inner synthetic event for an event with a bubbling surrogate - // (focus or blur), assume that the surrogate already propagated from triggering the - // native event and prevent that from happening again here. - // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the - // bubbling surrogate propagates *after* the non-bubbling base), but that seems - // less bad than duplication. - } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { - event.stopPropagation(); - } - - // If this is a native event triggered above, everything is now in order - // Fire an inner synthetic event with the original arguments - } else if ( saved.length ) { - - // ...and capture the result - dataPriv.set( this, type, { - value: jQuery.event.trigger( - - // Support: IE <=9 - 11+ - // Extend with the prototype to reset the above stopImmediatePropagation() - jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), - saved.slice( 1 ), - this - ) - } ); - - // Abort handling of the native event - event.stopImmediatePropagation(); - } - } - } ); -} - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || Date.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - code: true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - which: true -}, jQuery.event.addProp ); - -jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { - jQuery.event.special[ type ] = { - - // Utilize native event if possible so blur/focus sequence is correct - setup: function() { - - // Claim the first handler - // dataPriv.set( this, "focus", ... ) - // dataPriv.set( this, "blur", ... ) - leverageNative( this, type, expectSync ); - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function() { - - // Force setup before trigger - leverageNative( this, type ); - - // Return non-false to allow normal event-path propagation - return true; - }, - - // Suppress native focus or blur as it's already being fired - // in leverageNative. - _default: function() { - return true; - }, - - delegateType: delegateType - }; -} ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - // Support: IE <=10 - 11, Edge 12 - 13 only - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( elem ).children( "tbody" )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { - elem.type = elem.type.slice( 5 ); - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.get( src ); - events = pdataOld.events; - - if ( events ) { - dataPriv.remove( dest, "handle events" ); - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = flat( args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - valueIsFunction = isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( valueIsFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( valueIsFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl && !node.noModule ) { - jQuery._evalUrl( node.src, { - nonce: node.nonce || node.getAttribute( "nonce" ) - }, doc ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && isAttached( node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html; - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = isAttached( elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - -var swap = function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - -var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; - - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; - - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - // Support: Chrome <=64 - // Don't get tricked when zoom affects offsetWidth (gh-4029) - div.style.position = "absolute"; - scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - function roundPixelMeasures( measure ) { - return Math.round( parseFloat( measure ) ); - } - - var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableTrDimensionsVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - jQuery.extend( support, { - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles: function() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize: function() { - computeStyleTests(); - return scrollboxSizeVal; - }, - - // Support: IE 9 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Behavior in IE 9 is more subtle than in newer versions & it passes - // some versions of this test; make sure not to make it pass there! - // - // Support: Firefox 70+ - // Only Firefox includes border widths - // in computed dimensions. (gh-4529) - reliableTrDimensions: function() { - var table, tr, trChild, trStyle; - if ( reliableTrDimensionsVal == null ) { - table = document.createElement( "table" ); - tr = document.createElement( "tr" ); - trChild = document.createElement( "div" ); - - table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; - tr.style.cssText = "border:1px solid"; - - // Support: Chrome 86+ - // Height set through cssText does not get applied. - // Computed height then comes back as 0. - tr.style.height = "1px"; - trChild.style.height = "9px"; - - // Support: Android 8 Chrome 86+ - // In our bodyBackground.html iframe, - // display for all div elements is set to "inline", - // which causes a problem only in Android 8 Chrome 86. - // Ensuring the div is display: block - // gets around this issue. - trChild.style.display = "block"; - - documentElement - .appendChild( table ) - .appendChild( tr ) - .appendChild( trChild ); - - trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + - parseInt( trStyle.borderTopWidth, 10 ) + - parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; - - documentElement.removeChild( table ); - } - return reliableTrDimensionsVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !isAttached( elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style, - vendorProps = {}; - -// Return a vendor-prefixed property or undefined -function vendorPropName( name ) { - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a potentially-mapped jQuery.cssProps or vendor prefixed property -function finalPropName( name ) { - var final = jQuery.cssProps[ name ] || vendorProps[ name ]; - - if ( final ) { - return final; - } - if ( name in emptyStyle ) { - return name; - } - return vendorProps[ name ] = vendorPropName( name ) || name; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }; - -function setPositiveNumber( _elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0; - - // Adjustment may not be necessary - if ( box === ( isBorderBox ? "border" : "content" ) ) { - return 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin - if ( box === "margin" ) { - delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); - } - - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if ( !isBorderBox ) { - - // Add padding - delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // For "border" or "margin", add border - if ( box !== "padding" ) { - delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - - // But still keep track of it otherwise - } else { - extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - - // If we get here with a border-box (content + padding + border), we're seeking "content" or - // "padding" or "margin" - } else { - - // For "content", subtract padding - if ( box === "content" ) { - delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // For "content" or "padding", subtract border - if ( box !== "margin" ) { - delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - // Account for positive content-box scroll gutter when requested by providing computedVal - if ( !isBorderBox && computedVal >= 0 ) { - - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max( 0, Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - computedVal - - delta - - extra - - 0.5 - - // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter - // Use an explicit zero to avoid NaN (gh-3964) - ) ) || 0; - } - - return delta; -} - -function getWidthOrHeight( elem, dimension, extra ) { - - // Start with computed style - var styles = getStyles( elem ), - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). - // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox, - - val = curCSS( elem, dimension, styles ), - offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); - - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if ( rnumnonpx.test( val ) ) { - if ( !extra ) { - return val; - } - val = "auto"; - } - - - // Support: IE 9 - 11 only - // Use offsetWidth/offsetHeight for when box sizing is unreliable. - // In those cases, the computed value can be trusted to be border-box. - if ( ( !support.boxSizingReliable() && isBorderBox || - - // Support: IE 10 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Interestingly, in some cases IE 9 doesn't suffer from this issue. - !support.reliableTrDimensions() && nodeName( elem, "tr" ) || - - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - val === "auto" || - - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && - - // Make sure the element is visible & connected - elem.getClientRects().length ) { - - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Where available, offsetWidth/offsetHeight approximate border box dimensions. - // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the - // retrieved value as a content box dimension. - valueIsBorderBox = offsetProp in elem; - if ( valueIsBorderBox ) { - val = elem[ offsetProp ]; - } - } - - // Normalize "" and auto - val = parseFloat( val ) || 0; - - // Adjust for the element's box model - return ( val + - boxModelAdjustment( - elem, - dimension, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles, - - // Provide the current computed size to request scroll gutter calculation (gh-3589) - val - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "gridArea": true, - "gridColumn": true, - "gridColumnEnd": true, - "gridColumnStart": true, - "gridRow": true, - "gridRowEnd": true, - "gridRowStart": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: {}, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append - // "px" to a few hardcoded values. - if ( type === "number" && !isCustomProp ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( _i, dimension ) { - jQuery.cssHooks[ dimension ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = getStyles( elem ), - - // Only read styles.position if the test has a chance to fail - // to avoid forcing a reflow. - scrollboxSizeBuggy = !support.scrollboxSize() && - styles.position === "absolute", - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) - boxSizingNeeded = scrollboxSizeBuggy || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra ? - boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ) : - 0; - - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && scrollboxSizeBuggy ) { - subtract -= Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - parseFloat( styles[ dimension ] ) - - boxModelAdjustment( elem, dimension, "border", false, styles ) - - 0.5 - ); - } - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ dimension ] = value; - value = jQuery.css( elem, dimension ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( prefix !== "margin" ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || - tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = Date.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - result.stop.bind( result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = Date.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -function classesToArray( value ) { - if ( Array.isArray( value ) ) { - return value; - } - if ( typeof value === "string" ) { - return value.match( rnothtmlwhite ) || []; - } - return []; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isValidValue = type === "string" || Array.isArray( value ); - - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( isValidValue ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = classesToArray( value ); - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, valueIsFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - valueIsFunction = isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( valueIsFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -support.focusin = "onfocusin" in window; - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function( e ) { - e.stopPropagation(); - }; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = lastElement = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - lastElement = cur; - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - - if ( event.isPropagationStopped() ) { - lastElement.addEventListener( type, stopPropagationCallback ); - } - - elem[ type ](); - - if ( event.isPropagationStopped() ) { - lastElement.removeEventListener( type, stopPropagationCallback ); - } - - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - - // Handle: regular nodes (via `this.ownerDocument`), window - // (via `this.document`) & document (via `this`). - var doc = this.ownerDocument || this.document || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this.document || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = { guid: Date.now() }; - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml, parserErrorElem; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) {} - - parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; - if ( !xml || parserErrorElem ) { - jQuery.error( "Invalid XML: " + ( - parserErrorElem ? - jQuery.map( parserErrorElem.childNodes, function( el ) { - return el.textContent; - } ).join( "\n" ) : - data - ) ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && toType( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - if ( a == null ) { - return ""; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ).filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ).map( function( _i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - -originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() + " " ] = - ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) - .concat( match[ 2 ] ); - } - } - match = responseHeaders[ key.toLowerCase() + " " ]; - } - return match == null ? null : match.join( ", " ); - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 15 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available and should be processed, append data to url - if ( s.data && ( s.processData || typeof s.data === "string" ) ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + - uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Use a noop converter for missing script but not if jsonp - if ( !isSuccess && - jQuery.inArray( "script", s.dataTypes ) > -1 && - jQuery.inArray( "json", s.dataTypes ) < 0 ) { - s.converters[ "text script" ] = function() {}; - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( _i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - -jQuery.ajaxPrefilter( function( s ) { - var i; - for ( i in s.headers ) { - if ( i.toLowerCase() === "content-type" ) { - s.contentType = s.headers[ i ] || ""; - } - } -} ); - - -jQuery._evalUrl = function( url, options, doc ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - - // Only evaluate the response if it is successful (gh-4126) - // dataFilter is not invoked for failure responses, so using it instead - // of the default converter is kludgy but it works. - converters: { - "text script": function() {} - }, - dataFilter: function( response ) { - jQuery.globalEval( response, options, doc ); - } - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var htmlIsFunction = isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.ontimeout = - xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain or forced-by-attrs requests - if ( s.crossDomain || s.scriptAttrs ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - - - - - - - -
-
-
-
- -
-

cochar package¶

-
-

cochar.cochar module¶

-

Cochar - main module

-
-
-cochar.cochar.calc_build(strength: int, size: int) int¶
-

Return build based on sum od strength and size.

-

f: X -> Y

-

X: {64, 84, 124, 164, 204, 283, 364, 444, 524} -Y: {-2, -1, 0, 1, 2, 3, 4, 5, 6}

-

TODO: Increase bonus damage for +1K6 for every 80 points above 524

-
-
Parameters:
-
    -
  • strength (int) – character’s strength

  • -
  • size (int) – character’s size

  • -
-
-
Returns:
-

character’s build

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.cochar.calc_combat_characteristics(strength: int, size: int, dexterity: int, damage_bonus: str = '', build: int = 0, dodge: int = 0) Tuple[str, int, int]¶
-

Based on strength, size and dexterity, -return combat characteristics such as: -dame bonus, build, dodge

-
-
Parameters:
-
    -
  • strength (int) – strength points

  • -
  • size (int) – size points

  • -
  • dexterity (int) – dexterity points

  • -
-
-
Returns:
-

(damage bonus, build, dodge)

-
-
Return type:
-

Tuple(str, int, int)

-
-
-
- -
-
-cochar.cochar.calc_damage_bonus(strength: int, size: int) str¶
-

Return damage bonus, based on sum of strength and size.

-

f: X -> Y

-

X: {64, 84, 124, 164, 204, 283, 364, 444, 524} -Y: {“-2â€, “-1â€, “0â€, “+1K4â€, “+1K6â€, “+2K6â€, “+3K6â€, “+4K6â€, “+5K6â€,}

-

TODO: Increase bonus damage for +1K6 for every 80 points above 524

-
-
Parameters:
-
    -
  • strength (int) – character’s strength

  • -
  • size (int) – character’s size

  • -
-
-
Returns:
-

character’s damage bonus

-
-
Return type:
-

str

-
-
-
- -
-
-cochar.cochar.calc_derived_attributes(power: int, size: int, condition: int, sanity_points: int = 0, magic_points: int = 0, hit_points: int = 0) Tuple[int, int, int]¶
-

Based on power, size and condition, -return sanity, magic and hit points

-
-
Parameters:
-
    -
  • power (int) – power points

  • -
  • size (int) – size points

  • -
  • condition (int) – condition points

  • -
  • sanity_points (int, optional) – sanity points, defaults to 0

  • -
  • magic_points (int, optional) – magic points, defaults to 0

  • -
  • hit_points (int, optional) – hit points, defaults to 0

  • -
-
-
Returns:
-

(sanity points, magic points, hit points)

-
-
Return type:
-

tuple

-
-
-
- -
-
-cochar.cochar.calc_dodge(dexterity: int) int¶
-

Return dodge based on dexterity:

-

dodge = dexterity // 2

-
-
Parameters:
-

dexterity (int) – character’s dexterity

-
-
Returns:
-

character’s dodge

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.cochar.calc_hit_points(size: int, condition: int) int¶
-

Return hit points based on size and condition.

-
-
Parameters:
-
    -
  • size (int) – size value

  • -
  • condition (int) – condition value

  • -
-
-
Returns:
-

hit points

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.cochar.calc_magic_points(power: int) int¶
-

Return magic points based on power

-
-
Parameters:
-

power (int) – power value

-
-
Returns:
-

magic points

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.cochar.calc_move_rate(strength: int, dexterity: int, size: int) int¶
-

Return move rate base on relations between -strength, dexterity and size

-

if both dexterity and strength are smaller than size, -return 7 -if both strength and size are higher or equal than size, -return 9 -else return 8

-
-
Parameters:
-
    -
  • strength (int) – character’s strength

  • -
  • dexterity (int) – characters dexterity

  • -
  • size (int) – character’s size

  • -
-
-
Returns:
-

move rate

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.cochar.calc_sanity_points(power: int) int¶
-

Return sanity points based on power

-
-
Parameters:
-

power (int) – power value

-
-
Returns:
-

sanity points

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.cochar.characteristic_test(tested_value: int, repetition: int = 1) int¶
-

Perform characteristic test.

-

Roll number between 1 to 100, -If that number is higher than tested value, than increase tested value with random number, -between 1 to 10. -Repeat repetition times. -If result would be higher than 99, return 99

-
-
Parameters:
-
    -
  • tested_value (int) – tested value

  • -
  • repetition (int) – how many test to perform

  • -
-
-
Returns:
-

unchanged or increased tested value, but not higher than 99

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.cochar.create_character(year: int, country: str, first_name: ~typing.Optional[str] = None, last_name: ~typing.Optional[str] = None, age: ~typing.Optional[int] = None, sex: ~typing.Optional[str] = None, random_mode: bool = False, occupation: ~typing.Optional[str] = None, skills: ~cochar.skill.SkillsDict = {}, occup_type: ~typing.Optional[str] = None, era: ~typing.Optional[str] = None, tags: ~typing.Optional[~typing.List[str]] = None, skills_generator: ~cochar.skill.SkillsGenerator = <cochar.skill.SkillsGenerator object>) Character¶
-

Main function for creating Character. -Use this function instead of instantiating Character class.

-
-
Parameters:
-
    -
  • year (int) – year of the game

  • -
  • country (str) – country of character’s origin

  • -
  • first_name (str, optional) – character’s first name, defaults to “â€

  • -
  • last_name (str, optional) – character’s last name, defaults to “â€

  • -
  • age (int, optional) – character’s age, defaults to False

  • -
  • sex (str, optional) – character’s sex, defaults to False

  • -
  • random_mode (bool, optional) – choose occupation completely randomly, regardless the character’s statistics, defaults to “Falseâ€

  • -
  • occupation (str, optional) – character’s occupation return provided occupation as character’s occupation if it exists, defaults to “Noneâ€

  • -
  • skills (Skills, optional) – character’s skills, defaults to {}

  • -
  • occup_type (str, optional) – occupation type, defaults to None

  • -
  • era (str, optional) – occupation era, defaults to None

  • -
  • tags (List[str], optional) – occupation tags, defaults to None

  • -
-
-
Raises:
-

ValueError – raise if sex is incorrect

-
-
Returns:
-

generated character

-
-
Return type:
-

Character

-
-
-
- -
-
-cochar.cochar.generate_age(year: int, sex: str, age: int = False) int¶
-

Generate characters age, based on year and sex. -Return age if age is provided.

-
-
Parameters:
-
    -
  • year (int) – year of the game

  • -
  • sex (str) – character’s sex

  • -
  • age (int, optional) – character’s age, defaults to False

  • -
-
-
Returns:
-

character’s age

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.cochar.generate_base_characteristics(age, strength: int = 0, condition: int = 0, size: int = 0, dexterity: int = 0, appearance: int = 0, education: int = 0, intelligence: int = 0, power: int = 0, luck: int = 0, move_rate: int = 0) tuple¶
-

Return base characteristics based on age as a tuple.

-

Base characteristics: -1. strength -2. condition -3. size -4. dexterity -5. appearance -6. education -7. intelligence -8. power -9. luck -10. move rate

-
-
Parameters:
-
    -
  • age (int) – character’s age

  • -
  • strength (int, optional) – strength, defaults to 0

  • -
  • condition (int, optional) – condition, defaults to 0

  • -
  • size (int, optional) – size, defaults to 0

  • -
  • dexterity (int, optional) – dexterity, defaults to 0

  • -
  • appearance (int, optional) – appearance, defaults to 0

  • -
  • education (int, optional) – education, defaults to 0

  • -
  • intelligence (int, optional) – intelligence, defaults to 0

  • -
  • power (int, optional) – power, defaults to 0

  • -
  • move_rate (int, optional) – move rate, defaults to 0

  • -
  • luck (int, optional) – luck, defaults to 0

  • -
-
-
Returns:
-

(strength, condition, size, dexterity, appearance, education, intelligence, power, luck, move_rate)

-
-
Return type:
-

tuple

-
-
-
- -
-
-cochar.cochar.generate_first_name(year: int, sex: str, country: str, weights: bool) str¶
-

Return random first name based on given parameters.

-
-
Parameters:
-
    -
  • year (int) – year of the data set with names (if data set not available use a closes available data set)

  • -
  • sex (str) – name gender, available options [‘M’, ‘F’, ‘N’, None]

  • -
  • country (str) – name country

  • -
  • weights (bool) – if true, take under account popularity of names. [default: True]

  • -
-
-
Returns:
-

first name

-
-
Return type:
-

str

-
-
-
- -
-
-cochar.cochar.generate_last_name(year: int, sex: str, country: str, weights: bool) str¶
-

Return random last name based on the given parameters

-
-
Parameters:
-
    -
  • year (int) – year of the data set with names (if data set not available use a closes available data set)

  • -
  • sex (str) – name gender, available options [‘M’, ‘F’, ‘N’, None]

  • -
  • country (str) – name country

  • -
  • weights (bool) – If true, take under account popularity of names. [default: True]

  • -
-
-
Returns:
-

last name

-
-
Return type:
-

str

-
-
-
- -
-
-cochar.cochar.generate_sex(sex: Optional[Union[str, bool]] = None) str¶
-

Generate character’s sex

-
-
Parameters:
-

sex (Union[str, bool]) – Character’s sex, if provided return that value

-
-
Raises:
-

ValueError – If provided sex is not in {“Mâ€, “Fâ€, None}, raise this error

-
-
Returns:
-

Character’s sex as “M†or “Fâ€

-
-
Return type:
-

str

-
-
-
- -
-
-cochar.cochar.subtract_points_from_characteristic(characteristic_points: int, subtract_points: int) int¶
-

Subtract points from characteristic points, -but if result would be zero or below, than return 1.

-
-
Parameters:
-
    -
  • characteristic_points (int) – _description_

  • -
  • subtract_points (int) – _description_

  • -
-
-
Returns:
-

_description_

-
-
Return type:
-

int

-
-
-
>>> education = 50
->>> points_to_subtract = 10
->>> subtract_points_from_characteristic(education, points_to_subtract)
-40
->>> points_to_subtract = 60
->>> subtract_points_from_characteristic(education, points_to_subtract)
-1
-
-
-
- -
-
-cochar.cochar.subtract_points_from_str_con_dex(strength: int, condition: int, dexterity: int, subtract_points: int) Tuple[int, int, int]¶
-

Subtract certain amount of points from strength, condition and -dexterity, but prevent each of the characteristics to be -lower than 1.

-
-
Parameters:
-
    -
  • strength (int) – character’s strength

  • -
  • condition (int) – character’s condition

  • -
  • dexterity (int) – character’s dexterity

  • -
  • subtract_points (int) – amount of points to subtract

  • -
-
-
Returns:
-

(strength, condition, dexterity)

-
-
Return type:
-

Tuple[int, int, int]

-
-
-
- -
-
-

cochar.character module¶

-

“This module contains classes related with Character object itself.

-
-
-class cochar.character.Age(min_age: int, max_age: int)¶
-

Bases: Validator

-

Character’s age.

-
-
Parameters:
-
    -
  • min_age (int) – minimal character’s age

  • -
  • max_age (int) – maximal character’s age

  • -
-
-
-
-
-validate(new_age: int) None¶
-

Validate character’s age.

-
-
Parameters:
-

new_age (int) – character’s new age

-
-
Raises:
-
-
-
-
- -
- -
-
-class cochar.character.Build¶
-

Bases: Validator

-

Character’s build.

-

correct_values = [-2, -1, 0, 1, 2, 3, 4, 5, 6]

-

TODO: increase range. +1 for each 80 point above STR+SIZ.

-
-
-validate(new_build: int) None¶
-

Validate character’s build.

-
-
Parameters:
-

new_build (int) – character’s new build

-
-
Raises:
-

InvalidBuildValue – Invalid build. {new_build} not in {correct_values}

-
-
-
- -
- -
-
-class cochar.character.Character(year: int = 0, country: str = '', first_name: str = '', last_name: str = '', age: int = 0, sex: str = '', occupation: str = '', strength: int = 0, condition: int = 0, size: int = 0, dexterity: int = 0, appearance: int = 0, education: int = 0, intelligence: int = 0, power: int = 0, luck: int = 0, move_rate: int = 0, damage_bonus: str = 0, build: int = 0, dodge: int = 0, skills: SkillsDict = {}, sanity_points: int = 0, magic_points: int = 0, hit_points: int = 0)¶
-

Bases: object

-

Container for character.

-
-
-age¶
-

Character’s age.

-
-
Parameters:
-
    -
  • min_age (int) – minimal character’s age

  • -
  • max_age (int) – maximal character’s age

  • -
-
-
-
- -
-
-appearance¶
-

Base characteristic for character class

-
- -
-
-build¶
-

Character’s build.

-

correct_values = [-2, -1, 0, 1, 2, 3, 4, 5, 6]

-

TODO: increase range. +1 for each 80 point above STR+SIZ.

-
- -
-
-condition¶
-

Base characteristic for character class

-
- -
-
-country¶
-

Character’s country.

-

Country depends on available data. By default database from -external randname package is taken. -Country also defines what dataset will be used for generating character’s -name.

-

See randname.available_countries().

-
- -
-
-damage_bonus¶
-

Character damage bonus.

-

correct_values = ['-2', '-1', '0', '+1K4', '+1K6', '+2K6', '+3K6', '+4K6', '+5K6']

-
- -
-
-dexterity¶
-

Base characteristic for character class

-
- -
-
-dodge¶
-

Base characteristic for character class

-
- -
-
-education¶
-

Base characteristic for character class

-
- -
-
-first_name¶
-

Character’s name

-
- -
-
-get_json_format() dict¶
-

Return character’s full characteristics as a dictionary.

-
-
Returns:
-

full characteristics

-
-
Return type:
-

dict

-
-
-
- -
-
-hit_points¶
-

Base characteristic for character class

-
- -
-
-intelligence¶
-

Base characteristic for character class

-
- -
-
-last_name¶
-

Character’s name

-
- -
-
-luck¶
-

Base characteristic for character class

-
- -
-
-magic_points¶
-

Base characteristic for character class

-
- -
-
-move_rate¶
-

Base characteristic for character class

-
- -
-
-occupation¶
-

Character’s occupation.

-

Available occupations are defined in occupation database.

-
- -
-
-power¶
-

Base characteristic for character class

-
- -
-
-sanity_points¶
-

Base characteristic for character class

-
- -
-
-sex¶
-

Character’s sex.

-

Available sex options: -- M: male -- F: female -- None: for non binary

-

As there are not any data for non binary names. -When None is selected sex will be randomly drawn from M or F

-
>>> c = Character(year=1925, country="US", sex="F")
->>> c.sex
-'F'
-
-
-
- -
-
-size¶
-

Base characteristic for character class

-
- -
-
-property skills: SkillsDict¶
-

Character’s skills.

-
-
Returns:
-

character’s skills

-
-
Return type:
-

cochar.skill.Skills

-
-
-
- -
-
-strength¶
-

Base characteristic for character class

-
- -
-
-year¶
-

Year in game.

-

Technically any integer is a valid year. But practically that depends -on database with names used to generate names.

-

Besides name, also character’s age depends on the year. Probability of -generating certain year is related with the population age pyramid at the -certain year.

-

Lowest and highest year in the data defines effective range for year. Years -below or above are treated the same as in the lowest or highest years in data. -That means for example if data for names ends on the year 2010, than setting -higher year will give same results as 2010.

-
- -
- -
-
-class cochar.character.Characteristic(min_value=None)¶
-

Bases: Validator

-

Base characteristic for character class

-
-
-validate(value: int)¶
-

Check if characteristic is a valid number and is not below min_value

-
-
Parameters:
-

value (int) – value to validate

-
-
Raises:
-
-
-
-
- -
- -
-
-class cochar.character.Country¶
-

Bases: Validator

-

Character’s country.

-

Country depends on available data. By default database from -external randname package is taken. -Country also defines what dataset will be used for generating character’s -name.

-

See randname.available_countries().

-
-
-validate(new_country: str) None¶
-

Validate character’s country.

-
-
Parameters:
-

new_country (str) – character’s new country

-
-
Raises:
-

InvalidCountryValue – “Country not available: {new_country} -> {randname.available_countries()}

-
-
-
- -
- -
-
-class cochar.character.DamageBonus¶
-

Bases: Validator

-

Character damage bonus.

-

correct_values = ['-2', '-1', '0', '+1K4', '+1K6', '+2K6', '+3K6', '+4K6', '+5K6']

-
-
-validate(new_damage_bonus: str) None¶
-

Validate character’s damage bonus.

-
-
Parameters:
-

new_damage_bonus (str) – character’s new damage bonus

-
-
Raises:
-

InvalidDamageBonusValue – Invalid damage bonus. {new_damage_bonus} not in {correct_values}

-
-
-
- -
- -
-
-class cochar.character.Name¶
-

Bases: Validator

-

Character’s name

-
-
-validate(new_name: str)¶
-

Check if name is a valid name.

-
-
Parameters:
-

new_name (str) – new character name

-
-
Raises:
-

cochar.error.EmptyName – raise if new_name is empty

-
-
-
- -
- -
-
-class cochar.character.Occupation(available_occupations)¶
-

Bases: Validator

-

Character’s occupation.

-

Available occupations are defined in occupation database.

-
-
-validate(new_occupation: str) None¶
-

Validate character’s occupation.

-
-
Parameters:
-

new_occupation (str) – character’s new occupation

-
-
Raises:
-

InvalidOccupationValue – raise when new_occupation is not in OCCUPATION_LIST

-
-
-
- -
- -
-
-class cochar.character.Sex¶
-

Bases: Validator

-

Character’s sex.

-

Available sex options: -- M: male -- F: female -- None: for non binary

-

As there are not any data for non binary names. -When None is selected sex will be randomly drawn from M or F

-
>>> c = Character(year=1925, country="US", sex="F")
->>> c.sex
-'F'
-
-
-
-
-validate(new_sex: Optional[str]) None¶
-

Validate character’s sex.

-
-
Parameters:
-

new_sex (str | None) – character’s new sex

-
-
Raises:
-

InvalidSexValue – Incorrect sex value: sex -> [‘M’, ‘F’, None’]

-
-
-
- -
- -
-
-class cochar.character.Validator¶
-

Bases: ABC

-

It’s a parent class for all other descriptors.

-

Defines validate method, that needs to be implemented by -all children.

-
-
Parameters:
-

ABC (ABCMeta) – abstract base class

-
-
-
-
-abstract validate(value)¶
-
- -
- -
-
-class cochar.character.Year¶
-

Bases: Validator

-

Year in game.

-

Technically any integer is a valid year. But practically that depends -on database with names used to generate names.

-

Besides name, also character’s age depends on the year. Probability of -generating certain year is related with the population age pyramid at the -certain year.

-

Lowest and highest year in the data defines effective range for year. Years -below or above are treated the same as in the lowest or highest years in data. -That means for example if data for names ends on the year 2010, than setting -higher year will give same results as 2010.

-
-
-validate(new_year: int) None¶
-

Validate if year is an integer.

-
-
Parameters:
-

new_year (int) – new year of the game

-
-
Raises:
-

cochar.error.InvalidYearValue – raise when new_year is not an integer

-
-
-
>>> character = create_character()
->>> character.year = 1800
-
-
-
- -
- -
-
-

cochar.occupations module¶

-

Occupations -Occupations is a module that contains functions related -with occupations

-
-
-cochar.occup.calc_hobby_points(intelligence: int, hobby_points: Optional[int] = None) int¶
-

Return hobby points, based on intelligence.

-

occupation points = 2 * intelligence

-

If hobby_points provided, return hobby_points

-
-
Parameters:
-
    -
  • intelligence (int) – intelligence points

  • -
  • hobby_points (int, optional) – hobby_points, defaults to None

  • -
-
-
Returns:
-

hobby points

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.occup.calc_occupation_points(occupation: str, education: int, power: int, dexterity: int, appearance: int, strength: int, occupation_points: Optional[int] = None) int¶
-

Return occupation points based on occupation, education, power, -dexterity, appearance and strength.

-

If occupation_points provided, return occupation_points

-
-
Parameters:
-
    -
  • occupation (str) – occupation points

  • -
  • education (int) – education points

  • -
  • power (int) – power points

  • -
  • dexterity (int) – dexterity points

  • -
  • appearance (int) – appearance points

  • -
  • strength (int) – strength points

  • -
  • occupation_points (int, optional) – occupation points, if provided function returns that value instead of calculating it, defaults to None

  • -
-
-
Returns:
-

occupation points for provided occupation

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.occup.generate_occupation(education: int = 1, power: int = 1, dexterity: int = 1, appearance: int = 1, strength: int = 1, random_mode: bool = False, occupation: Optional[str] = None, occup_type: Optional[str] = None, era: Optional[List[str]] = None, tags: Optional[List[str]] = None) str¶
-

Return occupation based on: -education, power, dexterity, appearance and strength.

-
-
Parameters:
-
    -
  • education (int, optional) – education points, defaults to 1

  • -
  • power (int, optional) – power points, defaults to 1

  • -
  • dexterity (int, optional) – dexterity points, defaults to 1

  • -
  • appearance (int, optional) – appearance points, defaults to 1

  • -
  • strength (int, optional) – strength points, defaults to 1

  • -
  • random_mode (bool, optional) – ignore edu, pow, dex and str points and return totally random occupation, defaults to False

  • -
  • occupation (str, optional) – return specified occupation, defaults to None

  • -
  • occup_type (str, optional) – specify type of occupation to return, defaults to None

  • -
  • era (str, optional) – specify era of occupation to return, defaults to None

  • -
  • tags (List[str], optional) – return occupation with defined tags, defaults to None

  • -
-
-
Raises:
-
-
-
Returns:
-

occupation name

-
-
Return type:
-

str

-
-
-
- -
-
-cochar.occup.get_occupation_list()¶
-
- -
-
-

cochar.skills module¶

-

Skills -Skills module contains all functions related with skills -and Skills object, which is a container for skills

-
-
-class cochar.skill.SkillsDict(dict=None, /, **kwargs)¶
-

Bases: UserDict

-

Dictionary like object to store character’s skills. -Override __setitem__ to validate skills data.

-
-
Parameters:
-

UserDict (abc.ABCMeta) – UserDict from collections

-
-
-
-
-get_json_format()¶
-

Return Skills as a dictionary

-
- -
- -
-
-class cochar.skill.SkillsGenerator(interface: SkillsDataInterface)¶
-

Bases: object

-
-
-generate_skills(occupation: str, occupation_points: int, hobby_points: int, dexterity: int, education: int, skills: Optional[SkillsDict] = None) SkillsDict¶
-

Return skills based on: -occupation, occupation_points, hobby_points, dexterity and education

-

If skills provided, return skills

-

Each occupation has related skills, that are chosen randomly. Then -each skill has randomly assigned skill level - number of points related -with that skill.

-

Dexterity is required for dodge skill. -Education is required for language(own) skill.

-
-
Parameters:
-
    -
  • occupation (str) – occupation

  • -
  • occupation_points (int) – occupation_points

  • -
  • hobby_points (int) – hobby_points

  • -
  • dexterity (int) – dexterity

  • -
  • education (int) – education

  • -
  • skills (Skills, optional) – skills, defaults to None

  • -
-
-
Returns:
-

skills with assigned skill level

-
-
Return type:
-

Skills

-
-
-
- -
-
-set_interface(interface: SkillsDataInterface) None¶
-
- -
- -
-
-cochar.skill.calc_skill_points(occupation: str, education: int, power: int, dexterity: int, appearance: int, strength: int) int¶
-

Return skill points based on: -occupation, education, power, dexterity, appearance and strength.

-

Return maximum points for provided occupation.

-
-
Parameters:
-
    -
  • occupation (str) – occupation name

  • -
  • education (int) – education points

  • -
  • power (int) – power points

  • -
  • dexterity (int) – dexterity points

  • -
  • appearance (int) – appearance points

  • -
  • strength (int) – strength points

  • -
-
-
Returns:
-

skill points

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.skill.generate_credit_rating_points(occupation: str, occupation_points: int) int¶
-

For provided occupation, and it occupation points, return -credit rating points.

-
-
Parameters:
-
    -
  • occupation (str) – occupation

  • -
  • occupation_points (int) – occupation points

  • -
-
-
Returns:
-

credit rating points

-
-
Return type:
-

int

-
-
-
- -
-
-cochar.skill.skill_test(tested_value: int, repetition: int = 1) int¶
-

Perform skill test.

-

Works like improvement test. Roll number between 1 to 100, -If that number is higher than tested value or higher, -than 95, then increase tested value with random number, -between 1 to 10.

-

Repeat repetition times.

-
-
Parameters:
-
    -
  • tested_value (int) – tested value

  • -
  • repetition (int) – how many test to perform

  • -
-
-
Returns:
-

unchanged, or increased tested value

-
-
Return type:
-

int

-
-
-
- -
-
-

cochar.utils module¶

-

Utilities for cochar module

-
-
param TRANSLATION_DICT:
-

dictionary with translations for skills

-
-
param AGE_RANGE:
-

tuple[int, int], contains ranges of possible ages.

-
-
param YEAR_RANGE:
-

tuple[int], available years for last names

-
-
-

legend:

-
    -
  • a: art/craft

  • -
  • s: science

  • -
  • f: fighting

  • -
  • g: firearms

  • -
  • i: interpersonal

  • -
  • l: language

  • -
  • *: any

  • -
-
-
-cochar.utils.is_skill_valid(skill_value: int) bool¶
-

Check if skill value is int type and it is not -below 0.

-
-
Parameters:
-

skill_value (int) – skill value to test

-
-
Returns:
-

True if value is valid, else False

-
-
Return type:
-

bool

-
-
-
- -
-
-cochar.utils.narrowed_bisect(a: Sequence[int], x: int) int¶
-

Standard bisect_left from bisect module -can return number that exceed len(a). -narrowed_bisect returns number that is <= len(a).

-

It is to prevent IndexError, as many other variables -relay on the index number returned.

-
-
Parameters:
-
    -
  • a (Sequence) – sequence of numbers

  • -
  • x (int) – number to insert

  • -
-
-
Returns:
-

position of insertion

-
-
Return type:
-

int

-
-
-
- -
-
-

cochar.errors module¶

-

Errors for cochar module

-
-
-exception cochar.error.AgeNotInRange(age: int, min_age: int, max_age: int)¶
-

Bases: CocharError

-

Age must be within specified range, default 15 - 90

-
- -
-
-exception cochar.error.CharacteristicPointsBelowMinValue(skill_name: str, min_value=0)¶
-

Bases: CocharError

-

Characteristic points cannot be below defined minimal value

-
- -
-
-exception cochar.error.CharacteristicValueNotAnInt(skill_name: str, skill_value: Any)¶
-

Bases: CocharError

-

Characteristic value has to be an integer number

-
- -
-
-exception cochar.error.CocharError¶
-

Bases: Exception

-
- -
-
-exception cochar.error.EmptyName¶
-

Bases: CocharError

-

Name cannot be an empty string

-
- -
-
-exception cochar.error.IncorrectOccupation(occupation_name: str)¶
-

Bases: CocharError

-

Raise when occupation is not in OCCUPATIONS_LIST

-
- -
-
-exception cochar.error.InvalidAgeValue(age: int)¶
-

Bases: CocharError

-

Age must be an integer number

-
- -
-
-exception cochar.error.InvalidBuildValue(build: str, correct_build: list)¶
-

Bases: CocharError

-

Raise when occupation is not in occupation list

-
- -
-
-exception cochar.error.InvalidCountryValue(country: str, available_countries: list)¶
-

Bases: CocharError

-

Raise when country is not in available countries

-
- -
-
-exception cochar.error.InvalidDamageBonusValue(damage_bonus: str, correct_damage_bonus: list)¶
-

Bases: CocharError

-

Raise when occupation is not in occupation list

-
- -
-
-exception cochar.error.InvalidOccupationEra(era: str, correct_era: list)¶
-

Bases: CocharError

-

Raise when occupation era is not correct

-
- -
-
-exception cochar.error.InvalidOccupationTags(tags: str, correct_tags: list)¶
-

Bases: CocharError

-

Raise when tag is not among available tags

-
- -
-
-exception cochar.error.InvalidOccupationType(_type: str, correct_type: list)¶
-

Bases: CocharError

-

Raise when occupation type is not correct

-
- -
-
-exception cochar.error.InvalidOccupationValue(occupation: str, available_occupations: list)¶
-

Bases: CocharError

-

Raise when occupation is not in occupation list

-
- -
-
-exception cochar.error.InvalidSexValue(sex: str, available_sex: list)¶
-

Bases: CocharError

-

InvalidSexArgument.

-

Raise when selected sex is not it available for chosen country.

-
- -
-
-exception cochar.error.InvalidYearValue(year: int)¶
-

Bases: CocharError

-

Year must be an integer number

-
- -
-
-exception cochar.error.NoneOccupationMeetsCriteria¶
-

Bases: CocharError

-

Raise when searching criteria are not met by any occupation

-
- -
-
-exception cochar.error.OccupationPointsBelowZero¶
-

Bases: CocharError

-

Raise when provided occupation points are below 0

-
- -
-
-exception cochar.error.SkillPointsBelowZero(skill)¶
-

Bases: CocharError

-

Skill points cannot be below zero

-
- -
-
-exception cochar.error.SkillValueNotAnInt(skill)¶
-

Bases: CocharError

-

Skill value has to be an integer number

-
- -
-
-exception cochar.error.SkillsNotADict(skill)¶
-

Bases: CocharError

-

Skills must be a dictionary

-
- -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html deleted file mode 100644 index 1cba0c6..0000000 --- a/docs/_build/html/genindex.html +++ /dev/null @@ -1,495 +0,0 @@ - - - - - - - - Index — cochar 1.0.1 documentation - - - - - - - - - - - - - - - -
-
-
-
- - -

Index

- -
- A - | B - | C - | D - | E - | F - | G - | H - | I - | L - | M - | N - | O - | P - | S - | V - | Y - -
-

A

- - - -
- -

B

- - - -
- -

C

- - - -
- -

D

- - - -
- -

E

- - - -
- -

F

- - -
- -

G

- - - -
- -

H

- - -
- -

I

- - - -
- -

L

- - - -
- -

M

- - - -
- -

N

- - - -
- -

O

- - - -
- -

P

- - -
- -

S

- - - -
- -

V

- - - -
- -

Y

- - - -
- - - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html deleted file mode 100644 index 8adfdc1..0000000 --- a/docs/_build/html/index.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - - - Welcome to cochar’s documentation! — cochar 1.0.1 documentation - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Welcome to cochar’s documentation!¶

-
-

Contents:

- -
-
-
-

Indices and tables¶

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/objects.inv b/docs/_build/html/objects.inv deleted file mode 100644 index 7d6e71f..0000000 --- a/docs/_build/html/objects.inv +++ /dev/null @@ -1,9 +0,0 @@ -# Sphinx inventory version 2 -# Project: cochar -# Version: -# The remainder of this file is compressed using zlib. -xÚ¥™ÍrÓ0Çïy -3pM®½µi‡É¡C¸xdy“ˆÊ’G’Û†¯Áëñ$¬$Û±C™êãB\[¿ÝõJÚýËPI÷D­ì?„PE{8kdÝq(ÞÔ?Ü›†¿õ7—ïŠå‚ž0«óXŽr¢uña†ýoüê‘pVãÀÌ^Ö!äEÇxåˉÞÖÓ¬{©ñy!Æ(Vuè=Žn[ÀkAsŒTCÂy*EÍ “"ËF'Œ:dX¨Iƒ¹,+):cžñ‡™¬Pd5«Pw”d&tË”6¥ MN ;0å-E¹•ª!&qg¬öÌ”­dÂäL âÀ9ÛAÞbÇšÞч ×)£ù iä#”ª/X‰6$¥]›»ÔZùäË_"¯‰Àý–Ÿ Ï94û™“IýÀ8wÑ·J¶ °€ÄñFØ™}Flé8ӆѴ&æÐÔþy,üáŽ=“èñÒ5Š‹¡O{p‰žoú²ìÒ‰¾ng;;ØãKô{ï7a°CŸèé‹§dœò©D¯ßúMìÐq¾ÜOŒÈî§å¨å¶ nö_ñã1*›Š˜’Îv´Ž·s*Â"itüu9°ƒöŠÃæ%Ž=íç‘ô´Ç¡ÿ4Îp|6Ñ%fÚÄñ -0ârv$ †QÂ}á’DÎÔVDCÖb-Íer~3H°0v¾ù—‡pÜLýsª[Üñ<"Yn|?/ܼ"ùO‘”¯gS}ª‚Î7/r™1~œH -`¥ñMì÷7µ%ÂÍx‘j/£VЇÇàQkÖ¨Îñš‰]‚!@¸Äí ës¶TÜøÓý›º¢ái%Ö€'<öTL ²Ð¦>«%-–³Åpv$ô›ãsÈ„•qv8'p w=²±—‹ã°ÞêdÄWàx>„ÂÈÞþŸ_¿u㺄q;ñÍóò‚«ö°x[×>§Þéäé+ØÝ×›˜Óx©1ªIÌþŽ'Ö÷ûí¶X›}Ç÷]qüšqY/4¶.ºŸ»ö÷¼{ÿüΦò/Éÿ§ \ No newline at end of file diff --git a/docs/_build/html/py-modindex.html b/docs/_build/html/py-modindex.html deleted file mode 100644 index bc368ea..0000000 --- a/docs/_build/html/py-modindex.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - Python Module Index — cochar 1.0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- - -

Python Module Index

- -
- c -
- - - - - - - - - - - - - - - - - - - - - - - - - -
 
- c
- cochar -
    - cochar.character -
    - cochar.cochar -
    - cochar.error -
    - cochar.occup -
    - cochar.skill -
    - cochar.utils -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/readme.html b/docs/_build/html/readme.html deleted file mode 100644 index b64174d..0000000 --- a/docs/_build/html/readme.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - Call Of Cthulhu Character Generator — cochar 1.0.1 documentation - - - - - - - - - - - - - - - - - -
-
-
-
- - -

PyPI version -License: GNU AGPL v3 -Code style: black -Language: Python -Author: Walu

-
-

Call Of Cthulhu Character Generator¶

-

Fast way of creating a random character for Call of Cthulhu RPG 7th ed.

-
-

Summary¶

-

cochar stands for Call of Cthulhu Character. It’s a python package design to create a full characters for Call of Cthulhu RPG 7th ed.

-

www.cochar.pl demonstrates a power of cochar package.

-
-
-

Table of Contents¶

-
    -
  • Project Title

  • -
  • Summary

  • -
  • Table of Contents

  • -
  • Installation

  • -
  • Usage

  • -
  • Dependencies

  • -
  • Documentation

  • -
  • Contribution

  • -
  • Web version

  • -
  • Author

  • -
  • License

  • -
-
-
-

Installation¶

-
pip3 install cochar
-
-
-
-
-

Usage¶

-
-

Basic¶

-

Example:

-
>>> from cochar import create_character
->>> person = create_character(1925, "US")
->>> person
->>> Character(year=1925, country='US', first_name='Anthem', last_name='Pharr', age=22, sex='M', occupation='doctor of medicine', strength=33, condition=30, size=78, dexterity=40, appearance=23, education=87, intelligence=65, power=50, move_rate=7, luck=38, skills={'first aid': 38, 'language [latin]': 9, 'medicine': 73, 'science [biology]': 48, 'ride': 64, 'anthropology': 6, 'charm': 46, 'intimidate': 32, 'art/craft (sculptor)': 9, 'credit rating': 74, 'dodge': 20}, damage_bonus='0', build=0, dodge=20, sanity_points=50, magic_points=10, hit_points=10)
-
-
-
-
-

Default settings¶

-

Default settings are defined in ./data/settings.json.

-
{
-  "min_age": 15,
-  "max_age": 90,
-  "max_skill_level": 90,
-  "year": 1925,
-  "age": null,
-  "sex": null,
-  "first_name": null,
-  "last_name": null,
-  "country": "US",
-  "occupation": null,
-  "weights": true,
-  "database": "",
-  "show_warnings": false,
-  "occupation_type": null,
-  "era": null,
-  "tags": null
-}
-
-
-
-
-
-

Dependencies¶

-

cochar depends on randname module for generating random names.

-

For more details please see:

- -
-
-

Documentation¶

-

Detailed documentation of module can by found here: -cochar documentation

-
-
-

Contribution¶

-

If you want to contribute to cochar project read contribution for more information.

-
-
-

Web Version¶

-
-

Web application is not a part of cochar package.

-
-

Web application was design to present the power of cochar package. You can check it out on www.cochar.pl

-
-
-

Author¶

-

Adam Walkiewicz

-
-
-

License¶

-

Cochar is licensed under the terms of the GNU AGPL v3

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/search.html b/docs/_build/html/search.html deleted file mode 100644 index 736c899..0000000 --- a/docs/_build/html/search.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - Search — cochar 1.0.1 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Search

- - - - -

- Searching for multiple words only shows matches that contain - all words. -

- - -
- - - -
- - - -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js deleted file mode 100644 index 6af495b..0000000 --- a/docs/_build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({"docnames": ["cochar", "index", "readme"], "filenames": ["cochar.rst", "index.rst", "readme.md"], "titles": ["cochar package", "Welcome to cochar\u2019s documentation!", "Call Of Cthulhu Character Generator"], "terms": {"main": 0, "calc_build": [0, 1], "strength": [0, 2], "int": 0, "size": [0, 2], "return": 0, "build": [0, 1, 2], "base": 0, "sum": 0, "od": 0, "f": [0, 1, 2], "x": 0, "y": 0, "64": [0, 2], "84": 0, "124": 0, "164": 0, "204": 0, "283": 0, "364": 0, "444": 0, "524": 0, "2": 0, "1": 0, "0": [0, 2], "3": [0, 2], "4": 0, "5": 0, "6": [0, 2], "todo": 0, "increas": 0, "bonu": 0, "damag": 0, "1k6": 0, "everi": 0, "80": 0, "point": 0, "abov": 0, "paramet": 0, "": [0, 2], "type": 0, "calc_combat_characterist": [0, 1], "dexter": [0, 2], "damage_bonu": [0, 2], "str": 0, "doge": [], "tupl": 0, "combat": 0, "characterist": [0, 1], "dame": 0, "calc_damage_bonu": [0, 1], "1k4": 0, "2k6": 0, "3k6": 0, "4k6": 0, "5k6": 0, "calc_derived_attribut": [0, 1], "power": [0, 2], "condit": [0, 2], "sanity_point": [0, 2], "magic_point": [0, 2], "hit_point": [0, 2], "saniti": 0, "magic": 0, "hit": 0, "option": [0, 2], "default": [0, 1], "calc_dog": [], "calc_hit_point": [0, 1], "valu": 0, "calc_magic_point": [0, 1], "calc_move_r": [0, 1], "move": 0, "rate": [0, 2], "relat": 0, "between": 0, "both": 0, "ar": [0, 2], "smaller": 0, "than": 0, "7": [0, 2], "higher": 0, "equal": 0, "9": [0, 2], "els": 0, "8": 0, "calc_sanity_point": [0, 1], "characteristic_test": [0, 1], "tested_valu": 0, "repetit": 0, "perform": 0, "test": 0, "roll": 0, "number": 0, "100": 0, "If": [0, 2], "i": [0, 2], "random": [0, 2], "10": [0, 2], "repeat": 0, "time": 0, "result": 0, "would": 0, "99": 0, "how": 0, "mani": 0, "unchang": 0, "create_charact": [0, 1, 2], "year": [0, 1, 2], "countri": [0, 1, 2], "first_nam": [0, 2], "none": 0, "last_nam": [0, 2], "ag": [0, 1, 2], "sex": [0, 1, 2], "random_mod": 0, "bool": 0, "fals": [0, 2], "skillsdict": [0, 1], "occup_typ": 0, "era": [0, 2], "tag": [0, 2], "list": 0, "skills_gener": 0, "skillsgener": [0, 1], "object": 0, "function": 0, "creat": [0, 2], "us": [0, 2], "thi": [0, 2], "instead": 0, "instanti": 0, "class": 0, "game": 0, "origin": 0, "first": [0, 2], "name": [0, 1, 2], "last": 0, "choos": 0, "complet": 0, "randomli": 0, "regardless": 0, "statist": 0, "provid": 0, "exist": 0, "rais": 0, "valueerror": 0, "incorrect": 0, "gener": [0, 1], "generate_ag": [0, 1], "generate_base_characterist": [0, 1], "appear": [0, 2], "educ": [0, 2], "intellig": [0, 2], "luck": [0, 2], "move_r": [0, 2], "generate_first_nam": [0, 1], "weight": [0, 2], "given": 0, "data": [0, 2], "set": [0, 1], "avail": 0, "close": 0, "gender": 0, "m": [0, 2], "n": 0, "true": [0, 2], "take": 0, "under": [0, 2], "account": 0, "popular": 0, "generate_last_nam": [0, 1], "generate_sex": [0, 1], "union": 0, "subtract_points_from_characterist": [0, 1], "characteristic_point": 0, "subtract_point": 0, "subtract": 0, "from": [0, 2], "zero": 0, "below": 0, "_description_": 0, "50": [0, 2], "points_to_subtract": 0, "40": [0, 2], "60": 0, "subtract_points_from_str_con_dex": [0, 1], "certain": 0, "amount": 0, "prevent": 0, "each": 0, "lower": 0, "contain": 0, "itself": 0, "min_ag": [0, 2], "max_ag": [0, 2], "valid": [0, 1], "minim": 0, "maxim": 0, "new_ag": 0, "new": 0, "invalidagevalu": [0, 1], "when": 0, "an": 0, "integ": 0, "agenotinrang": [0, 1], "must": 0, "min": 0, "max": 0, "correct_valu": 0, "rang": 0, "siz": 0, "new_build": 0, "invalidbuildvalu": [0, 1], "invalid": 0, "depend": [0, 1], "By": 0, "databas": [0, 2], "extern": 0, "randnam": [0, 2], "taken": 0, "also": 0, "defin": [0, 2], "what": 0, "dataset": 0, "see": [0, 2], "available_countri": 0, "get_json_format": 0, "dict": 0, "full": [0, 2], "dictionari": 0, "male": 0, "femal": 0, "non": 0, "binari": 0, "As": 0, "ani": [0, 2], "select": 0, "drawn": 0, "c": [0, 1, 2], "1925": [0, 2], "u": [0, 2], "properti": 0, "technic": 0, "But": 0, "practic": 0, "besid": 0, "probabl": 0, "popul": 0, "pyramid": 0, "lowest": 0, "highest": 0, "effect": 0, "treat": 0, "same": 0, "That": 0, "mean": 0, "exampl": [0, 2], "end": 0, "2010": 0, "give": 0, "min_valu": 0, "check": [0, 2], "characteristicvaluenotanint": [0, 1], "characteristicpointsbelowzero": 0, "new_countri": 0, "invalidcountryvalu": [0, 1], "damagebonu": [0, 1], "new_damage_bonu": 0, "invaliddamagebonusvalu": [0, 1], "new_nam": 0, "emptynam": [0, 1], "empti": 0, "available_occup": 0, "new_occup": 0, "invalidoccupationvalu": [0, 1], "occupation_list": 0, "new_sex": 0, "invalidsexvalu": [0, 1], "abc": 0, "It": [0, 2], "parent": 0, "all": [0, 1, 2], "other": 0, "descriptor": 0, "method": 0, "need": 0, "implement": 0, "children": 0, "abcmeta": 0, "abstract": 0, "new_year": 0, "invalidyearvalu": [0, 1], "1800": 0, "calc_hobby_point": [0, 1], "hobby_point": 0, "hobbi": 0, "calc_occupation_point": [0, 1], "occupation_point": 0, "calcul": 0, "generate_occup": [0, 1], "ignor": 0, "edu": 0, "pow": 0, "dex": 0, "total": 0, "specifi": 0, "incorrectoccup": [0, 1], "noneoccupationmeetscriteria": [0, 1], "search": [0, 1], "criteria": 0, "met": 0, "get_occupation_list": [0, 1], "which": 0, "kwarg": 0, "userdict": 0, "like": 0, "store": 0, "overrid": 0, "__setitem__": 0, "collect": 0, "interfac": 0, "skillsdatainterfac": 0, "generate_skil": 0, "ha": 0, "chosen": 0, "Then": 0, "assign": 0, "level": 0, "requir": 0, "languag": [0, 2], "own": 0, "set_interfac": 0, "calc_skill_point": [0, 1], "maximum": 0, "generate_credit_rating_point": [0, 1], "For": [0, 2], "credit": [0, 2], "skill_test": [0, 1], "work": 0, "improv": 0, "95": 0, "param": 0, "translation_dict": 0, "translat": 0, "age_rang": 0, "possibl": 0, "year_rang": 0, "legend": 0, "art": [0, 2], "craft": [0, 2], "scienc": [0, 2], "fight": 0, "g": 0, "firearm": 0, "interperson": 0, "l": 0, "is_skill_valid": [0, 1], "skill_valu": 0, "narrowed_bisect": [0, 1], "sequenc": 0, "standard": 0, "bisect_left": 0, "bisect": 0, "can": [0, 2], "exce": 0, "len": 0, "indexerror": 0, "variabl": 0, "relai": 0, "index": [0, 1], "insert": 0, "posit": 0, "except": 0, "cocharerror": [0, 1], "within": 0, "15": [0, 2], "90": [0, 2], "characteristicpointsbelowminvalu": [0, 1], "skill_nam": 0, "cannot": 0, "string": 0, "occupation_nam": 0, "occupations_list": 0, "correct_build": 0, "correct_damage_bonu": 0, "invalidoccupationera": [0, 1], "correct_era": 0, "correct": 0, "invalidoccupationtag": [0, 1], "correct_tag": 0, "among": 0, "invalidoccupationtyp": [0, 1], "_type": 0, "correct_typ": 0, "available_sex": 0, "invalidsexargu": 0, "occupationpointsbelowzero": [0, 1], "skillpointsbelowzero": [0, 1], "skillvaluenotanint": [0, 1], "skillsnotadict": [0, 1], "o": [1, 2], "thulhu": [1, 2], "har": [1, 2], "acter": [1, 2], "summari": 1, "instal": 1, "usag": 1, "basic": 1, "contribut": 1, "web": 1, "version": 1, "author": 1, "licens": 1, "packag": [1, 2], "modul": [1, 2], "charact": 1, "occup": [1, 2], "skill": [1, 2], "util": 1, "error": 1, "page": 1, "cochar": 2, "rpg": 2, "7th": 2, "ed": 2, "copyright": 2, "2023": 2, "adam": 2, "walkiewicz": 2, "program": 2, "free": 2, "softwar": 2, "you": 2, "redistribut": 2, "modifi": 2, "term": 2, "gnu": 2, "affero": 2, "public": 2, "publish": 2, "foundat": 2, "either": 2, "your": 2, "later": 2, "distribut": 2, "hope": 2, "without": 2, "warranti": 2, "even": 2, "impli": 2, "merchant": 2, "fit": 2, "FOR": 2, "A": 2, "particular": 2, "purpos": 2, "more": 2, "detail": 2, "should": 2, "have": 2, "receiv": 2, "copi": 2, "along": 2, "fast": 2, "wai": 2, "stand": 2, "python": 2, "design": 2, "www": 2, "pl": 2, "demonstr": 2, "project": 2, "titl": 2, "pip3": 2, "import": 2, "person": 2, "anthem": 2, "pharr": 2, "22": 2, "doctor": 2, "medicin": 2, "33": 2, "30": 2, "78": 2, "23": 2, "87": 2, "65": 2, "38": 2, "aid": 2, "latin": 2, "73": 2, "biologi": 2, "48": 2, "ride": 2, "anthropologi": 2, "charm": 2, "46": 2, "intimid": 2, "32": 2, "sculptor": 2, "74": 2, "20": 2, "json": 2, "max_skill_level": 2, "null": 2, "show_warn": 2, "occupation_typ": 2, "pleas": 2, "github": 2, "pypi": 2, "found": 2, "here": 2, "want": 2, "read": 2, "inform": 2, "applic": 2, "part": 2, "wa": 2, "present": 2, "out": 2, "agpl": 2, "v3": 2, "dodg": [0, 2], "calc_dodg": [0, 1]}, "objects": {"cochar": [[0, 0, 0, "-", "character"], [0, 0, 0, "-", "cochar"], [0, 0, 0, "-", "error"], [0, 0, 0, "-", "occup"], [0, 0, 0, "-", "skill"], [0, 0, 0, "-", "utils"]], "cochar.character": [[0, 1, 1, "", "Age"], [0, 1, 1, "", "Build"], [0, 1, 1, "", "Character"], [0, 1, 1, "", "Characteristic"], [0, 1, 1, "", "Country"], [0, 1, 1, "", "DamageBonus"], [0, 1, 1, "", "Name"], [0, 1, 1, "", "Occupation"], [0, 1, 1, "", "Sex"], [0, 1, 1, "", "Validator"], [0, 1, 1, "", "Year"]], "cochar.character.Age": [[0, 2, 1, "", "validate"]], "cochar.character.Build": [[0, 2, 1, "", "validate"]], "cochar.character.Character": [[0, 3, 1, "", "age"], [0, 3, 1, "", "appearance"], [0, 3, 1, "", "build"], [0, 3, 1, "", "condition"], [0, 3, 1, "", "country"], [0, 3, 1, "", "damage_bonus"], [0, 3, 1, "", "dexterity"], [0, 3, 1, "", "dodge"], [0, 3, 1, "", "education"], [0, 3, 1, "", "first_name"], [0, 2, 1, "", "get_json_format"], [0, 3, 1, "", "hit_points"], [0, 3, 1, "", "intelligence"], [0, 3, 1, "", "last_name"], [0, 3, 1, "", "luck"], [0, 3, 1, "", "magic_points"], [0, 3, 1, "", "move_rate"], [0, 3, 1, "", "occupation"], [0, 3, 1, "", "power"], [0, 3, 1, "", "sanity_points"], [0, 3, 1, "", "sex"], [0, 3, 1, "", "size"], [0, 4, 1, "", "skills"], [0, 3, 1, "", "strength"], [0, 3, 1, "", "year"]], "cochar.character.Characteristic": [[0, 2, 1, "", "validate"]], "cochar.character.Country": [[0, 2, 1, "", "validate"]], "cochar.character.DamageBonus": [[0, 2, 1, "", "validate"]], "cochar.character.Name": [[0, 2, 1, "", "validate"]], "cochar.character.Occupation": [[0, 2, 1, "", "validate"]], "cochar.character.Sex": [[0, 2, 1, "", "validate"]], "cochar.character.Validator": [[0, 2, 1, "", "validate"]], "cochar.character.Year": [[0, 2, 1, "", "validate"]], "cochar.cochar": [[0, 5, 1, "", "calc_build"], [0, 5, 1, "", "calc_combat_characteristics"], [0, 5, 1, "", "calc_damage_bonus"], [0, 5, 1, "", "calc_derived_attributes"], [0, 5, 1, "", "calc_dodge"], [0, 5, 1, "", "calc_hit_points"], [0, 5, 1, "", "calc_magic_points"], [0, 5, 1, "", "calc_move_rate"], [0, 5, 1, "", "calc_sanity_points"], [0, 5, 1, "", "characteristic_test"], [0, 5, 1, "", "create_character"], [0, 5, 1, "", "generate_age"], [0, 5, 1, "", "generate_base_characteristics"], [0, 5, 1, "", "generate_first_name"], [0, 5, 1, "", "generate_last_name"], [0, 5, 1, "", "generate_sex"], [0, 5, 1, "", "subtract_points_from_characteristic"], [0, 5, 1, "", "subtract_points_from_str_con_dex"]], "cochar.error": [[0, 6, 1, "", "AgeNotInRange"], [0, 6, 1, "", "CharacteristicPointsBelowMinValue"], [0, 6, 1, "", "CharacteristicValueNotAnInt"], [0, 6, 1, "", "CocharError"], [0, 6, 1, "", "EmptyName"], [0, 6, 1, "", "IncorrectOccupation"], [0, 6, 1, "", "InvalidAgeValue"], [0, 6, 1, "", "InvalidBuildValue"], [0, 6, 1, "", "InvalidCountryValue"], [0, 6, 1, "", "InvalidDamageBonusValue"], [0, 6, 1, "", "InvalidOccupationEra"], [0, 6, 1, "", "InvalidOccupationTags"], [0, 6, 1, "", "InvalidOccupationType"], [0, 6, 1, "", "InvalidOccupationValue"], [0, 6, 1, "", "InvalidSexValue"], [0, 6, 1, "", "InvalidYearValue"], [0, 6, 1, "", "NoneOccupationMeetsCriteria"], [0, 6, 1, "", "OccupationPointsBelowZero"], [0, 6, 1, "", "SkillPointsBelowZero"], [0, 6, 1, "", "SkillValueNotAnInt"], [0, 6, 1, "", "SkillsNotADict"]], "cochar.occup": [[0, 5, 1, "", "calc_hobby_points"], [0, 5, 1, "", "calc_occupation_points"], [0, 5, 1, "", "generate_occupation"], [0, 5, 1, "", "get_occupation_list"]], "cochar.skill": [[0, 1, 1, "", "SkillsDict"], [0, 1, 1, "", "SkillsGenerator"], [0, 5, 1, "", "calc_skill_points"], [0, 5, 1, "", "generate_credit_rating_points"], [0, 5, 1, "", "skill_test"]], "cochar.skill.SkillsDict": [[0, 2, 1, "", "get_json_format"]], "cochar.skill.SkillsGenerator": [[0, 2, 1, "", "generate_skills"], [0, 2, 1, "", "set_interface"]], "cochar.utils": [[0, 5, 1, "", "is_skill_valid"], [0, 5, 1, "", "narrowed_bisect"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:attribute", "4": "py:property", "5": "py:function", "6": "py:exception"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "property", "Python property"], "5": ["py", "function", "Python function"], "6": ["py", "exception", "Python exception"]}, "titleterms": {"cochar": [0, 1], "packag": 0, "modul": 0, "charact": [0, 2], "occup": 0, "skill": 0, "util": 0, "error": 0, "welcom": 1, "": 1, "document": [1, 2], "content": [1, 2], "indic": 1, "tabl": [1, 2], "call": 2, "Of": 2, "cthulhu": 2, "gener": 2, "summari": 2, "instal": 2, "usag": 2, "basic": 2, "default": 2, "set": 2, "depend": 2, "contribut": 2, "web": 2, "version": 2, "author": 2, "licens": 2}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx": 57}, "alltitles": {"cochar package": [[0, "cochar-package"]], "cochar.cochar module": [[0, "module-cochar.cochar"]], "cochar.character module": [[0, "module-cochar.character"]], "cochar.occupations module": [[0, "module-cochar.occup"]], "cochar.skills module": [[0, "module-cochar.skill"]], "cochar.utils module": [[0, "module-cochar.utils"]], "cochar.errors module": [[0, "module-cochar.error"]], "Welcome to cochar\u2019s documentation!": [[1, "welcome-to-cochar-s-documentation"]], "Contents:": [[1, null]], "Indices and tables": [[1, "indices-and-tables"]], "Call Of Cthulhu Character Generator": [[2, "call-of-cthulhu-character-generator"]], "Summary": [[2, "summary"]], "Table of Contents": [[2, "table-of-contents"]], "Installation": [[2, "installation"]], "Usage": [[2, "usage"]], "Basic": [[2, "basic"]], "Default settings": [[2, "default-settings"]], "Dependencies": [[2, "dependencies"]], "Documentation": [[2, "documentation"]], "Contribution": [[2, "contribution"]], "Web Version": [[2, "web-version"]], "Author": [[2, "author"]], "License": [[2, "license"]]}, "indexentries": {"age (class in cochar.character)": [[0, "cochar.character.Age"]], "agenotinrange": [[0, "cochar.error.AgeNotInRange"]], "build (class in cochar.character)": [[0, "cochar.character.Build"]], "character (class in cochar.character)": [[0, "cochar.character.Character"]], "characteristic (class in cochar.character)": [[0, "cochar.character.Characteristic"]], "characteristicpointsbelowminvalue": [[0, "cochar.error.CharacteristicPointsBelowMinValue"]], "characteristicvaluenotanint": [[0, "cochar.error.CharacteristicValueNotAnInt"]], "cocharerror": [[0, "cochar.error.CocharError"]], "country (class in cochar.character)": [[0, "cochar.character.Country"]], "damagebonus (class in cochar.character)": [[0, "cochar.character.DamageBonus"]], "emptyname": [[0, "cochar.error.EmptyName"]], "incorrectoccupation": [[0, "cochar.error.IncorrectOccupation"]], "invalidagevalue": [[0, "cochar.error.InvalidAgeValue"]], "invalidbuildvalue": [[0, "cochar.error.InvalidBuildValue"]], "invalidcountryvalue": [[0, "cochar.error.InvalidCountryValue"]], "invaliddamagebonusvalue": [[0, "cochar.error.InvalidDamageBonusValue"]], "invalidoccupationera": [[0, "cochar.error.InvalidOccupationEra"]], "invalidoccupationtags": [[0, "cochar.error.InvalidOccupationTags"]], "invalidoccupationtype": [[0, "cochar.error.InvalidOccupationType"]], "invalidoccupationvalue": [[0, "cochar.error.InvalidOccupationValue"]], "invalidsexvalue": [[0, "cochar.error.InvalidSexValue"]], "invalidyearvalue": [[0, "cochar.error.InvalidYearValue"]], "name (class in cochar.character)": [[0, "cochar.character.Name"]], "noneoccupationmeetscriteria": [[0, "cochar.error.NoneOccupationMeetsCriteria"]], "occupation (class in cochar.character)": [[0, "cochar.character.Occupation"]], "occupationpointsbelowzero": [[0, "cochar.error.OccupationPointsBelowZero"]], "sex (class in cochar.character)": [[0, "cochar.character.Sex"]], "skillpointsbelowzero": [[0, "cochar.error.SkillPointsBelowZero"]], "skillvaluenotanint": [[0, "cochar.error.SkillValueNotAnInt"]], "skillsdict (class in cochar.skill)": [[0, "cochar.skill.SkillsDict"]], "skillsgenerator (class in cochar.skill)": [[0, "cochar.skill.SkillsGenerator"]], "skillsnotadict": [[0, "cochar.error.SkillsNotADict"]], "validator (class in cochar.character)": [[0, "cochar.character.Validator"]], "year (class in cochar.character)": [[0, "cochar.character.Year"]], "age (cochar.character.character attribute)": [[0, "cochar.character.Character.age"]], "appearance (cochar.character.character attribute)": [[0, "cochar.character.Character.appearance"]], "build (cochar.character.character attribute)": [[0, "cochar.character.Character.build"]], "calc_build() (in module cochar.cochar)": [[0, "cochar.cochar.calc_build"]], "calc_combat_characteristics() (in module cochar.cochar)": [[0, "cochar.cochar.calc_combat_characteristics"]], "calc_damage_bonus() (in module cochar.cochar)": [[0, "cochar.cochar.calc_damage_bonus"]], "calc_derived_attributes() (in module cochar.cochar)": [[0, "cochar.cochar.calc_derived_attributes"]], "calc_dodge() (in module cochar.cochar)": [[0, "cochar.cochar.calc_dodge"]], "calc_hit_points() (in module cochar.cochar)": [[0, "cochar.cochar.calc_hit_points"]], "calc_hobby_points() (in module cochar.occup)": [[0, "cochar.occup.calc_hobby_points"]], "calc_magic_points() (in module cochar.cochar)": [[0, "cochar.cochar.calc_magic_points"]], "calc_move_rate() (in module cochar.cochar)": [[0, "cochar.cochar.calc_move_rate"]], "calc_occupation_points() (in module cochar.occup)": [[0, "cochar.occup.calc_occupation_points"]], "calc_sanity_points() (in module cochar.cochar)": [[0, "cochar.cochar.calc_sanity_points"]], "calc_skill_points() (in module cochar.skill)": [[0, "cochar.skill.calc_skill_points"]], "characteristic_test() (in module cochar.cochar)": [[0, "cochar.cochar.characteristic_test"]], "cochar.character": [[0, "module-cochar.character"]], "cochar.cochar": [[0, "module-cochar.cochar"]], "cochar.error": [[0, "module-cochar.error"]], "cochar.occup": [[0, "module-cochar.occup"]], "cochar.skill": [[0, "module-cochar.skill"]], "cochar.utils": [[0, "module-cochar.utils"]], "condition (cochar.character.character attribute)": [[0, "cochar.character.Character.condition"]], "country (cochar.character.character attribute)": [[0, "cochar.character.Character.country"]], "create_character() (in module cochar.cochar)": [[0, "cochar.cochar.create_character"]], "damage_bonus (cochar.character.character attribute)": [[0, "cochar.character.Character.damage_bonus"]], "dexterity (cochar.character.character attribute)": [[0, "cochar.character.Character.dexterity"]], "dodge (cochar.character.character attribute)": [[0, "cochar.character.Character.dodge"]], "education (cochar.character.character attribute)": [[0, "cochar.character.Character.education"]], "first_name (cochar.character.character attribute)": [[0, "cochar.character.Character.first_name"]], "generate_age() (in module cochar.cochar)": [[0, "cochar.cochar.generate_age"]], "generate_base_characteristics() (in module cochar.cochar)": [[0, "cochar.cochar.generate_base_characteristics"]], "generate_credit_rating_points() (in module cochar.skill)": [[0, "cochar.skill.generate_credit_rating_points"]], "generate_first_name() (in module cochar.cochar)": [[0, "cochar.cochar.generate_first_name"]], "generate_last_name() (in module cochar.cochar)": [[0, "cochar.cochar.generate_last_name"]], "generate_occupation() (in module cochar.occup)": [[0, "cochar.occup.generate_occupation"]], "generate_sex() (in module cochar.cochar)": [[0, "cochar.cochar.generate_sex"]], "generate_skills() (cochar.skill.skillsgenerator method)": [[0, "cochar.skill.SkillsGenerator.generate_skills"]], "get_json_format() (cochar.character.character method)": [[0, "cochar.character.Character.get_json_format"]], "get_json_format() (cochar.skill.skillsdict method)": [[0, "cochar.skill.SkillsDict.get_json_format"]], "get_occupation_list() (in module cochar.occup)": [[0, "cochar.occup.get_occupation_list"]], "hit_points (cochar.character.character attribute)": [[0, "cochar.character.Character.hit_points"]], "intelligence (cochar.character.character attribute)": [[0, "cochar.character.Character.intelligence"]], "is_skill_valid() (in module cochar.utils)": [[0, "cochar.utils.is_skill_valid"]], "last_name (cochar.character.character attribute)": [[0, "cochar.character.Character.last_name"]], "luck (cochar.character.character attribute)": [[0, "cochar.character.Character.luck"]], "magic_points (cochar.character.character attribute)": [[0, "cochar.character.Character.magic_points"]], "module": [[0, "module-cochar.character"], [0, "module-cochar.cochar"], [0, "module-cochar.error"], [0, "module-cochar.occup"], [0, "module-cochar.skill"], [0, "module-cochar.utils"]], "move_rate (cochar.character.character attribute)": [[0, "cochar.character.Character.move_rate"]], "narrowed_bisect() (in module cochar.utils)": [[0, "cochar.utils.narrowed_bisect"]], "occupation (cochar.character.character attribute)": [[0, "cochar.character.Character.occupation"]], "power (cochar.character.character attribute)": [[0, "cochar.character.Character.power"]], "sanity_points (cochar.character.character attribute)": [[0, "cochar.character.Character.sanity_points"]], "set_interface() (cochar.skill.skillsgenerator method)": [[0, "cochar.skill.SkillsGenerator.set_interface"]], "sex (cochar.character.character attribute)": [[0, "cochar.character.Character.sex"]], "size (cochar.character.character attribute)": [[0, "cochar.character.Character.size"]], "skill_test() (in module cochar.skill)": [[0, "cochar.skill.skill_test"]], "skills (cochar.character.character property)": [[0, "cochar.character.Character.skills"]], "strength (cochar.character.character attribute)": [[0, "cochar.character.Character.strength"]], "subtract_points_from_characteristic() (in module cochar.cochar)": [[0, "cochar.cochar.subtract_points_from_characteristic"]], "subtract_points_from_str_con_dex() (in module cochar.cochar)": [[0, "cochar.cochar.subtract_points_from_str_con_dex"]], "validate() (cochar.character.age method)": [[0, "cochar.character.Age.validate"]], "validate() (cochar.character.build method)": [[0, "cochar.character.Build.validate"]], "validate() (cochar.character.characteristic method)": [[0, "cochar.character.Characteristic.validate"]], "validate() (cochar.character.country method)": [[0, "cochar.character.Country.validate"]], "validate() (cochar.character.damagebonus method)": [[0, "cochar.character.DamageBonus.validate"]], "validate() (cochar.character.name method)": [[0, "cochar.character.Name.validate"]], "validate() (cochar.character.occupation method)": [[0, "cochar.character.Occupation.validate"]], "validate() (cochar.character.sex method)": [[0, "cochar.character.Sex.validate"]], "validate() (cochar.character.validator method)": [[0, "cochar.character.Validator.validate"]], "validate() (cochar.character.year method)": [[0, "cochar.character.Year.validate"]], "year (cochar.character.character attribute)": [[0, "cochar.character.Character.year"]]}}) \ No newline at end of file diff --git a/docs/cochar.rst b/docs/cochar.rst deleted file mode 100644 index b85425d..0000000 --- a/docs/cochar.rst +++ /dev/null @@ -1,50 +0,0 @@ -cochar package -============== - -cochar.cochar module --------------------- - -.. automodule:: cochar.cochar - :members: - :undoc-members: - :show-inheritance: - -cochar.character module ------------------------ - -.. automodule:: cochar.character - :members: - :undoc-members: - :show-inheritance: - -cochar.occupations module -------------------------- - -.. automodule:: cochar.occup - :members: - :undoc-members: - :show-inheritance: - -cochar.skills module --------------------- - -.. automodule:: cochar.skill - :members: - :undoc-members: - :show-inheritance: - -cochar.utils module -------------------- - -.. automodule:: cochar.utils - :members: - :undoc-members: - :show-inheritance: - -cochar.errors module --------------------- - -.. automodule:: cochar.error - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index db610cc..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,64 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('source')) - - -# -- Project information ----------------------------------------------------- - -project = "cochar" -copyright = "2021, Adam Walkiewicz" -author = "Adam Walkiewicz" - -# The full version, including alpha/beta/rc tags -release = "1.0.1" - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ["sphinx.ext.autodoc", "sphinx.ext.todo", "myst_parser"] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "classic" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -# for to do list? -todo_include_todos = True - -# For other markdown languages -source_suffix = { - ".rst": "restructuredtext", - ".txt": "markdown", - ".md": "markdown", -} diff --git a/CONTRIBUTION.md b/docs/contribution.md similarity index 97% rename from CONTRIBUTION.md rename to docs/contribution.md index 9f4c079..517ea36 100644 --- a/CONTRIBUTION.md +++ b/docs/contribution.md @@ -43,7 +43,8 @@ Pull requests are the best way to propose changes to the codebase (we use [Githu ## What do we need -Look at the [To Do](README#to-do) list in [README](README). +Look at the [issue](https://github.com/ajwalkiewicz/cochar/issues) to see what +do we need now. Right now most important are: diff --git a/docs/documentation.md b/docs/documentation.md new file mode 100644 index 0000000..3616254 --- /dev/null +++ b/docs/documentation.md @@ -0,0 +1,3 @@ +# Project Documentation + +::: src.cochar diff --git a/docs/environment.md b/docs/environment.md new file mode 100644 index 0000000..01c4cbc --- /dev/null +++ b/docs/environment.md @@ -0,0 +1,113 @@ + +# Setting Up the Development Environment + +To contribute to the cochar project, it's important to set up a development +environment that matches the project's requirements. This ensures consistency +and reduces the time spent debugging non-existent bugs. + +## Prerequisites + +Before setting up the environment, ensure you have the following installed: + +- **Python**: The project is built using Python. Make sure you have Python + installed on your machine. The project has to be compatible with **python3.10** +- **Make**: We use Make to simplify various tasks such as setup, testing, + and building the project. +- **Curl**: Required for downloading scripts. +- **Linux** machine: It is not a hard requirement, but all instructions here + are based on **Ubuntu 22.04**. + +## Steps to Set Up the Environment + +1. **Clone the Repository**: + ```sh + git clone https://github.com/ajwalkiewicz/cochar.git + cd cochar + ``` + +2. **Install UV**: + UV is used for project management. If UV is not installed, the setup script will install it for you. + ```sh + make check-uv + ``` + +3. **Set Up the Project**: + Run the setup command to install all necessary dependencies and set up the project. + ```sh + make setup + ``` + +4. **Verify the Setup**: + Ensure that the setup was successful by running the following command: + ```sh + make check + ``` + +## Additional Commands + +- **Build the Project**: + ```sh + make build + ``` + +- **Run Tests**: + ```sh + make test + ``` + +- **Run All Tests**: + ```sh + make test_all + ``` + +- **Clean the Environment**: + ```sh + make clean + ``` + +- **Format the Code**: + ```sh + make format + ``` + +- **Check Typing**: + ```sh + make type + ``` + +- **Serve Documentation Locally**: + ```sh + make docs_serve + ``` + +- **Upload Documentation**: + ```sh + make docs_upload + ``` + +By following these steps, you will have a development environment that is +consistent with the project's requirements. For any issues or further details, +refer to the [Contribution Guidelines](contribution.md). + +## References + +* Python: https://www.python.org/ +* Project management tool: [UV](https://docs.astral.sh/uv/) +* Formatter: [Ruff](https://docs.astral.sh/ruff/) +* Testing: [Pytest](https://docs.pytest.org/en/stable/index.html) \ No newline at end of file diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..afab884 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,138 @@ + + +# Getting Started + +## Installation + +To install the package, use pip: + +```sh +pip install cochar +``` + +## Basic Usage + +The simplest way to create a character is to use the `create_character` function with just the year and country: + +```python +from cochar import create_character + +# Create a random character for 1925 in the United States +character = create_character(1925, "US") +print(character) +``` + +This will generate a complete character with random attributes, skills, occupation, and personal details. + +## Creating a Character with Specific Parameters + +You can customize character creation by providing specific parameters: + +```python +from cochar import create_character + +# Create a character with specific attributes +character = create_character( + year=1925, + country="US", + age=35, + sex="F", + first_name="Sarah", + last_name="Thompson", + occupation="doctor of medicine" +) + +print(f"Name: {character.first_name} {character.last_name}") +print(f"Age: {character.age}, Sex: {character.sex}") +print(f"Occupation: {character.occupation}") +print(f"Skills: {character.skills}") +``` + +## Available Parameters + +The `create_character` function accepts the following parameters: + +- `year` (required): The year in which the game takes place +- `country` (required): The character's country of origin (e.g., "US") +- `first_name`: Character's first name (random if not provided) +- `last_name`: Character's last name (random if not provided) +- `age`: Character's age (random within valid range if not provided) +- `sex`: Character's sex - "M" or "F" (random if not provided) +- `occupation`: Character's occupation (random based on characteristics if not provided) +- `random_mode`: If True, choose occupation completely randomly regardless of statistics +- `occup_type`: Filter occupations by type +- `era`: Filter occupations by era +- `tags`: Filter occupations by tags + +## Accessing Character Attributes + +Once created, you can access various character attributes: + +```python +character = create_character(1925, "US") + +# Personal information +print(f"Name: {character.first_name} {character.last_name}") +print(f"Age: {character.age}, Sex: {character.sex}") +print(f"Occupation: {character.occupation}") + +# Characteristics +print(f"Strength: {character.strength}") +print(f"Dexterity: {character.dexterity}") +print(f"Intelligence: {character.intelligence}") +print(f"Education: {character.education}") + +# Derived attributes +print(f"Hit Points: {character.hit_points}") +print(f"Sanity Points: {character.sanity_points}") +print(f"Magic Points: {character.magic_points}") +print(f"Damage Bonus: {character.damage_bonus}") + +# Skills +print(f"Skills: {character.skills}") +print(f"Dodge: {character.dodge}") +``` + +## Working with Different Time Periods + +You can create characters for different eras by changing the year: + +```python +# 1920s character +character_1920s = create_character(1925, "US") + +# Modern era character +character_modern = create_character(2020, "US") +``` + +## Command Line Usage + +You can also use cochar from the command line: + +```sh +python3 -m cochar +``` + +This will launch an interactive character generation session. + +## Next Steps + +- Check out the [Documentation](documentation.md) for detailed API reference +- See [Contribution](contribution.md) if you'd like to contribute to the project +- Visit the web version at [www.cochar.pl](http://www.cochar.pl) to see cochar in action \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 8016e02..0000000 --- a/docs/index.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index fa56cbd..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. cochar documentation master file, created by - sphinx-quickstart on Wed Jun 23 22:24:25 2021. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to cochar's documentation! -================================== - -.. toctree:: - :maxdepth: 3 - :caption: Contents: - - readme - cochar - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/license.md b/docs/license.md new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/docs/license.md @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 2119f51..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/use-make.md b/docs/use-make.md new file mode 100644 index 0000000..9556080 --- /dev/null +++ b/docs/use-make.md @@ -0,0 +1,92 @@ + +# How-To Guides + +## Using Make in This Project + +This project uses `make` to automate various tasks. Below are the available commands and their descriptions: + +### Setup +To set up the project, run: +```sh +make setup +``` +This will check if `uv` is installed and set up the project environment. + +### Build +To build the project, run: +```sh +make build +``` +This will check the code, run tests, and build the package. + +### Test +To run the tests, use: +```sh +make test +``` +This will run the tests excluding those marked as slow. + +To run all tests, use: +```sh +make test_all +``` + +### Clean +To clean the project, run: +```sh +make clean +``` +This will remove the virtual environment, build files, and cache. + +### Format +To format the project files, run: +```sh +make format +``` +This will format the files using `ruff`. + +### Check +To check the project files, run: +```sh +make check +``` +This will check the files using `ruff`. + +### Type Checking +To check the typing, run: +```sh +make type +``` +This will check the typing using `mypy`. + +### Documentation +To build the documentation, run: +```sh +make docs +``` + +To serve the documentation locally, run: +```sh +make docs_serve +``` + +To upload the documentation, run: +```sh +make docs_upload +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..21fc3e8 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,34 @@ +site_name: COCHAR + +theme: + name: "material" + features: + - content.code.copy + +plugins: + - mkdocstrings: + handlers: + python: + options: + group_by_category: true + show_submodules: true + +markdown_extensions: + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + +nav: + - About Project: README.md + - Getting Started: getting-started.md + - How-To Guides: + - Use make: use-make.md + - Development: + - Contribution: contribution.md + - Setting up environment: environment.md + - Documentation: documentation.md + - License: license.md diff --git a/pyproject.toml b/pyproject.toml index 5f13423..14172ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,8 +43,10 @@ build-backend = "uv_build" [dependency-groups] dev = [ "deepdiff>=8.6.1", + "mkdocs>=1.6.1", + "mkdocs-material>=9.6.23", + "mkdocstrings[python]>=0.30.1", "mypy>=1.18.2", "pytest>=8.4.2", "ruff>=0.14.3", - "sphinx>=8.2.3", ] diff --git a/src/cochar/__init__.py b/src/cochar/__init__.py index bd68fc0..1c98f79 100755 --- a/src/cochar/__init__.py +++ b/src/cochar/__init__.py @@ -13,107 +13,15 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import os -import json -import logging -from pathlib import Path -from typing import Dict, List, Union, Set +"""Cochar - create a random character for Call of Cthulhu RPG 7th ed.""" -import randname +from importlib.metadata import version + +from cochar.cochar import create_character __title__ = "cochar" -__version__ = "1.0.1" +__version__ = version("cochar") __author__ = "Adam Walkiewicz" __license__ = "AGPL v3.0" -DEFAULT_LOGGING_LEVEL = logging.ERROR - -LOGGING_LEVEL_MAP = { - "debug": logging.DEBUG, - "info": logging.INFO, - "warning": logging.WARNING, - "error": logging.ERROR, - "critical": logging.CRITICAL, -} - -logging_level = DEFAULT_LOGGING_LEVEL - -logging.basicConfig( - format="[%(asctime)s][%(levelname)s][%(filename)s:%(funcName)s:%(lineno)d] %(message)s", - level=logging_level, -) - - -def set_logging_level(logging_level=logging_level): - logging_level = LOGGING_LEVEL_MAP.get(logging_level) - return logging.basicConfig( - format="[%(asctime)s][%(levelname)s][%(filename)s:%(funcName)s:%(lineno)d] %(message)s", - level=logging_level, - ) - - -SEX_OPTIONS: Set[Union[str, bool]] = {"M", "m", "F", "f", None} -_THIS_FOLDER = os.path.dirname(os.path.abspath(__file__)) -POP_PYRAMID_PATH = os.path.abspath( - os.path.join(_THIS_FOLDER, "data", "popPyramid.json") -) - -# modification's table for characteristics: -MODIFIERS = { - "age_range": [19, 39, 49, 59, 69, 79, 90], - "mod_char_points": [5, 0, 5, 10, 20, 40, 80], - "mod_app": [0, 0, 5, 10, 15, 20, 25], - "mod_move_rate": [0, 0, 1, 2, 3, 4, 5], - "mod_edu": [0, 1, 2, 3, 4, 4, 4], -} -# Value matrix for setting build -VALUE_MATRIX = { - "combat_range": [64, 84, 124, 164, 204, 283, 364, 444, 524], - "build": [-2, -1, 0, 1, 2, 3, 4, 5, 6], - "damage_bonus": ["-2", "-1", "0", "+1K4", "+1K6", "+2K6", "+3K6", "+4K6", "+5K6"], -} - -with open( - os.path.join(_THIS_FOLDER, "data", "occupations.json"), "r", encoding="utf-8" -) as json_file: - # Full data of occupations - OCCUPATIONS_DATA: Dict[str, dict] = dict(json.load(json_file)) - # OCCUPATIONS_DATA.pop("test") - # Just occupations names in the list - OCCUPATIONS_LIST: List[str] = list(OCCUPATIONS_DATA.keys()) - # Occupations divided on 5 categories depends on skill point calculation method - OCCUPATIONS_GROUPS: List[List[str]] = [ - [key for key, value in OCCUPATIONS_DATA.items() if "edu" in value["groups"]], - [key for key, value in OCCUPATIONS_DATA.items() if "edupow" in value["groups"]], - [key for key, value in OCCUPATIONS_DATA.items() if "edudex" in value["groups"]], - [key for key, value in OCCUPATIONS_DATA.items() if "eduapp" in value["groups"]], - [key for key, value in OCCUPATIONS_DATA.items() if "edustr" in value["groups"]], - ] - -with open( - os.path.join(_THIS_FOLDER, "data", "settings.json"), "r", encoding="utf-8" -) as json_file: - settings: dict = json.load(json_file) - MIN_AGE: int = settings["min_age"] - MAX_AGE: int = settings["max_age"] - MAX_SKILL_LEVEL: int = settings["max_skill_level"] - YEAR: int = settings["year"] - AGE: int = settings["age"] - SEX: str = settings["sex"] - FIRST_NAME: str = settings["first_name"] - LAST_NAME: str = settings["last_name"] - COUNTRY: str = settings["country"] - OCCUPATION: str = settings["occupation"] - WEIGHTS: bool = settings["weights"] - SHOW_WARNINGS: bool = settings["show_warnings"] - OCCUPATION_TYPE: str = settings["occupation_type"] - ERA: str = settings["era"] - TAGS: List[str] = settings["tags"] - - DATABASE: str = settings["database"] - if not DATABASE: - DATABASE = randname.DATABASE - -SKILLS_DATABASE = Path() / _THIS_FOLDER / "data" / "skills.json" - -from cochar.cochar import * +__all__ = ["create_character"] diff --git a/src/cochar/__main__.py b/src/cochar/__main__.py index 8743d76..13f539d 100644 --- a/src/cochar/__main__.py +++ b/src/cochar/__main__.py @@ -14,45 +14,48 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import argparse +from collections.abc import Sequence -from . import cochar +import cochar.cochar as cochar +import cochar.config as config +import cochar.error as error -def pars_arguments(): +def parse_arguments(args: Sequence[str] | None = None) -> argparse.Namespace: parser = argparse.ArgumentParser() parser.add_argument( "--year", type=int, required=False, - default=cochar.YEAR, + default=config.YEAR, help="Character's year of born", ) parser.add_argument( "--first_name", type=str, required=False, - default=cochar.FIRST_NAME, + default=config.FIRST_NAME, help="Character's first name", ) parser.add_argument( "--last_name", type=str, required=False, - default=cochar.LAST_NAME, + default=config.LAST_NAME, help="Character's last name", ) parser.add_argument( "--age", type=int, required=False, - default=cochar.AGE, + default=config.AGE, help="Character's age", ) parser.add_argument( "--sex", type=str, required=False, - default=cochar.SEX, + default=config.SEX, dest="sex", help="Character's sex", ) @@ -60,7 +63,7 @@ def pars_arguments(): "--country", type=str, required=False, - default=cochar.COUNTRY, + default=config.COUNTRY, choices=["US", "PL", "ES"], help="Character's country", ) @@ -68,14 +71,14 @@ def pars_arguments(): "--occupation", type=str, required=False, - default=cochar.OCCUPATION, + default=config.OCCUPATION, help="Character's occupation", ) parser.add_argument( "--occup_type", type=str, required=False, - default=cochar.OCCUPATION_TYPE, + default=config.OCCUPATION_TYPE, choices=["classic", "expansion", "custom"], help="Occupation type", ) @@ -83,7 +86,7 @@ def pars_arguments(): "--era", type=str, required=False, - default=cochar.ERA, + default=config.ERA, choices=["classic-1920", "modern"], help="Occupation era", ) @@ -91,16 +94,16 @@ def pars_arguments(): "--tags", type=str, required=False, - default=cochar.TAGS, + default=config.TAGS, choices=["lovecraftian", "criminal"], help="Occupation tags", ) - return parser.parse_args() + return parser.parse_args(args) def main(): - args = pars_arguments() + args = parse_arguments() if args.tags: tags = [args.tags] else: @@ -120,7 +123,7 @@ def main(): tags=tags, ) ) - except cochar.error.NoneOccupationMeetsCriteria as e: + except error.NoneOccupationMeetsCriteria as e: print(e) diff --git a/src/cochar/character.py b/src/cochar/character.py index 4bbfd41..356ba5e 100644 --- a/src/cochar/character.py +++ b/src/cochar/character.py @@ -13,15 +13,14 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -""""This module contains classes related with Character object itself.""" +""" "This module contains classes related with Character object itself.""" from abc import ABC, abstractmethod -from typing import List, Union +from typing import Any, override import randname -import cochar -import cochar.cochar +import cochar.config import cochar.error import cochar.skill @@ -31,9 +30,6 @@ class Validator(ABC): Defines validate method, that needs to be implemented by all children. - - :param ABC: abstract base class - :type ABC: ABCMeta """ def __set_name__(self, owner, name): @@ -48,23 +44,27 @@ def __set__(self, obj, value): setattr(obj, self.private_name, value) @abstractmethod - def validate(self, value): + def validate(self, value) -> None: pass class Characteristic(Validator): """Base characteristic for character class""" - def __init__(self, min_value=None): + def __init__(self, min_value: int) -> None: self.min_value = min_value - def validate(self, value: int): + @override + def validate(self, value: int) -> None: """Check if characteristic is a valid number and is not below `min_value` - :param value: value to validate - :type value: int - :raises cochar.error.CharacteristicValueNotAnInt: raise if value is not an integer - :raises cochar.error.CharacteristicPointsBelowZero: raise if value is below min_value + Args: + value: value to validate + + + Raises: + cochar.error.CharacteristicValueNotAnInt: raise if value is not an integer + cochar.error.CharacteristicPointsBelowMinValue: raise if value is below min_value """ if not isinstance(value, int): raise cochar.error.CharacteristicValueNotAnInt(self.public_name, value) @@ -79,16 +79,19 @@ def __set__(self, obj, value): self.validate(value) setattr(obj, self.private_name, str(value)) - def validate(self, new_name: str): + @override + def validate(self, value: str) -> None: """Check if name is a valid name. - :param new_name: new character name - :type new_name: str - :raises cochar.error.EmptyName: raise if `new_name` is empty + Args: + value: new character name + + Raises: + cochar.error.EmptyName: raise if `value` is empty """ - if new_name == "": + if value == "": raise cochar.error.EmptyName() - self._first_name = str(new_name) + self._first_name = str(value) class Year(Validator): @@ -107,18 +110,22 @@ class Year(Validator): higher year will give same results as 2010. """ - def validate(self, new_year: int) -> None: + @override + def validate(self, value: int) -> None: """Validate if year is an integer. - :param new_year: new year of the game - :type new_year: int - :raises cochar.error.InvalidYearValue: raise when `new_year` is not an integer + Args: + value: new year of the game + + Raises: + cochar.error.InvalidYearValue: raise when `value` is not an integer - >>> character = create_character() - >>> character.year = 1800 + Examples: + >>> character = create_character() + >>> character.year = 1800 """ - if not isinstance(new_year, int): - raise cochar.error.InvalidYearValue(new_year) + if not isinstance(value, int): + raise cochar.error.InvalidYearValue(value) class Sex(Validator): @@ -132,75 +139,90 @@ class Sex(Validator): As there are not any data for non binary names. When ``None`` is selected sex will be randomly drawn from M or F - >>> c = Character(year=1925, country="US", sex="F") - >>> c.sex - 'F' + Examples: + >>> c = Character(year=1925, country="US", sex="F") + >>> c.sex + 'F' """ - def validate(self, new_sex: Union[str, None]) -> None: + @override + def validate(self, value: str | None) -> None: """ Validate character's sex. - :param new_sex: character's new sex - :type new_sex: str | None - :raises InvalidSexValue: Incorrect sex value: sex -> ['M', 'F', None'] + Args: + value: character's new sex + + Raises: + cochar.error.InvalidSexValue: Incorrect sex value: sex -> ['M', 'F', None] """ - if new_sex not in cochar.SEX_OPTIONS: - raise cochar.error.InvalidSexValue(new_sex, cochar.SEX_OPTIONS) + if value not in cochar.config.SEX_OPTIONS: + raise cochar.error.InvalidSexValue(value, cochar.config.SEX_OPTIONS) class Age(Validator): """Character's age. - :param min_age: minimal character's age - :type min_age: int - :param max_age: maximal character's age - :type max_age: int + Warning: + Age must be between `min_age` and `max_age` defined during + descriptor initialization. """ def __init__(self, min_age: int, max_age: int) -> None: + """Initialize age descriptor. + + Args: + min_age: minimal character's age + max_age: maximal character's age + """ self.min_age = min_age self.max_age = max_age - def validate(self, new_age: int) -> None: + @override + def validate(self, value: int) -> None: """ Validate character's age. - :param new_age: character's new age - :type new_age: int - :raises InvalidAgeValue: raise when age is not an integer - :raises AgeNotInRange: age must be between min and max age + Args: + value: character's new age + + Raises: + cochar.error.InvalidAgeValue: raise when age is not an integer + cochar.error.AgeNotInRange: age must be between min and max age """ - if not isinstance(new_age, int): - raise cochar.error.InvalidAgeValue(new_age) + if not isinstance(value, int): + raise cochar.error.InvalidAgeValue(value) - if not self.min_age <= new_age <= self.max_age: - raise cochar.error.AgeNotInRange(new_age, self.min_age, self.max_age) + if not self.min_age <= value <= self.max_age: + raise cochar.error.AgeNotInRange(value, self.min_age, self.max_age) class Country(Validator): """Character's country. Country depends on available data. By default database from - external ``randname`` package is taken. + external `randname` package is taken. Country also defines what dataset will be used for generating character's name. - See ``randname.available_countries()``. + See `randname.available_countries()`. """ - def validate(self, new_country: str) -> None: + @override + def validate(self, value: str) -> None: """ Validate character's country. - :param new_country: character's new country - :type new_country: str - :raises InvalidCountryValue: "Country not available: {new_country} -> {randname.available_countries()} + Args: + value: character's new country + + Raises: + cochar.error.InvalidCountryValue: "Country not available: {value} -> {randname.available_countries()} """ available_countries = randname.available_countries() - if new_country not in available_countries: - raise cochar.error.InvalidCountryValue(new_country, available_countries) + if value not in available_countries: + raise cochar.error.InvalidCountryValue(value, available_countries) class Occupation(Validator): @@ -212,18 +234,19 @@ class Occupation(Validator): def __init__(self, available_occupations): self.available_occupations = available_occupations - def validate(self, new_occupation: str) -> None: + @override + def validate(self, value: str) -> None: """ Validate character's occupation. - :param new_occupation: character's new occupation - :type new_occupation: str - :raises InvalidOccupationValue: raise when `new_occupation` is not in `OCCUPATION_LIST` + Args: + value: character's new occupation + + Raises: + cochar.error.InvalidOccupationValue: raise when `value` is not in `OCCUPATION_LIST` """ - if new_occupation not in self.available_occupations: - raise cochar.error.InvalidOccupationValue( - new_occupation, self.available_occupations - ) + if value not in self.available_occupations: + raise cochar.error.InvalidOccupationValue(value, self.available_occupations) class DamageBonus(Validator): @@ -233,13 +256,16 @@ class DamageBonus(Validator): """ - def validate(self, new_damage_bonus: str) -> None: + @override + def validate(self, value: str) -> None: """ Validate character's damage bonus. - :param new_damage_bonus: character's new damage bonus - :type new_damage_bonus: str - :raises InvalidDamageBonusValue: Invalid damage bonus. {new_damage_bonus} not in {correct_values} + Args: + value: character's new damage bonus + + Raises: + cochar.error.InvalidDamageBonusValue: Invalid damage bonus. {value} not in {correct_values} """ # TODO: Increase range. +1 for each 80 point above STR+SIZ correct_values = [ @@ -253,7 +279,7 @@ def validate(self, new_damage_bonus: str) -> None: "+4K6", "+5K6", ] - new_damage_bonus = str(new_damage_bonus).upper() + new_damage_bonus = str(value).upper() if new_damage_bonus not in correct_values: raise cochar.error.InvalidDamageBonusValue(new_damage_bonus, correct_values) @@ -261,33 +287,38 @@ def validate(self, new_damage_bonus: str) -> None: class Build(Validator): """Character's build. - ``correct_values = [-2, -1, 0, 1, 2, 3, 4, 5, 6]`` + Warning: + `correct_values = [-2, -1, 0, 1, 2, 3, 4, 5, 6]` TODO: increase range. +1 for each 80 point above STR+SIZ. """ - def validate(self, new_build: int) -> None: + @override + def validate(self, value: int) -> None: """ Validate character's build. - :param new_build: character's new build - :type new_build: int - :raises InvalidBuildValue: Invalid build. {new_build} not in {correct_values} + Args: + value: character's new build + + Raises: + cochar.error.InvalidBuildValue: Invalid build. {value} not in {correct_values} """ correct_values = [-2, -1, 0, 1, 2, 3, 4, 5, 6] - if new_build not in correct_values: - raise cochar.error.InvalidBuildValue(new_build, correct_values) + if value not in correct_values: + raise cochar.error.InvalidBuildValue(value, correct_values) class Character: """Container for character. - .. warning: + Warning: Although this class can be used as standalone class, it is advised to use `cochar.create_character()` function to generate character. """ + # Characteristics descriptors strength = Characteristic(min_value=0) condition = Characteristic(min_value=0) size = Characteristic(min_value=0) @@ -304,14 +335,16 @@ class Character: hit_points = Characteristic(min_value=0) dodge = Characteristic(min_value=0) + # Name descriptors first_name = Name() last_name = Name() + # Other descriptors year = Year() sex = Sex() - age = Age(min_age=cochar.MIN_AGE, max_age=cochar.MAX_AGE) + age = Age(min_age=cochar.config.MIN_AGE, max_age=cochar.config.MAX_AGE) country = Country() - occupation = Occupation(available_occupations=cochar.OCCUPATIONS_LIST) + occupation = Occupation(available_occupations=cochar.config.OCCUPATIONS_LIST) damage_bonus = DamageBonus() build = Build() @@ -334,10 +367,10 @@ def __init__( power: int = 0, luck: int = 0, move_rate: int = 0, - damage_bonus: str = 0, + damage_bonus: str = "0", build: int = 0, dodge: int = 0, - skills: cochar.skill.SkillsDict = {}, + skills: cochar.skill.SkillsDict | None = None, sanity_points: int = 0, magic_points: int = 0, hit_points: int = 0, @@ -361,7 +394,12 @@ def __init__( self.luck = luck self.damage_bonus = damage_bonus self.build = build - self.skills = cochar.skill.SkillsDict(skills) + + if skills is None: + self.skills = cochar.skill.SkillsDict() + else: + self.skills = skills + self.dodge = dodge self.sanity_points = sanity_points self.magic_points = magic_points @@ -371,13 +409,13 @@ def __init__( def skills(self) -> cochar.skill.SkillsDict: """Character's skills. - :return: character's skills - :rtype: cochar.skill.Skills + Returns: + character's skills """ return self._skills @skills.setter - def skills(self, new_skills: Union[dict, cochar.skill.SkillsDict]) -> None: + def skills(self, new_skills: dict | cochar.skill.SkillsDict) -> None: if isinstance(new_skills, cochar.skill.SkillsDict): self._skills = new_skills elif isinstance(new_skills, dict): @@ -385,11 +423,10 @@ def skills(self, new_skills: Union[dict, cochar.skill.SkillsDict]) -> None: else: raise cochar.error.SkillsNotADict("Invalid skills. Skills must be a dict") - def get_json_format(self) -> dict: + def get_json_format(self) -> dict[str, Any]: """Return character's full characteristics as a dictionary. :return: full characteristics - :rtype: dict """ result = {str(key)[1:]: value for key, value in vars(self).items()} result.update({"skills": self.skills.get_json_format()}) @@ -400,15 +437,15 @@ def __eq__(self, o: object) -> bool: def __repr__(self) -> str: return ( - f"Character(year={self._year}, country='{self._country}', " - f"first_name='{self._first_name}', last_name='{self._last_name}', " - f"age={self._age}, sex='{self._sex}', occupation='{self._occupation}', " - f"strength={self._strength}, condition={self._condition}, size={self._size}, " - f"dexterity={self._dexterity}, appearance={self._appearance}, education={self._education}, " - f"intelligence={self._intelligence}, power={self._power}, move_rate={self._move_rate}, " - f"luck={self._luck}, skills={self._skills}, damage_bonus='{self._damage_bonus}', " - f"build={self._build}, dodge={self._dodge}, sanity_points={self._sanity_points}, " - f"magic_points={self._magic_points}, hit_points={self._hit_points})" + f"Character(year={self.year}, country='{self.country}', " + f"first_name='{self.first_name}', last_name='{self.last_name}', " + f"age={self.age}, sex='{self.sex}', occupation='{self.occupation}', " + f"strength={self.strength}, condition={self.condition}, size={self.size}, " + f"dexterity={self.dexterity}, appearance={self.appearance}, education={self.education}, " + f"intelligence={self.intelligence}, power={self.power}, move_rate={self.move_rate}, " + f"luck={self.luck}, skills={self.skills}, damage_bonus='{self.damage_bonus}', " + f"build={self.build}, dodge={self.dodge}, sanity_points={self.sanity_points}, " + f"magic_points={self.magic_points}, hit_points={self.hit_points})" ) def __str__(self) -> str: @@ -425,16 +462,16 @@ def __str__(self) -> str: return ( f"Character\n" - f"Name: {self._first_name} {self._last_name}\n" - f"Sex: {self._sex}, Age: {self._age}, Country: {self._country}\n" - f"Occupation: {self._occupation.capitalize()}\n" - f"STR: {self._strength} CON: {self._condition} SIZ: {self._size}\n" - f"DEX: {self._dexterity} APP: {self._appearance} EDU: {self._education}\n" - f"INT: {self._intelligence} POW: {self._power} Luck: {self._luck}\n" - f"Damage bonus: {self._damage_bonus}\n" - f"Build: {self._build}\n" - f"Dodge: {self._dodge}\n" - f"Move rate: {self._move_rate}\n" + f"Name: {self.first_name} {self.last_name}\n" + f"Sex: {self.sex}, Age: {self.age}, Country: {self.country}\n" + f"Occupation: {self.occupation.capitalize()}\n" + f"STR: {self.strength} CON: {self.condition} SIZ: {self.size}\n" + f"DEX: {self.dexterity} APP: {self.appearance} EDU: {self.education}\n" + f"INT: {self.intelligence} POW: {self.power} Luck: {self.luck}\n" + f"Damage bonus: {self.damage_bonus}\n" + f"Build: {self.build}\n" + f"Dodge: {self.dodge}\n" + f"Move rate: {self.move_rate}\n" f"Skills:\n" f"{skills}" ) diff --git a/src/cochar/cochar.py b/src/cochar/cochar.py index edd8b55..d822915 100644 --- a/src/cochar/cochar.py +++ b/src/cochar/cochar.py @@ -14,24 +14,24 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """**Cochar - main module**""" + import json import random -from typing import List, Tuple, Union import randname -import cochar import cochar.character +import cochar.config +import cochar.error +import cochar.interface import cochar.occup import cochar.skill import cochar.utils -import cochar.error -import cochar.interface -cochar.set_logging_level("debug") +cochar.config.set_logging_level("debug") SKILLS_INTERFACE = cochar.interface.SkillsJSONInterface( - cochar.SKILLS_DATABASE, cochar.ERA + cochar.config.SKILLS_DATABASE, cochar.config.ERA ) SKILLS_GENERATOR = cochar.skill.SkillsGenerator(SKILLS_INTERFACE) @@ -39,50 +39,47 @@ def create_character( year: int, country: str, - first_name: str = cochar.FIRST_NAME, - last_name: str = cochar.LAST_NAME, - age: int = cochar.AGE, - sex: str = cochar.SEX, + first_name: str = cochar.config.FIRST_NAME, + last_name: str = cochar.config.LAST_NAME, + age: int = cochar.config.AGE, + sex: str = cochar.config.SEX, random_mode: bool = False, - occupation: str = cochar.OCCUPATION, - skills: cochar.skill.SkillsDict = {}, - occup_type: str = cochar.OCCUPATION_TYPE, - era: str = cochar.ERA, - tags: List[str] = cochar.TAGS, + occupation: str = cochar.config.OCCUPATION, + skills: cochar.skill.SkillsDict | None = None, + occup_type: str = cochar.config.OCCUPATION_TYPE, + era: str = cochar.config.ERA, + tags: list[str] = cochar.config.TAGS, skills_generator: cochar.skill.SkillsGenerator = SKILLS_GENERATOR, ) -> cochar.character.Character: """Main function for creating Character. Use this function instead of instantiating Character class. - :param year: year of the game - :type year: int - :param country: country of character's origin - :type country: str - :param first_name: character's first name, defaults to "" - :type first_name: str, optional - :param last_name: character's last name, defaults to "" - :type last_name: str, optional - :param age: character's age, defaults to False - :type age: int, optional - :param sex: character's sex, defaults to False - :type sex: str, optional - :param random_mode: choose occupation completely randomly, regardless the character's statistics, defaults to "False" - :type random_mode: bool, optional - :param occupation: character's occupation return provided occupation as character's occupation if it exists, defaults to "None" - :type occupation: str, optional - :param skills: character's skills, defaults to {} - :type skills: Skills, optional - :param occup_type: occupation type, defaults to None - :type occup_type: str, optional - :param era: occupation era, defaults to None - :type era: str, optional - :param tags: occupation tags, defaults to None - :type tags: List[str], optional - :raises ValueError: raise if sex is incorrect - :return: generated character - :rtype: Character + Args: + year: year of the game + country: country of character's origin + first_name: character's first name, defaults to "" + last_name: character's last name, defaults to "" + age: character's age, defaults to False + sex: character's sex, defaults to False + random_mode: choose occupation completely randomly, regardless the character's statistics, defaults to "False" + occupation: character's occupation return provided occupation as character's occupation if it exists, defaults to "None" + skills: character's skills, defaults to {} + occup_type: occupation type, defaults to None + era: occupation era, defaults to None + tags: occupation tags, defaults to None + + Raises: + cochar.error.InvalidYearValue: raise if year is incorrect + cochar.error.InvalidCountryValue: raise if country is incorrect + cochar.error.InvalidOccupationValue: raise if occupation is incorrect + cochar.error.InvalidOccupationTypeValue: raise if occupation type is incorrect + cochar.error.InvalidEraValue: raise if era is incorrect + cochar.error.InvalidTagsValue: raise if tags are incorrect + + Returns: + Generated character. """ - weights = cochar.WEIGHTS + weights = cochar.config.WEIGHTS sex = generate_sex(sex) @@ -131,6 +128,9 @@ def create_character( ) hobby_points = cochar.occup.calc_hobby_points(intelligence) + if skills is None: + skills = cochar.skill.SkillsDict() + skills = skills_generator.generate_skills( occupation, occupation_points, hobby_points, dexterity, education, skills ) @@ -169,14 +169,13 @@ def generate_age(year: int, sex: str, age: int = False) -> int: """Generate characters age, based on year and sex. Return age if age is provided. - :param year: year of the game - :type year: int - :param sex: character's sex - :type sex: str - :param age: character's age, defaults to False - :type age: int, optional - :return: character's age - :rtype: int + Args: + year: year of the game + sex: character's sex + age: character's age, defaults to False + + Returns: + Character's age """ if not isinstance(year, int): raise cochar.error.InvalidYearValue(year) @@ -192,15 +191,15 @@ def generate_age(year: int, sex: str, age: int = False) -> int: file_name = f"pop{corrected_year}" - with open(cochar.POP_PYRAMID_PATH, "r", encoding="utf-8") as json_file: + with open(cochar.config.POP_PYRAMID_PATH, "r", encoding="utf-8") as json_file: - def correct_age_range(age_range: Tuple[int, int], max_age: int): + def correct_age_range(age_range: tuple[tuple[int, int], ...], max_age: int): for i, elem in enumerate(age_range): if elem[1] > max_age: return i return len(age_range) + 1 - max_age_index = correct_age_range(cochar.utils.AGE_RANGE, cochar.MAX_AGE) + max_age_index = correct_age_range(cochar.utils.AGE_RANGE, cochar.config.MAX_AGE) age_population = cochar.utils.AGE_RANGE[:max_age_index] age_weights = json.load(json_file)[file_name][sex][3 : 3 + max_age_index] @@ -212,7 +211,7 @@ def correct_age_range(age_range: Tuple[int, int], max_age: int): def generate_base_characteristics( - age, + age: int, strength: int = 0, condition: int = 0, size: int = 0, @@ -238,30 +237,21 @@ def generate_base_characteristics( 9. luck 10. move rate - :param age: character's age - :type age: int - :param strength: strength, defaults to 0 - :type strength: int, optional - :param condition: condition, defaults to 0 - :type condition: int, optional - :param size: size, defaults to 0 - :type size: int, optional - :param dexterity: dexterity, defaults to 0 - :type dexterity: int, optional - :param appearance: appearance, defaults to 0 - :type appearance: int, optional - :param education: education, defaults to 0 - :type education: int, optional - :param intelligence: intelligence, defaults to 0 - :type intelligence: int, optional - :param power: power, defaults to 0 - :type power: int, optional - :param move_rate: move rate, defaults to 0 - :type move_rate: int, optional - :param luck: luck, defaults to 0 - :type luck: int, optional - :return: (strength, condition, size, dexterity, appearance, education, intelligence, power, luck, move_rate) - :rtype: tuple + Args: + age: character's age + strength: strength, defaults to 0 + condition: condition, defaults to 0 + size: size, defaults to 0 + dexterity: dexterity, defaults to 0 + appearance: appearance, defaults to 0 + education: education, defaults to 0 + intelligence: intelligence, defaults to 0 + power: power, defaults to 0 + move_rate: move rate, defaults to 0 + luck: luck, defaults to 0 + + Returns: + (strength, condition, size, dexterity, appearance, education, intelligence, power, luck, move_rate) """ if strength == 0: strength = random.randint(15, 90) @@ -286,11 +276,11 @@ def generate_base_characteristics( if age <= 19: luck = max(luck, random.randint(15, 90)) - age_range = cochar.utils.narrowed_bisect(cochar.MODIFIERS["age_range"], age) - mod_char_points = cochar.MODIFIERS["mod_char_points"][age_range] - mod_app = cochar.MODIFIERS["mod_app"][age_range] - mod_move_rate = cochar.MODIFIERS["mod_move_rate"][age_range] - mod_edu = cochar.MODIFIERS["mod_edu"][age_range] + age_range = cochar.utils.narrowed_bisect(cochar.config.MODIFIERS["age_range"], age) + mod_char_points = cochar.config.MODIFIERS["mod_char_points"][age_range] + mod_app = cochar.config.MODIFIERS["mod_app"][age_range] + mod_move_rate = cochar.config.MODIFIERS["mod_move_rate"][age_range] + mod_edu = cochar.config.MODIFIERS["mod_edu"][age_range] appearance = subtract_points_from_characteristic(appearance, mod_app) strength, condition, dexterity = subtract_points_from_str_con_dex( @@ -320,24 +310,20 @@ def calc_derived_attributes( sanity_points: int = 0, magic_points: int = 0, hit_points: int = 0, -) -> Tuple[int, int, int]: +) -> tuple[int, int, int]: """Based on power, size and condition, return sanity, magic and hit points - :param power: power points - :type power: int - :param size: size points - :type size: int - :param condition: condition points - :type condition: int - :param sanity_points: sanity points, defaults to 0 - :type sanity_points: int, optional - :param magic_points: magic points, defaults to 0 - :type magic_points: int, optional - :param hit_points: hit points, defaults to 0 - :type hit_points: int, optional - :return: (sanity points, magic points, hit points) - :rtype: tuple + Args: + power: power points + size: size points + condition: condition points + sanity_points: sanity points, defaults to 0 + magic_points: magic points, defaults to 0 + hit_points: hit points, defaults to 0 + + Returns: + (sanity points, magic points, hit points) """ if sanity_points == 0: sanity_points = calc_sanity_points(power) @@ -352,10 +338,11 @@ def calc_derived_attributes( def calc_sanity_points(power: int) -> int: """Return sanity points based on power - :param power: power value - :type power: int - :return: sanity points - :rtype: int + Args: + power: power value + + Returns: + sanity points """ return power @@ -363,10 +350,11 @@ def calc_sanity_points(power: int) -> int: def calc_magic_points(power: int) -> int: """Return magic points based on power - :param power: power value - :type power: int - :return: magic points - :rtype: int + Args: + power: power value + + Returns: + magic points """ return power // 5 @@ -375,11 +363,8 @@ def calc_hit_points(size: int, condition: int) -> int: """Return hit points based on size and condition. :param size: size value - :type size: int :param condition: condition value - :type condition: int :return: hit points - :rtype: int """ return (size + condition) // 10 @@ -391,19 +376,18 @@ def calc_combat_characteristics( damage_bonus: str = "", build: int = 0, dodge: int = 0, -) -> Tuple[str, int, int]: +) -> tuple[str, int, int]: """Based on strength, size and dexterity, return combat characteristics such as: dame bonus, build, dodge - :param strength: strength points - :type strength: int - :param size: size points - :type size: int - :param dexterity: dexterity points - :type dexterity: int - :return: (damage bonus, build, dodge) - :rtype: Tuple(str, int, int) + Args: + strength: strength points + size: size points + dexterity: dexterity points + + Returns: + (damage bonus, build, dodge) """ if damage_bonus == "": damage_bonus = calc_damage_bonus(strength, size) @@ -418,25 +402,27 @@ def calc_combat_characteristics( def calc_damage_bonus(strength: int, size: int) -> str: """Return damage bonus, based on sum of strength and size. + ``` f: X -> Y X: {64, 84, 124, 164, 204, 283, 364, 444, 524} Y: {"-2", "-1", "0", "+1K4", "+1K6", "+2K6", "+3K6", "+4K6", "+5K6",} + ``` TODO: Increase bonus damage for +1K6 for every 80 points above 524 - :param strength: character's strength - :type strength: int - :param size: character's size - :type size: int - :return: character's damage bonus - :rtype: str + Args: + strength: character's strength + size: character's size + + Returns: + character's damage bonus """ sum_str_siz = strength + size combat_range = cochar.utils.narrowed_bisect( - cochar.VALUE_MATRIX["combat_range"], sum_str_siz + cochar.config.VALUE_MATRIX["combat_range"], sum_str_siz ) - damage_bonus = cochar.VALUE_MATRIX["damage_bonus"][combat_range] + damage_bonus = cochar.config.VALUE_MATRIX["damage_bonus"][combat_range] return damage_bonus @@ -450,18 +436,18 @@ def calc_build(strength: int, size: int) -> int: TODO: Increase bonus damage for +1K6 for every 80 points above 524 - :param strength: character's strength - :type strength: int - :param size: character's size - :type size: int - :return: character's build - :rtype: int + Args: + strength: character's strength + size: character's size + + Returns: + character's build """ sum_str_siz = strength + size combat_range = cochar.utils.narrowed_bisect( - cochar.VALUE_MATRIX["combat_range"], sum_str_siz + cochar.config.VALUE_MATRIX["combat_range"], sum_str_siz ) - build = cochar.VALUE_MATRIX["build"][combat_range] + build = cochar.config.VALUE_MATRIX["build"][combat_range] return build @@ -470,10 +456,11 @@ def calc_dodge(dexterity: int) -> int: dodge = dexterity // 2 - :param dexterity: character's dexterity - :type dexterity: int - :return: character's dodge - :rtype: int + Args: + dexterity: character's dexterity + + Returns: + character's dodge """ return dexterity // 2 @@ -484,20 +471,21 @@ def subtract_points_from_characteristic( """Subtract points from characteristic points, but if result would be zero or below, than return 1. - :param characteristic_points: _description_ - :type characteristic_points: int - :param subtract_points: _description_ - :type subtract_points: int - :return: _description_ - :rtype: int - - >>> education = 50 - >>> points_to_subtract = 10 - >>> subtract_points_from_characteristic(education, points_to_subtract) - 40 - >>> points_to_subtract = 60 - >>> subtract_points_from_characteristic(education, points_to_subtract) - 1 + Args: + characteristic_points: _description_ + subtract_points: _description_ + + Returns: + characteristic points after subtraction + + Examples: + >>> education = 50 + >>> points_to_subtract = 10 + >>> subtract_points_from_characteristic(education, points_to_subtract) + 40 + >>> points_to_subtract = 60 + >>> subtract_points_from_characteristic(education, points_to_subtract) + 1 """ return ( characteristic_points - subtract_points @@ -508,21 +496,19 @@ def subtract_points_from_characteristic( def subtract_points_from_str_con_dex( strength: int, condition: int, dexterity: int, subtract_points: int -) -> Tuple[int, int, int]: +) -> tuple[int, int, int]: """Subtract certain amount of points from strength, condition and dexterity, but prevent each of the characteristics to be lower than 1. - :param strength: character's strength - :type strength: int - :param condition: character's condition - :type condition: int - :param dexterity: character's dexterity - :type dexterity: int - :param subtract_points: amount of points to subtract - :type subtract_points: int - :return: (strength, condition, dexterity) - :rtype: Tuple[int, int, int] + Args: + strength: character's strength + condition: character's condition + dexterity: character's dexterity + subtract_points: amount of points to subtract + + Returns: + (strength, condition, dexterity) """ characteristics = { "strength": strength, @@ -557,15 +543,15 @@ def characteristic_test(tested_value: int, repetition: int = 1) -> int: Repeat `repetition` times. If result would be higher than 99, return 99 - .. note: + Notes: for skills use skill_test() - :param tested_value: tested value - :type tested_value: int - :param repetition: how many test to perform - :type repetition: int - :return: unchanged or increased tested value, but not higher than 99 - :rtype: int + Args: + tested_value: tested value + repetition: how many test to perform + + Returns: + Unchanged or increased tested value, but not higher than 99. """ for _ in range(repetition): test = random.randint(1, 100) @@ -584,14 +570,14 @@ def calc_move_rate(strength: int, dexterity: int, size: int) -> int: return 9 else return 8 - :param strength: character's strength - :type strength: int - :param dexterity: characters dexterity - :type dexterity: int - :param size: character's size - :type size: int - :return: move rate - :rtype: int + Args: + strength: character's strength + dexterity: characters dexterity + size: character's size + + + Returns: + character's move rate """ if dexterity < size and strength < size: move_rate = 7 @@ -607,19 +593,17 @@ def calc_move_rate(strength: int, dexterity: int, size: int) -> int: def generate_last_name(year: int, sex: str, country: str, weights: bool) -> str: """Return random last name based on the given parameters - .. note: + Notes: For generating only last name, use randname module. - :param year: year of the data set with names (if data set not available use a closes available data set) - :type year: int - :param sex: name gender, available options ['M', 'F', 'N', None] - :type sex: str - :param country: name country - :type country: str - :param weights: If true, take under account popularity of names. [default: True] - :type weights: bool - :return: last name - :rtype: str + Args: + year: year of the data set with names (if data set not available use a closes available data set) + sex: name gender, available options ['M', 'F', 'N', None] + country: name country + weights: If true, take under account popularity of names. [default: True] + + Returns: + last name """ sex = _verify_and_return_sex(sex, country, name="last_names") return randname.last_name( @@ -627,8 +611,8 @@ def generate_last_name(year: int, sex: str, country: str, weights: bool) -> str: sex, country, weights, - database=cochar.DATABASE, - show_warnings=cochar.SHOW_WARNINGS, + database=cochar.config.DATABASE, + show_warnings=cochar.config.SHOW_WARNINGS, ) @@ -636,19 +620,17 @@ def generate_last_name(year: int, sex: str, country: str, weights: bool) -> str: def generate_first_name(year: int, sex: str, country: str, weights: bool) -> str: """Return random first name based on given parameters. - .. note: + Notes: For generating only first name, use randname module. - :param year: year of the data set with names (if data set not available use a closes available data set) - :type year: int - :param sex: name gender, available options ['M', 'F', 'N', None] - :type sex: str - :param country: name country - :type country: str - :param weights: if true, take under account popularity of names. [default: True] - :type weights: bool - :return: first name - :rtype: str + Args: + year: year of the data set with names (if data set not available use a closes available data set) + sex: name gender, available options ['M', 'F', 'N', None] + country: name country + weights: if true, take under account popularity of names. [default: True] + + Returns: + first name """ sex = _verify_and_return_sex(sex, country, name="first_names") return randname.first_name( @@ -656,8 +638,8 @@ def generate_first_name(year: int, sex: str, country: str, weights: bool) -> str sex, country, weights, - database=cochar.DATABASE, - show_warnings=cochar.SHOW_WARNINGS, + database=cochar.config.DATABASE, + show_warnings=cochar.config.SHOW_WARNINGS, ) @@ -667,14 +649,13 @@ def _verify_and_return_sex(sex: str, country: str, name: str) -> str: if provided sex is invalid, it will be overridden, and function return valid sex. - :param sex: _description_ - :type sex: str - :param country: _description_ - :type country: str - :param name: _description_ - :type name: str - :return: _description_ - :rtype: str + Args: + sex: Sex to validate + country: Country with data + name: Name type (e.g., "first_names" or "last_names") + + Returns: + valid sex """ available_sex = randname.show_data()[country][name] if sex not in available_sex: @@ -685,16 +666,19 @@ def _verify_and_return_sex(sex: str, country: str, name: str) -> str: return sex -def generate_sex(sex: Union[str, bool] = None) -> str: +def generate_sex(sex: str | None = None) -> str: """Generate character's sex - :param sex: Character's sex, if provided return that value - :type sex: Union[str, bool] - :raises ValueError: If provided sex is not in {"M", "F", None}, raise this error - :return: Character's sex as "M" or "F" - :rtype: str + Args: + sex: Character's sex, if provided return that value + + Raises: + ValueError: If provided sex is not in {"M", "F", None}, raise this error + + Returns: + Character's sex as "M" or "F" """ - if sex not in cochar.SEX_OPTIONS: + if sex not in cochar.config.SEX_OPTIONS: raise ValueError(f"incorrect sex value: {sex} -> ['M', 'F', None]") return random.choice(("M", "F")) if sex is None else sex.upper() diff --git a/src/cochar/config.py b/src/cochar/config.py new file mode 100644 index 0000000..090c1c3 --- /dev/null +++ b/src/cochar/config.py @@ -0,0 +1,96 @@ +import json +import logging +import os +from pathlib import Path + +import randname + +DEFAULT_LOGGING_LEVEL = logging.ERROR + +LOGGING_LEVEL_MAP = { + "debug": logging.DEBUG, + "info": logging.INFO, + "warning": logging.WARNING, + "error": logging.ERROR, + "critical": logging.CRITICAL, +} + +logging_level = DEFAULT_LOGGING_LEVEL + +logging.basicConfig( + format="[%(asctime)s][%(levelname)s][%(filename)s:%(funcName)s:%(lineno)d] %(message)s", + level=logging_level, +) + + +def set_logging_level(level: str = "error"): + logging_level = LOGGING_LEVEL_MAP.get(level) + return logging.basicConfig( + format="[%(asctime)s][%(levelname)s][%(filename)s:%(funcName)s:%(lineno)d] %(message)s", + level=logging_level, + ) + + +SEX_OPTIONS: set[str | None] = {"M", "m", "F", "f", None} +_THIS_FOLDER = os.path.dirname(os.path.abspath(__file__)) +POP_PYRAMID_PATH = os.path.abspath( + os.path.join(_THIS_FOLDER, "data", "popPyramid.json") +) + +# modification's table for characteristics: +MODIFIERS = { + "age_range": [19, 39, 49, 59, 69, 79, 90], + "mod_char_points": [5, 0, 5, 10, 20, 40, 80], + "mod_app": [0, 0, 5, 10, 15, 20, 25], + "mod_move_rate": [0, 0, 1, 2, 3, 4, 5], + "mod_edu": [0, 1, 2, 3, 4, 4, 4], +} +# Value matrix for setting build +VALUE_MATRIX = { + "combat_range": [64, 84, 124, 164, 204, 283, 364, 444, 524], + "build": [-2, -1, 0, 1, 2, 3, 4, 5, 6], + "damage_bonus": ["-2", "-1", "0", "+1K4", "+1K6", "+2K6", "+3K6", "+4K6", "+5K6"], +} + +with open( + os.path.join(_THIS_FOLDER, "data", "occupations.json"), "r", encoding="utf-8" +) as json_file: + # Full data of occupations + OCCUPATIONS_DATA: dict[str, dict] = dict(json.load(json_file)) + # OCCUPATIONS_DATA.pop("test") + # Just occupations names in the list + OCCUPATIONS_LIST: list[str] = list(OCCUPATIONS_DATA.keys()) + # Occupations divided on 5 categories depends on skill point calculation method + OCCUPATIONS_GROUPS: list[list[str]] = [ + [key for key, value in OCCUPATIONS_DATA.items() if "edu" in value["groups"]], + [key for key, value in OCCUPATIONS_DATA.items() if "edupow" in value["groups"]], + [key for key, value in OCCUPATIONS_DATA.items() if "edudex" in value["groups"]], + [key for key, value in OCCUPATIONS_DATA.items() if "eduapp" in value["groups"]], + [key for key, value in OCCUPATIONS_DATA.items() if "edustr" in value["groups"]], + ] + +with open( + os.path.join(_THIS_FOLDER, "data", "settings.json"), "r", encoding="utf-8" +) as json_file: + settings: dict = json.load(json_file) + MIN_AGE: int = settings["min_age"] + MAX_AGE: int = settings["max_age"] + MAX_SKILL_LEVEL: int = settings["max_skill_level"] + YEAR: int = settings["year"] + AGE: int = settings["age"] + SEX: str = settings["sex"] + FIRST_NAME: str = settings["first_name"] + LAST_NAME: str = settings["last_name"] + COUNTRY: str = settings["country"] + OCCUPATION: str = settings["occupation"] + WEIGHTS: bool = settings["weights"] + SHOW_WARNINGS: bool = settings["show_warnings"] + OCCUPATION_TYPE: str = settings["occupation_type"] + ERA: str = settings["era"] + TAGS: list[str] = settings["tags"] + + DATABASE: str = settings["database"] + if not DATABASE: + DATABASE = randname.DATABASE + +SKILLS_DATABASE = Path() / _THIS_FOLDER / "data" / "skills.json" diff --git a/src/cochar/error.py b/src/cochar/error.py index 8248beb..d87cbcd 100644 --- a/src/cochar/error.py +++ b/src/cochar/error.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """**Errors for cochar module**""" + from typing import Any @@ -24,86 +25,86 @@ class CocharError(Exception): class IncorrectOccupation(CocharError): """Raise when occupation is not in OCCUPATIONS_LIST""" - def __init__(self, occupation_name: str): + def __init__(self, occupation_name: str) -> None: self.occupation_name = occupation_name self.message = f"'{self.occupation_name.capitalize()}' not in available occupations. Check cochar.OCCUPATIONS_LIST" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class CharacteristicValueNotAnInt(CocharError): """Characteristic value has to be an integer number""" - def __init__(self, skill_name: str, skill_value: Any): + def __init__(self, skill_name: str, skill_value: Any) -> None: self.skill_name = skill_name self.skill_value = skill_value self.message = f"{self.skill_name.capitalize()} points must be an integer: '{self.skill_value}'" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class CharacteristicPointsBelowMinValue(CocharError): """Characteristic points cannot be below defined minimal value""" - def __init__(self, skill_name: str, min_value=0): + def __init__(self, skill_name: str, min_value=0) -> None: self.skill_name = skill_name self.min_value = min_value self.message = f"'{self.skill_name}' Characteristic points cannot be below: {self.min_value}" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class SkillValueNotAnInt(CocharError): """Skill value has to be an integer number""" - def __init__(self, skill): + def __init__(self, skill: Any) -> None: self.skill = skill self.message = f"'{self.skill}' Skill value must be an integer" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class SkillPointsBelowZero(CocharError): """Skill points cannot be below zero""" - def __init__(self, skill): + def __init__(self, skill: Any) -> None: self.skill = skill self.message = f"'{self.skill}' Skill points cannot be below zero" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class SkillsNotADict(CocharError): """Skills must be a dictionary""" - def __init__(self, skill): + def __init__(self, skill: Any) -> None: self.skill = skill self.message = f"Invalid skills: '{self.skill}'. Skills must be an dictionary" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class InvalidYearValue(CocharError): """Year must be an integer number""" - def __init__(self, year: int): + def __init__(self, year: int) -> None: self.year = year self.message = f"Invalid year: '{self.year}'. Year must be an integer number" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message @@ -113,27 +114,27 @@ class InvalidSexValue(CocharError): Raise when selected sex is not it available for chosen country. """ - def __init__(self, sex: str, available_sex: list): + def __init__(self, sex: str | None, available_sex: set[str | None]) -> None: self.sex = sex self.available_sex = available_sex self.message = f"{self.sex} not in {self.available_sex}" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return f"{self.sex} -> {self.message}." class EmptyName(CocharError): """Name cannot be an empty string""" - def __str__(self): + def __str__(self) -> str: return "Name cannot be an empty string" class AgeNotInRange(CocharError): """Age must be within specified range, default 15 - 90""" - def __init__(self, age: int, min_age: int, max_age: int): + def __init__(self, age: int, min_age: int, max_age: int) -> None: self.age = age self.min_age = min_age self.max_age = max_age @@ -142,110 +143,110 @@ def __init__(self, age: int, min_age: int, max_age: int): ) super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return f"{self.message}." class InvalidAgeValue(CocharError): """Age must be an integer number""" - def __init__(self, age: int): + def __init__(self, age: Any) -> None: self.age = age self.message = f"'{self.age}' Age must be an integer number" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class InvalidCountryValue(CocharError): """Raise when country is not in available countries""" - def __init__(self, country: str, available_countries: list): + def __init__(self, country: str, available_countries: set) -> None: self.country = country self.available_countries = available_countries self.message = f"{self.country} not in [{self.available_countries}]" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return f"{self.country} -> {self.message}." class InvalidOccupationValue(CocharError): """Raise when occupation is not in occupation list""" - def __init__(self, occupation: str, available_occupations: list): + def __init__(self, occupation: str, available_occupations: list[str]) -> None: self.occupation = occupation self.available_occupations = available_occupations self.message = f"{self.occupation} not in [{self.available_occupations}]" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class InvalidDamageBonusValue(CocharError): """Raise when occupation is not in occupation list""" - def __init__(self, damage_bonus: str, correct_damage_bonus: list): + def __init__(self, damage_bonus: str, correct_damage_bonus: list[str]) -> None: self.damage_bonus = damage_bonus self.correct_damage_bonus = correct_damage_bonus self.message = f"{self.damage_bonus} not in [{self.correct_damage_bonus}]" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class InvalidBuildValue(CocharError): """Raise when occupation is not in occupation list""" - def __init__(self, build: str, correct_build: list): + def __init__(self, build: int, correct_build: list[int]) -> None: self.build = build self.correct_build = correct_build self.message = f"{self.build} not in [{self.correct_build}]" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class InvalidOccupationEra(CocharError): """Raise when occupation era is not correct""" - def __init__(self, era: str, correct_era: list): + def __init__(self, era: str, correct_era: set[str]) -> None: self.era = era self.correct_era = correct_era self.message = f"{self.era} not in [{self.correct_era}]" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class InvalidOccupationType(CocharError): """Raise when occupation type is not correct""" - def __init__(self, _type: str, correct_type: list): + def __init__(self, _type: str, correct_type: list[str]) -> None: self._type = _type self.correct_type = correct_type self.message = f"{self._type} not in [{self.correct_type}]" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message class InvalidOccupationTags(CocharError): """Raise when tag is not among available tags""" - def __init__(self, tags: str, correct_tags: list): + def __init__(self, tags: str, correct_tags: list[str]) -> None: self.tags = tags self.correct_tags = correct_tags self.message = f"{self.tags} not in [{self.correct_tags}]" super().__init__(self.message) - def __str__(self): + def __str__(self) -> str: return self.message diff --git a/src/cochar/interface.py b/src/cochar/interface.py index c569d31..3d8654d 100644 --- a/src/cochar/interface.py +++ b/src/cochar/interface.py @@ -13,63 +13,70 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from abc import ABC, abstractmethod, abstractproperty -from pathlib import Path -from typing import List, Dict - -import os -import json import itertools +import json +from abc import ABC, abstractmethod +from pathlib import Path +from typing import TypedDict class SkillsDataInterface(ABC): - def __init__(self, database: Path, era: str): + def __init__(self, database: Path, era: set[str] | str | None = None): self.database = database self.era = era @abstractmethod - def get_skills(self) -> Dict[str, int]: + def get_skills(self) -> dict[str, int]: pass @abstractmethod - def get_skills_from_category(self) -> Dict[str, int]: + def get_skills_from_category(self, category: str) -> list[str]: pass @abstractmethod - def get_all_skills_names(self) -> List[str]: + def get_all_skills_names(self) -> list[str]: pass @abstractmethod - def get_categories_names(self) -> List[str]: + def get_categories_names(self) -> list[str]: pass @abstractmethod - def get_basic_skills_names(self) -> List[str]: + def get_basic_skills_names(self) -> list[str]: pass +# TODO: actually use it +class SkillData(TypedDict): + value: int + era: set[str] + categories: list[str] + + class SkillsJSONInterface(SkillsDataInterface): - def __init__(self, database: Path, era: set = None): + def __init__(self, database: Path, era: set[str] | str | None = None): super().__init__(database, era) self.load_data(database) self.database = database - if not era: + if era is None: self.era = {"classic-1920", "modern"} + elif isinstance(era, str): + self.era = {era} else: - self.era = set(era) + self.era = era def load_data(self, database) -> None: with open(database, "r", encoding="utf-8") as json_file: - self.skills_data: Dict = json.load(json_file) + self.skills_data: dict[str, SkillData] = json.load(json_file) - def get_skills(self) -> Dict[str, int]: + def get_skills(self) -> dict[str, int]: return { skill: item["value"] for skill, item in self.skills_data.items() if set(item["era"]).issuperset(self.era) } - def get_all_skills_names(self) -> List[str]: + def get_all_skills_names(self) -> list[str]: return [ skill for skill, item in self.skills_data.items() @@ -77,7 +84,7 @@ def get_all_skills_names(self) -> List[str]: ] # TODO: filter out categories that are not in current era - def get_categories_names(self) -> List[str]: + def get_categories_names(self) -> list[str]: return list( set( itertools.chain( @@ -86,7 +93,7 @@ def get_categories_names(self) -> List[str]: ) ) - def get_basic_skills_names(self) -> List: + def get_basic_skills_names(self) -> list: skills_basic = [ skill for skill, item in self.skills_data.items() @@ -95,7 +102,7 @@ def get_basic_skills_names(self) -> List: ] return skills_basic - def get_skills_from_category(self, category) -> List[str]: + def get_skills_from_category(self, category: str) -> list[str]: return [ skill for skill, item in self.skills_data.items() diff --git a/src/cochar/occup.py b/src/cochar/occup.py index fb17adf..5679960 100644 --- a/src/cochar/occup.py +++ b/src/cochar/occup.py @@ -17,14 +17,16 @@ Occupations is a module that contains functions related with occupations """ + import copy import random from itertools import compress -from typing import List, Tuple +from typing import List import cochar -import cochar.skill +import cochar.config import cochar.error +import cochar.skill def generate_occupation( @@ -34,41 +36,35 @@ def generate_occupation( appearance: int = 1, strength: int = 1, random_mode: bool = False, - occupation: str = None, - occup_type: str = None, - era: List[str] = None, - tags: List[str] = None, + occupation: str | None = None, + occup_type: str | None = None, + era: list[str] | None = None, + tags: list[str] | None = None, ) -> str: """Return occupation based on: education, power, dexterity, appearance and strength. - :param education: education points, defaults to 1 - :type education: int, optional - :param power: power points, defaults to 1 - :type power: int, optional - :param dexterity: dexterity points, defaults to 1 - :type dexterity: int, optional - :param appearance: appearance points, defaults to 1 - :type appearance: int, optional - :param strength: strength points, defaults to 1 - :type strength: int, optional - :param random_mode: ignore edu, pow, dex and str points and return totally random occupation, defaults to False - :type random_mode: bool, optional - :param occupation: return specified occupation, defaults to None - :type occupation: str, optional - :param occup_type: specify type of occupation to return, defaults to None - :type occup_type: str, optional - :param era: specify era of occupation to return, defaults to None - :type era: str, optional - :param tags: return occupation with defined tags, defaults to None - :type tags: List[str], optional - :raises cochar.error.IncorrectOccupation: when occupation is not in the list of available occupations - :raises cochar.error.NoneOccupationMeetsCriteria: when searching criteria are not met by any occupation - :return: occupation name - :rtype: str + Args: + education: education points, defaults to 1 + power: power points, defaults to 1 + dexterity: dexterity points, defaults to 1 + appearance: appearance points, defaults to 1 + strength: strength points, defaults to 1 + random_mode: ignore edu, pow, dex and str points and return totally random occupation, defaults to False + occupation: return specified occupation, defaults to None + occup_type: specify type of occupation to return, defaults to None + era: specify era of occupation to return, defaults to None + tags: return occupation with defined tags, defaults to None + + Raises: + cochar.error.IncorrectOccupation: when occupation is not in the list of available occupations + cochar.error.NoneOccupationMeetsCriteria: when searching criteria are not met by any occupation + + Returns: + occupation name """ # TODO: What happen if user provide illegal values, strings or below 0? - skill_points_groups: List[int] = [ + skill_points_groups: list[int] = [ education * 4, # 1 education * 2 + power * 2, # 2 education * 2 + dexterity * 2, # 3 @@ -77,27 +73,29 @@ def generate_occupation( ] if random_mode: - return random.choice(cochar.OCCUPATIONS_LIST) + return random.choice(cochar.config.OCCUPATIONS_LIST) if occupation: - if occupation not in cochar.OCCUPATIONS_LIST: + if occupation not in cochar.config.OCCUPATIONS_LIST: raise cochar.error.IncorrectOccupation(occupation) return occupation - occupation_groups = copy.deepcopy(cochar.OCCUPATIONS_GROUPS) + occupation_groups = copy.deepcopy(cochar.config.OCCUPATIONS_GROUPS) if occup_type: for i, group in enumerate(occupation_groups): occupation_groups[i] = [ occup for occup in group - if cochar.OCCUPATIONS_DATA[occup]["type"] == occup_type + if cochar.config.OCCUPATIONS_DATA[occup]["type"] == occup_type ] if era: for i, group in enumerate(occupation_groups): occupation_groups[i] = [ - occup for occup in group if cochar.OCCUPATIONS_DATA[occup]["era"] in era + occup + for occup in group + if cochar.config.OCCUPATIONS_DATA[occup]["era"] in era ] if tags: @@ -105,7 +103,9 @@ def generate_occupation( occupation_groups[i] = [ occup for occup in group - if set(tags).issubset(set(cochar.OCCUPATIONS_DATA[occup]["tags"])) + if set(tags).issubset( + set(cochar.config.OCCUPATIONS_DATA[occup]["tags"]) + ) ] filtered_occupation_groups = [ @@ -141,29 +141,24 @@ def calc_occupation_points( dexterity: int, appearance: int, strength: int, - occupation_points: int = None, + occupation_points: int | None = None, ) -> int: """Return occupation points based on occupation, education, power, dexterity, appearance and strength. - If ``occupation_points`` provided, return ``occupation_points`` - - :param occupation: occupation points - :type occupation: str - :param education: education points - :type education: int - :param power: power points - :type power: int - :param dexterity: dexterity points - :type dexterity: int - :param appearance: appearance points - :type appearance: int - :param strength: strength points - :type strength: int - :param occupation_points: occupation points, if provided function returns that value instead of calculating it, defaults to None - :type occupation_points: int, optional - :return: occupation points for provided occupation - :rtype: int + If `occupation_points` provided, return `occupation_points` + + Args: + occupation: occupation points + education: education points + power: power points + dexterity: dexterity points + appearance: appearance points + strength: strength points + occupation_points: occupation points, if provided function returns that value instead of calculating it, defaults to None + + Returns: + occupation points for provided occupation """ return ( occupation_points @@ -174,22 +169,22 @@ def calc_occupation_points( ) -def calc_hobby_points(intelligence: int, hobby_points: int = None) -> int: +def calc_hobby_points(intelligence: int, hobby_points: int | None = None) -> int: """Return hobby points, based on intelligence. occupation points = 2 * intelligence If `hobby_points` provided, return `hobby_points` - :param intelligence: intelligence points - :type intelligence: int - :param hobby_points: hobby_points, defaults to None - :type hobby_points: int, optional - :return: hobby points - :rtype: int + Args: + intelligence: intelligence points + hobby_points: hobby_points, defaults to None + + Returns: + hobby points """ return hobby_points if hobby_points else intelligence * 2 def get_occupation_list(): - return sorted(cochar.OCCUPATIONS_LIST) + return sorted(cochar.config.OCCUPATIONS_LIST) diff --git a/src/cochar/skill.py b/src/cochar/skill.py index f231385..831df4b 100644 --- a/src/cochar/skill.py +++ b/src/cochar/skill.py @@ -18,25 +18,23 @@ and Skills object, which is a container for skills """ + import random from collections import UserDict -from typing import Dict, List import cochar +import cochar.config import cochar.error import cochar.interface import cochar.utils -Skill = Dict[str, int] +Skill = dict[str, int] # TODO: write unit test class SkillsDict(UserDict): """Dictionary like object to store character's skills. Override __setitem__ to validate skills data. - - :param UserDict: UserDict from collections - :type UserDict: abc.ABCMeta """ def get_json_format(self): @@ -46,12 +44,13 @@ def get_json_format(self): def __setitem__(self, key: str, value: int) -> None: """Add validation for skill values - :param key: skill name - :type key: str - :param value: skill value - :type value: int - :raises SkillValueNotAnInt: when value is not an integer - :raises SkillPointsBelowZero: when value is less than 0 + Args: + key: skill name + value: skill value + + Raises: + cochar.error.SkillValueNotAnInt: when value is not an integer + cochar.error.SkillPointsBelowZero: when value is less than 0 """ key = str(key) if not isinstance(value, int): @@ -83,7 +82,7 @@ def generate_skills( hobby_points: int, dexterity: int, education: int, - skills: SkillsDict = None, + skills: SkillsDict | None = None, ) -> SkillsDict: """Return skills based on: occupation, occupation_points, hobby_points, dexterity and education @@ -97,20 +96,16 @@ def generate_skills( Dexterity is required for `dodge` skill. Education is required for `language(own)` skill. - :param occupation: occupation - :type occupation: str - :param occupation_points: occupation_points - :type occupation_points: int - :param hobby_points: hobby_points - :type hobby_points: int - :param dexterity: dexterity - :type dexterity: int - :param education: education - :type education: int - :param skills: skills, defaults to None - :type skills: Skills, optional - :return: skills with assigned skill level - :rtype: Skills + Args: + occupation: occupation + occupation_points: occupation_points + hobby_points: hobby_points + dexterity: dexterity + education: education + skills: skills, defaults to None + + Returns: + skills with assigned skill level """ if skills: skills = SkillsDict(skills) @@ -130,9 +125,9 @@ def generate_skills( if occupation_points_to_distribute < 0: occupation_points_to_distribute = 0 - default_occupations_skills: list = cochar.OCCUPATIONS_DATA[occupation][ - "skills" - ].copy() + default_occupations_skills: list = cochar.config.OCCUPATIONS_DATA[ + occupation + ]["skills"].copy() occupation_skills_list = self._get_skills_list(default_occupations_skills) hobby_skills_list = self._get_skills_list(self.skills_basic) @@ -147,14 +142,15 @@ def generate_skills( return skills - def _get_skills_list(self, input_list: list) -> List[str]: + def _get_skills_list(self, input_list: list) -> list[str]: """Parse an input list taken from `occupations.json` and - return list of skills + return list of skills + + Args: + input_list: list of skills from `occupations.json` - :param input_list: list of skills from `occupations.json` - :type input_list: list - :return: list of skills - :rtype: List[str] + Returns: + list of skills """ skills_list = [] skills_list += list( @@ -169,7 +165,7 @@ def _get_skills_list(self, input_list: list) -> List[str]: skills_list += self._get_category_skills(input_list) return skills_list - def _get_choice_skills(self, skills_list: list) -> List[str]: + def _get_choice_skills(self, skills_list: list) -> list[str]: """Parse a choice option from skills in `occupation.json` and return list of skills @@ -177,10 +173,11 @@ def _get_choice_skills(self, skills_list: list) -> List[str]: [1, "occult", "natural world"] -> ["occult"] It means, return randomly one skills from the following options - :param skills_list: list of skills to choose - :type skills_list: list - :return: list of skills - :rtype: List[str] + Args: + skills_list: list of skills to choose + + Returns: + list of skills """ result = [] for item in skills_list: @@ -199,7 +196,7 @@ def _get_choice_skills(self, skills_list: list) -> List[str]: return result - def _get_category_skills(self, skills_list: list) -> List[str]: + def _get_category_skills(self, skills_list: list) -> list[str]: """Parse a category skills, and return list of skills. Example: @@ -208,10 +205,11 @@ def _get_category_skills(self, skills_list: list) -> List[str]: "2*" -> ["first aid", "listen"] It means, two random skills of all available skills. - :param skills_list: list of category skill options - :type skills_list: list - :return: list of skills - :rtype: List[str] + Args: + skills_list: list of category skill options + + Returns: + list of skills """ result = [] for item in skills_list: @@ -237,14 +235,13 @@ def _assign_skill_points( """Allocate randomly points to the skills from skills_list and store it in Skills object - :param points: points to allocate - :type points: int - :param skills_list: list of skills - :type skills_list: list - :param skills: Skills object - :type skills: Skills - :return: None - :rtype: None + Args: + points: points to allocate + skills_list: list of skills + skills: Skills object + + Returns: + Skills object with allocated points """ for skill in skills_list: if skill in self.skills_all: @@ -254,27 +251,28 @@ def _assign_skill_points( while points: skill = random.choice(skills_list) - if points <= cochar.MAX_SKILL_LEVEL - skills[skill]: + if points <= cochar.config.MAX_SKILL_LEVEL - skills[skill]: points_allocation = random.randint(0, points) elif sum(list(skills.values())) % 90 == 0: break - elif skills[skill] >= cochar.MAX_SKILL_LEVEL: + elif skills[skill] >= cochar.config.MAX_SKILL_LEVEL: continue else: points_allocation = random.randint( - 0, cochar.MAX_SKILL_LEVEL - skills[skill] + 0, cochar.config.MAX_SKILL_LEVEL - skills[skill] ) skills[skill] += points_allocation points -= points_allocation return skills - def _filter_skills(self, skills: Dict) -> SkillsDict: + def _filter_skills(self, skills: dict[str, int]) -> SkillsDict: """Filter out all skills with basic value form given dict. - >>> example_dict = {'psychoanalysis': 1, 'language (spanish)': 66} - >>> SkillsGenerator(skills_interface)._filter_skills(example_dict) - {'language (spanish)': 66} + Examples: + >>> example_dict = {'psychoanalysis': 1, 'language (spanish)': 66} + >>> SkillsGenerator(skills_interface)._filter_skills(example_dict) + {'language (spanish)': 66} """ def has_skill_default_value(item) -> bool: @@ -294,14 +292,16 @@ def generate_credit_rating_points(occupation: str, occupation_points: int) -> in """For provided occupation, and it occupation points, return credit rating points. - :param occupation: occupation - :type occupation: str - :param occupation_points: occupation points - :type occupation_points: int - :return: credit rating points - :rtype: int + Args: + occupation: occupation + occupation_points: occupation points + + Returns: + credit rating points """ - credit_rating_range = cochar.OCCUPATIONS_DATA[occupation]["credit_rating"].copy() + credit_rating_range = cochar.config.OCCUPATIONS_DATA[occupation][ + "credit_rating" + ].copy() if occupation_points < min(credit_rating_range): credit_rating_range = [0, occupation_points] if occupation_points < max(credit_rating_range): @@ -322,22 +322,18 @@ def calc_skill_points( Return maximum points for provided occupation. - :param occupation: occupation name - :type occupation: str - :param education: education points - :type education: int - :param power: power points - :type power: int - :param dexterity: dexterity points - :type dexterity: int - :param appearance: appearance points - :type appearance: int - :param strength: strength points - :type strength: int - :return: skill points - :rtype: int + Args: + occupation: occupation name + education: education points + power: power points + dexterity: dexterity points + appearance: appearance points + strength: strength points + + Returns: + skill points """ - skill_points_groups: tuple[int] = ( + skill_points_groups: tuple[int, ...] = ( education * 4, # 1 education * 2 + power * 2, # 2 education * 2 + dexterity * 2, # 3 @@ -346,7 +342,7 @@ def calc_skill_points( ) group_index = [ index - for index, group in enumerate(cochar.OCCUPATIONS_GROUPS) + for index, group in enumerate(cochar.config.OCCUPATIONS_GROUPS) if occupation in group ] points = [skill_points_groups[i] for i in group_index] @@ -364,15 +360,15 @@ def skill_test(tested_value: int, repetition: int = 1) -> int: Repeat repetition times. - .. note: + Notes:: for characteristics use `characteristic_test()` - :param tested_value: tested value - :type tested_value: int - :param repetition: how many test to perform - :type repetition: int - :return: unchanged, or increased tested value - :rtype: int + Args: + tested_value: tested value + repetition: how many test to perform + + Returns: + unchanged, or increased tested value """ for _ in range(repetition): test = random.randint(1, 100) diff --git a/src/cochar/utils.py b/src/cochar/utils.py index c54f24a..a2983d2 100644 --- a/src/cochar/utils.py +++ b/src/cochar/utils.py @@ -31,10 +31,11 @@ - *: any """ + from bisect import bisect_left -from typing import Dict, Tuple, Sequence +from collections.abc import Sequence -TRANSLATION_DICT: Dict[str, str] = { +TRANSLATION_DICT: dict[str, str | None] = { "a": "art/craft", "s": "science", "f": "fighting", @@ -46,7 +47,7 @@ "*": None, } -AGE_RANGE: Tuple[int, int] = ( +AGE_RANGE: tuple[tuple[int, int], ...] = ( (15, 19), (20, 24), (25, 29), @@ -66,7 +67,7 @@ (95, 99), ) -YEAR_RANGE: Tuple[int] = ( +YEAR_RANGE: tuple[int, ...] = ( 1950, 1955, 1960, @@ -93,12 +94,13 @@ def narrowed_bisect(a: Sequence[int], x: int) -> int: It is to prevent IndexError, as many other variables relay on the index number returned. - :param a: sequence of numbers - :type a: Sequence - :param x: number to insert - :type x: int - :return: position of insertion - :rtype: int + Args: + a: sequence of numbers + x: number to insert + + + Returns: + index in sequence a where x can be inserted without exceeding len(a) """ i = bisect_left(a, x) return i if i != len(a) else i - 1 @@ -108,10 +110,11 @@ def is_skill_valid(skill_value: int) -> bool: """Check if skill value is int type and it is not below 0. - :param skill_value: skill value to test - :type skill_value: int - :return: True if value is valid, else False - :rtype: bool + Args: + skill_value: skill value to test + + Returns: + True if value is valid, else False """ if not isinstance(skill_value, int): return False diff --git a/tests/test_character.py b/tests/test_character.py index f1b0718..2070520 100644 --- a/tests/test_character.py +++ b/tests/test_character.py @@ -1,7 +1,7 @@ import pytest -import cochar import cochar.character +from cochar.cochar import create_character @pytest.fixture @@ -85,7 +85,7 @@ def example_characters_json(): def test_year_bigger_that_range(): - c = cochar.create_character(year=2022, country="US") + c = create_character(year=2022, country="US") assert c.year == 2022 diff --git a/tests/test_cochar.py b/tests/test_cochar.py index 97990d9..f7116bb 100644 --- a/tests/test_cochar.py +++ b/tests/test_cochar.py @@ -3,9 +3,26 @@ import pytest -import cochar +import cochar.config import cochar.error -import cochar.skill +from cochar.cochar import ( + calc_build, + calc_combat_characteristics, + calc_damage_bonus, + calc_derived_attributes, + calc_dodge, + calc_hit_points, + calc_magic_points, + calc_move_rate, + calc_sanity_points, + characteristic_test, + create_character, + generate_age, + generate_base_characteristics, + generate_sex, + subtract_points_from_characteristic, + subtract_points_from_str_con_dex, +) @pytest.fixture @@ -64,26 +81,26 @@ def country(): ], ) def test_all_occupations(occupation, year, country): - c = cochar.create_character(year, country, occupation=occupation) + c = create_character(year, country, occupation=occupation) assert c.occupation == occupation @pytest.mark.parametrize("occup_type", ["classic", "expansion"]) def test_create_character_occup_type(year, country, occup_type): - c = cochar.create_character(year, country, occup_type=occup_type) - assert cochar.OCCUPATIONS_DATA[c.occupation]["type"] == occup_type + c = create_character(year, country, occup_type=occup_type) + assert cochar.config.OCCUPATIONS_DATA[c.occupation]["type"] == occup_type @pytest.mark.parametrize("era", ["classic-1920", "modern"]) def test_create_character_occup_era(year, country, era): - c = cochar.create_character(year, country, era=era) - assert cochar.OCCUPATIONS_DATA[c.occupation]["era"] == era + c = create_character(year, country, era=era) + assert cochar.config.OCCUPATIONS_DATA[c.occupation]["era"] == era @pytest.mark.parametrize("tags", [["lovecraftian"], ["criminal"]]) -def test_create_character_occup_era(year, country, tags): - c = cochar.create_character(year, country, tags=tags) - assert cochar.OCCUPATIONS_DATA[c.occupation]["tags"] == tags +def test_create_character_occup_era_tags(year, country, tags): + c = create_character(year, country, tags=tags) + assert cochar.config.OCCUPATIONS_DATA[c.occupation]["tags"] == tags # TODO: write better test @@ -100,8 +117,7 @@ def test_create_character_occup_era(year, country, tags): ) def test_create_character(param, value): assert ( - cochar.create_character(1925, "US", **{param: value}).__getattribute__(param) - == value + create_character(1925, "US", **{param: value}).__getattribute__(param) == value ) @@ -114,12 +130,12 @@ def test_create_character(param, value): ], ) def test_generate_age(year, sex, age, result): - assert cochar.generate_age(year, sex, age) == result + assert generate_age(year, sex, age) == result def test_generate_age_invalid_year(): with pytest.raises(cochar.error.InvalidYearValue): - cochar.generate_age("invalid", "F") + generate_age("invalid", "F") # TODO: write better unit test @@ -137,7 +153,7 @@ def test_generate_base_characteristics(): "luck": 0, "move_rate": 0, } - c = cochar.generate_base_characteristics(**data) + c = generate_base_characteristics(**data) assert 15 <= c[0] <= 90 # strength assert 15 <= c[1] <= 90 # condition assert 40 <= c[2] <= 90 # size @@ -162,7 +178,7 @@ def test_calc_derived_attributes( power, size, condition, sanity_points, magic_points, hit_points, result ): assert ( - cochar.calc_derived_attributes( + calc_derived_attributes( power, size, condition, sanity_points, magic_points, hit_points ) == result @@ -171,7 +187,7 @@ def test_calc_derived_attributes( @pytest.mark.parametrize("power", [-1, 0, 1, 50]) def test_sanity_points(power): - assert cochar.calc_sanity_points(power) == power + assert calc_sanity_points(power) == power @pytest.mark.parametrize( @@ -185,7 +201,7 @@ def test_sanity_points(power): ], ) def test_calc_magic_points(power, result): - assert cochar.calc_magic_points(power) == result + assert calc_magic_points(power) == result @pytest.mark.parametrize( @@ -198,7 +214,7 @@ def test_calc_magic_points(power, result): ], ) def test_calc_hit_points(size, condition, result): - assert cochar.calc_hit_points(size, condition) == result + assert calc_hit_points(size, condition) == result @pytest.mark.parametrize( @@ -213,7 +229,7 @@ def test_calc_combat_characteristics( strength, size, dexterity, damage_bonus, build, dodge, result ): assert ( - cochar.calc_combat_characteristics( + calc_combat_characteristics( strength, size, dexterity, damage_bonus, build, dodge ) == result @@ -238,7 +254,7 @@ def test_calc_combat_characteristics( ], ) def test_calc_damage_bonus(strength, size, result): - assert cochar.calc_damage_bonus(strength, size) == result + assert calc_damage_bonus(strength, size) == result # TODO: test for bigger ranges @@ -259,7 +275,7 @@ def test_calc_damage_bonus(strength, size, result): ], ) def test_calc_build(strength, size, result): - assert cochar.calc_build(strength, size) == result + assert calc_build(strength, size) == result @pytest.mark.parametrize( @@ -272,7 +288,7 @@ def test_calc_build(strength, size, result): ], ) def test_calc_dodge(dexterity, result): - assert cochar.calc_dodge(dexterity) == result + assert calc_dodge(dexterity) == result @pytest.mark.parametrize( @@ -290,9 +306,7 @@ def test_subtract_points_from_characteristic( characteristic_points, subtract_points, result ): assert ( - cochar.subtract_points_from_characteristic( - characteristic_points, subtract_points - ) + subtract_points_from_characteristic(characteristic_points, subtract_points) == result ) @@ -309,7 +323,7 @@ def test_subtract_points_from_str_con_dex( strength, condition, dexterity, subtract_points, result ): assert ( - cochar.subtract_points_from_str_con_dex( + subtract_points_from_str_con_dex( strength, condition, dexterity, subtract_points ) == result @@ -338,7 +352,7 @@ def mock_random(*args): return 1 with patch("random.randint", mock_random): - assert cochar.characteristic_test(tested_value, repetition) == result + assert characteristic_test(tested_value, repetition) == result @pytest.mark.parametrize( @@ -352,18 +366,18 @@ def mock_random(*args): ], ) def test_calc_move_rate(strength, dexterity, size, result): - assert cochar.calc_move_rate(strength, dexterity, size) == result + assert calc_move_rate(strength, dexterity, size) == result @pytest.mark.parametrize("input", ["M", "m", "F", "f", None]) def test_generate_sex_valid_input(input): - assert cochar.generate_sex(input) in ["M", "F"] + assert generate_sex(input) in ["M", "F"] @pytest.mark.parametrize("input", ["", False, True]) def test_generate_sex_invalid_input(input): with pytest.raises(ValueError): - cochar.generate_sex(input) + generate_sex(input) class TestCharacter(unittest.TestCase): @@ -371,10 +385,10 @@ class TestCharacter(unittest.TestCase): def setUpClass(cls): cls.year = 1925 cls.country = "US" - cls.character = cochar.create_character(cls.year, cls.country) + cls.character = create_character(cls.year, cls.country) def test_year_bigger_that_range(self): - cochar.create_character(year=2022, country="US") + create_character(year=2022, country="US") def test_invalid_country(self): with self.assertRaises(cochar.error.InvalidCountryValue): diff --git a/tests/test_cochar_misc.py b/tests/test_cochar_misc.py index 7c2f674..f5f893b 100755 --- a/tests/test_cochar_misc.py +++ b/tests/test_cochar_misc.py @@ -1,16 +1,14 @@ #!/usr/bin/python3 -import unittest import random -import pytest -from deepdiff import DeepDiff +import unittest -import cochar -import cochar.occup +from deepdiff import DeepDiff from randname import randname -from cochar import create_character, generate_first_name, generate_last_name -from cochar.character import Character -from cochar.error import * +import cochar.config +import cochar.error +from cochar.character import Character +from cochar.cochar import create_character, generate_first_name, generate_last_name TEST_OCC = { "test_occ": { @@ -60,7 +58,7 @@ def test_dummy(self): self.assertEqual(self.character.age, 21) def test_invalid_sex_value(self): - with self.assertRaises(InvalidSexValue): + with self.assertRaises(cochar.error.InvalidSexValue): self.character.sex = "Alien" def test_first_name(self): @@ -78,7 +76,7 @@ def test_first_name_setter(self): self.assertEqual(c.first_name, name) def test_first_name_setter_invalid(self): - with self.assertRaises(EmptyName): + with self.assertRaises(cochar.error.EmptyName): self.character.first_name = "" def test_last_name(self): @@ -97,172 +95,172 @@ def test_last_name_setter(self): self.assertEqual(c.last_name, name) def test_last_name_setter_invalid(self): - with self.assertRaises(EmptyName): + with self.assertRaises(cochar.error.EmptyName): self.character.last_name = "" def test_year_normal(self): self.character.year = 45 def test_year_not_integer(self): - with self.assertRaises(InvalidYearValue): + with self.assertRaises(cochar.error.InvalidYearValue): self.character.year = "a" def test_age_normal(self): self.character.age = 45 def test_age_below_range(self): - with self.assertRaises(AgeNotInRange): + with self.assertRaises(cochar.error.AgeNotInRange): self.character.age = 14 def test_age_above_range(self): - with self.assertRaises(AgeNotInRange): + with self.assertRaises(cochar.error.AgeNotInRange): self.character.age = 91 def test_age_not_integer(self): - with self.assertRaises(InvalidAgeValue): + with self.assertRaises(cochar.error.InvalidAgeValue): self.character.age = "a" def test_strength_normal(self): self.character.strength = 0 def test_strength_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.strength = -1 def test_strength_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.strength = "a" def test_condition_normal(self): self.character.condition = 0 def test_condition_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.condition = -1 def test_condition_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.condition = "a" def test_size_normal(self): self.character.size = 0 def test_size_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.size = -1 def test_size_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.size = "a" def test_dexterity_normal(self): self.character.dexterity = 0 def test_dexterity_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.dexterity = -1 def test_dexterity_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.dexterity = "a" def test_appearance_normal(self): self.character.appearance = 0 def test_appearance_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.appearance = -1 def test_appearance_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.appearance = "a" def test_education_normal(self): self.character.education = 0 def test_education_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.education = -1 def test_education_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.education = "a" def test_intelligence_normal(self): self.character.intelligence = 0 def test_intelligence_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.intelligence = -1 def test_intelligence_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.intelligence = "a" def test_power_normal(self): self.character.power = 0 def test_power_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.power = -1 def test_power_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.power = "a" def test_sanity_points_normal(self): self.character.sanity_points = 0 def test_sanity_points_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.sanity_points = -1 def test_sanity_points_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.sanity_points = "a" def test_magic_points_normal(self): self.character.magic_points = 0 def test_magic_points_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.magic_points = -1 def test_magic_points_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.magic_points = "a" def test_hit_points_normal(self): self.character.hit_points = 0 def test_hit_points_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.hit_points = -1 def test_hit_points_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.hit_points = "a" def test_luck_normal(self): self.character.luck = 0 def test_luck_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.luck = -1 def test_luck_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.luck = "a" def test_move_rate_normal(self): self.character.move_rate = 0 def test_move_rate_below_range(self): - with self.assertRaises(CharacteristicPointsBelowMinValue): + with self.assertRaises(cochar.error.CharacteristicPointsBelowMinValue): self.character.move_rate = -1 def test_move_rate_not_integer(self): - with self.assertRaises(CharacteristicValueNotAnInt): + with self.assertRaises(cochar.error.CharacteristicValueNotAnInt): self.character.move_rate = "a" def test_skills_correct(self): @@ -271,12 +269,12 @@ def test_skills_correct(self): def test_skills_incorrect_type(self): skills = "ride" - with self.assertRaises(SkillsNotADict): + with self.assertRaises(cochar.error.SkillsNotADict): self.character.skills = skills def test_skills_value_not_an_int(self): skills = {"ride": "a"} - with self.assertRaises(SkillValueNotAnInt): + with self.assertRaises(cochar.error.SkillValueNotAnInt): self.character.skills = skills # def test_skills_incorrect_key(self): @@ -287,7 +285,7 @@ def test_skills_value_not_an_int(self): def test_skills_incorrect_value_below_0(self): skills = {"ride": 50, "occult": -1} - with self.assertRaises(SkillPointsBelowZero): + with self.assertRaises(cochar.error.SkillPointsBelowZero): self.character.skills = skills def test_skills_change_one_skill(self): @@ -334,7 +332,7 @@ def test_damage_bonus_normal(self): self.character.damage_bonus = "+1K4" def test_damage_bonus_below_range(self): - with self.assertRaises(InvalidDamageBonusValue): + with self.assertRaises(cochar.error.InvalidDamageBonusValue): self.character.damage_bonus = -3 def test_build_normal(self): @@ -343,7 +341,7 @@ def test_build_normal(self): self.character.build = 6 def test_build_below_range(self): - with self.assertRaises(InvalidBuildValue): + with self.assertRaises(cochar.error.InvalidBuildValue): self.character.build = -3 self.character.build = -7 @@ -374,14 +372,14 @@ def test_generate_first_name(self): def test_repr_true(self): for _ in range(20): c = self.character - d = eval(c.__repr__()) + d: Character = eval(c.__repr__()) print(DeepDiff(c.__dict__, d.__dict__), end="") assert c == d def test_repr_false(self): c = self.character - d = eval(c.__repr__()) - all_occupations = cochar.OCCUPATIONS_LIST.copy() + d: Character = eval(c.__repr__()) + all_occupations = cochar.config.OCCUPATIONS_LIST.copy() all_occupations.remove(c.occupation) random_occupation = random.choice(all_occupations) c.occupation = random_occupation diff --git a/tests/test_occupations.py b/tests/test_occupations.py index d659147..29d42ec 100644 --- a/tests/test_occupations.py +++ b/tests/test_occupations.py @@ -1,13 +1,15 @@ #!/usr/bin/python3 import pytest -import cochar -import cochar.occup +import cochar.config import cochar.error +import cochar.occup def test_get_occupation_list(): - assert set(cochar.occup.get_occupation_list()) == set(cochar.OCCUPATIONS_LIST) + assert set(cochar.occup.get_occupation_list()) == set( + cochar.config.OCCUPATIONS_LIST + ) @pytest.mark.parametrize( @@ -122,7 +124,7 @@ def test_calc_occupation_points( def test_generate_occupation_random(): o = cochar.occup.generate_occupation(random_mode=True) - assert o in cochar.OCCUPATIONS_LIST + assert o in cochar.config.OCCUPATIONS_LIST def test_generate_occupation_with_occupation(): @@ -202,8 +204,11 @@ def test_generate_occupation_lovecraftian(): ] -def test_generate_occupation_random(): - assert cochar.occup.generate_occupation(random_mode=True) in cochar.OCCUPATIONS_LIST +def test_generate_occupation_random_2(): + assert ( + cochar.occup.generate_occupation(random_mode=True) + in cochar.config.OCCUPATIONS_LIST + ) def test_generate_occupation_incorrect_occupation(): diff --git a/tests/test_skills.py b/tests/test_skills.py index e3695ad..2262c4f 100644 --- a/tests/test_skills.py +++ b/tests/test_skills.py @@ -1,14 +1,18 @@ -import pytest from unittest.mock import patch +import pytest + import cochar -import cochar.skill +import cochar.config import cochar.interface +import cochar.skill @pytest.fixture(scope="function", autouse=False) def skills_interface(): - return cochar.interface.SkillsJSONInterface(cochar.SKILLS_DATABASE, cochar.ERA) + return cochar.interface.SkillsJSONInterface( + cochar.config.SKILLS_DATABASE, cochar.config.ERA + ) def test_skill_test(): @@ -245,7 +249,7 @@ def test_generate_credit_rating_points_one_example(occupation, occupation_points def test_generate_credit_rating_points_all_occupations(): - for occupation, item in cochar.OCCUPATIONS_DATA.items(): + for occupation, item in cochar.config.OCCUPATIONS_DATA.items(): occupation_credit_rating_range = item["credit_rating"] points_to_test = [ occupation_credit_rating_range[0] - 1 diff --git a/upload.sh b/upload.sh deleted file mode 100755 index f091ff8..0000000 --- a/upload.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash -# Cochar - create a random character for Call of Cthulhu RPG 7th ed. -# Copyright (C) 2023 Adam Walkiewicz - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -# Update Package Version -# This script upload package to pypi.org. -# Before that it run tests -# -# Author: Adam Walkiewicz - -# VERBOSE=false -HELP=false -SOFTWARE_VERSION_FLAG=false -SOFTWARE_VERSION="" -USER=$(head -n 1 credentials) -PASS=$(tail -n 1 credentials) - -while getopts vhs: flag; do - case "${flag}" in - # v) VERBOSE=true;; - h) HELP=true;; - s) SOFTWARE_VERSION_FLAG=true - SOFTWARE_VERSION=${OPTARG} - ;; - *) HELP=true;; - esac -done - -echo_help() { - echo "Usage: upload [OPTION]" - echo "Update version of packages" - echo "Example: upload -vs \"1.1.1\"" - echo "" - echo "Output control:" - # echo " -v verbose mode" - echo " -h help" - echo " -s package version" - echo "" - echo "Report bugs to github.com/awalkiewicz/randname" - echo "Copyright (C) 2021 Adam Walkiewicz. All rights reserved." - exit 1 -} - -# echo_verbose () { -# $VERBOSE && echo -e "$*"; -# } - -SEMVER_REGEX="^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$" - - -function validate_version { - if $SOFTWARE_VERSION_FLAG; then - local version=$1 - if [[ "$version" =~ $SEMVER_REGEX ]]; then - # if a second argument is passed, store the result in var named by $2 - if [ "$#" -eq "2" ]; then - local major=${BASH_REMATCH[1]} - local minor=${BASH_REMATCH[2]} - local patch=${BASH_REMATCH[3]} - local prere=${BASH_REMATCH[4]} - local build=${BASH_REMATCH[5]} - eval "$2=(\"$major\" \"$minor\" \"$patch\" \"$prere\" \"$build\")" - else - echo "Version valid" - fi - else - error "version $version does not match the semver scheme 'X.Y.Z(-PRERELEASE)(+BUILD)'. See help for more information." - fi - fi -} - -change_version(){ - local version=$1 - if $SOFTWARE_VERSION_FLAG; then - sed -i "s,\"[[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+.*\",\"$1\",g" setup.py - sed -i "s,\"[[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+.*\",\"$1\",g" docs/conf.py - sed -i "s,\"[[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+.*\",\"$1\",g" cochar/__init__.py - echo "Versioin changed to: $1" - fi -} - -main(){ - # install changes locally that to run tests - pip3 install -e . && \ - # run tests, check packages, uploadd packages - pytest -q && \ - # change version in all files that contains info about it - validate_version $SOFTWARE_VERSION && \ - change_version $SOFTWARE_VERSION && \ - # clean dist directory - rm -rvf -i build && \ - rm -rvf -i $(echo dist/*) && \ - # create package, tar and wheel package - python3 setup.py sdist bdist_wheel && \ - # check whether packages are good - twine check $(echo dist/*) && \ - # upload changes to pypi.org - twine upload $(echo dist/c*) -u "$USER" -p "$PASS" && \ - # create documentation documentation - cd docs/ && \ - make html -} - -$HELP && echo_help -main diff --git a/uv.lock b/uv.lock index 05fe61c..a37115f 100644 --- a/uv.lock +++ b/uv.lock @@ -2,15 +2,6 @@ version = 1 revision = 3 requires-python = ">=3.11" -[[package]] -name = "alabaster" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, -] - [[package]] name = "attrs" version = "25.4.0" @@ -29,6 +20,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] +[[package]] +name = "backrefs" +version = "5.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/a7/312f673df6a79003279e1f55619abbe7daebbb87c17c976ddc0345c04c7b/backrefs-5.9.tar.gz", hash = "sha256:808548cb708d66b82ee231f962cb36faaf4f2baab032f2fbb783e9c2fdddaa59", size = 5765857, upload-time = "2025-06-22T19:34:13.97Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/4d/798dc1f30468134906575156c089c492cf79b5a5fd373f07fe26c4d046bf/backrefs-5.9-py310-none-any.whl", hash = "sha256:db8e8ba0e9de81fcd635f440deab5ae5f2591b54ac1ebe0550a2ca063488cd9f", size = 380267, upload-time = "2025-06-22T19:34:05.252Z" }, + { url = "https://files.pythonhosted.org/packages/55/07/f0b3375bf0d06014e9787797e6b7cc02b38ac9ff9726ccfe834d94e9991e/backrefs-5.9-py311-none-any.whl", hash = "sha256:6907635edebbe9b2dc3de3a2befff44d74f30a4562adbb8b36f21252ea19c5cf", size = 392072, upload-time = "2025-06-22T19:34:06.743Z" }, + { url = "https://files.pythonhosted.org/packages/9d/12/4f345407259dd60a0997107758ba3f221cf89a9b5a0f8ed5b961aef97253/backrefs-5.9-py312-none-any.whl", hash = "sha256:7fdf9771f63e6028d7fee7e0c497c81abda597ea45d6b8f89e8ad76994f5befa", size = 397947, upload-time = "2025-06-22T19:34:08.172Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/fa31834dc27a7f05e5290eae47c82690edc3a7b37d58f7fb35a1bdbf355b/backrefs-5.9-py313-none-any.whl", hash = "sha256:cc37b19fa219e93ff825ed1fed8879e47b4d89aa7a1884860e2db64ccd7c676b", size = 399843, upload-time = "2025-06-22T19:34:09.68Z" }, + { url = "https://files.pythonhosted.org/packages/fc/24/b29af34b2c9c41645a9f4ff117bae860291780d73880f449e0b5d948c070/backrefs-5.9-py314-none-any.whl", hash = "sha256:df5e169836cc8acb5e440ebae9aad4bf9d15e226d3bad049cf3f6a5c20cc8dc9", size = 411762, upload-time = "2025-06-22T19:34:11.037Z" }, + { url = "https://files.pythonhosted.org/packages/41/ff/392bff89415399a979be4a65357a41d92729ae8580a66073d8ec8d810f98/backrefs-5.9-py39-none-any.whl", hash = "sha256:f48ee18f6252b8f5777a22a00a09a85de0ca931658f1dd96d4406a34f3748c60", size = 380265, upload-time = "2025-06-22T19:34:12.405Z" }, +] + [[package]] name = "certifi" version = "2025.10.5" @@ -111,6 +116,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, +] + [[package]] name = "cochar" version = "2.0.0b1" @@ -122,10 +139,12 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "deepdiff" }, + { name = "mkdocs" }, + { name = "mkdocs-material" }, + { name = "mkdocstrings", extra = ["python"] }, { name = "mypy" }, { name = "pytest" }, { name = "ruff" }, - { name = "sphinx" }, ] [package.metadata] @@ -134,10 +153,12 @@ requires-dist = [{ name = "rname", specifier = ">=0.3.7" }] [package.metadata.requires-dev] dev = [ { name = "deepdiff", specifier = ">=8.6.1" }, + { name = "mkdocs", specifier = ">=1.6.1" }, + { name = "mkdocs-material", specifier = ">=9.6.23" }, + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.30.1" }, { name = "mypy", specifier = ">=1.18.2" }, { name = "pytest", specifier = ">=8.4.2" }, { name = "ruff", specifier = ">=0.14.3" }, - { name = "sphinx", specifier = ">=8.2.3" }, ] [[package]] @@ -162,30 +183,36 @@ wheels = [ ] [[package]] -name = "docutils" -version = "0.21.2" +name = "ghp-import" +version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, ] [[package]] -name = "idna" -version = "3.11" +name = "griffe" +version = "1.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +dependencies = [ + { name = "colorama" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/6c09dd7ce4c7837e4cdb11dce980cb45ae3cd87677298dc3b781b6bce7d3/griffe-1.14.0.tar.gz", hash = "sha256:9d2a15c1eca966d68e00517de5d69dd1bc5c9f2335ef6c1775362ba5b8651a13", size = 424684, upload-time = "2025-09-05T15:02:29.167Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/2a/b1/9ff6578d789a89812ff21e4e0f80ffae20a65d5dd84e7a17873fe3b365be/griffe-1.14.0-py3-none-any.whl", hash = "sha256:0e9d52832cccf0f7188cfe585ba962d2674b241c01916d780925df34873bceb0", size = 144439, upload-time = "2025-09-05T15:02:27.511Z" }, ] [[package]] -name = "imagesize" -version = "1.4.1" +name = "idna" +version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] [[package]] @@ -236,6 +263,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] +[[package]] +name = "markdown" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931, upload-time = "2025-11-03T19:51:15.007Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678, upload-time = "2025-11-03T19:51:13.887Z" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -310,6 +346,134 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/fa/9124cd63d822e2bcbea1450ae68cdc3faf3655c69b455f3a7ed36ce6c628/mkdocs_autorefs-1.4.3.tar.gz", hash = "sha256:beee715b254455c4aa93b6ef3c67579c399ca092259cc41b7d9342573ff1fc75", size = 55425, upload-time = "2025-08-26T14:23:17.223Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/4d/7123b6fa2278000688ebd338e2a06d16870aaf9eceae6ba047ea05f92df1/mkdocs_autorefs-1.4.3-py3-none-any.whl", hash = "sha256:469d85eb3114801d08e9cc55d102b3ba65917a869b893403b8987b601cf55dc9", size = 25034, upload-time = "2025-08-26T14:23:15.906Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.6.23" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/de/cc1d5139c2782b1a49e1ed1845b3298ed6076b9ba1c740ad7c952d8ffcf9/mkdocs_material-9.6.23.tar.gz", hash = "sha256:62ebc9cdbe90e1ae4f4e9b16a6aa5c69b93474c7b9e79ebc0b11b87f9f055e00", size = 4048130, upload-time = "2025-11-01T16:33:11.782Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/df/bc583e857174b0dc6df67d555123533f09e7e1ac0f3fae7693fb6840c0a3/mkdocs_material-9.6.23-py3-none-any.whl", hash = "sha256:3bf3f1d82d269f3a14ed6897bfc3a844cc05e1dc38045386691b91d7e6945332", size = 9210689, upload-time = "2025-11-01T16:33:08.196Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "0.30.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/33/2fa3243439f794e685d3e694590d28469a9b8ea733af4b48c250a3ffc9a0/mkdocstrings-0.30.1.tar.gz", hash = "sha256:84a007aae9b707fb0aebfc9da23db4b26fc9ab562eb56e335e9ec480cb19744f", size = 106350, upload-time = "2025-09-19T10:49:26.446Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/2c/f0dc4e1ee7f618f5bff7e05898d20bf8b6e7fa612038f768bfa295f136a4/mkdocstrings-0.30.1-py3-none-any.whl", hash = "sha256:41bd71f284ca4d44a668816193e4025c950b002252081e387433656ae9a70a82", size = 36704, upload-time = "2025-09-19T10:49:24.805Z" }, +] + +[package.optional-dependencies] +python = [ + { name = "mkdocstrings-python" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "1.18.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/95/ae/58ab2bfbee2792e92a98b97e872f7c003deb903071f75d8d83aa55db28fa/mkdocstrings_python-1.18.2.tar.gz", hash = "sha256:4ad536920a07b6336f50d4c6d5603316fafb1172c5c882370cbbc954770ad323", size = 207972, upload-time = "2025-08-28T16:11:19.847Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/8f/ce008599d9adebf33ed144e7736914385e8537f5fc686fdb7cceb8c22431/mkdocstrings_python-1.18.2-py3-none-any.whl", hash = "sha256:944fe6deb8f08f33fa936d538233c4036e9f53e840994f6146e8e94eb71b600d", size = 138215, upload-time = "2025-08-28T16:11:18.176Z" }, +] + [[package]] name = "mypy" version = "1.18.2" @@ -375,6 +539,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + [[package]] name = "pathspec" version = "0.12.1" @@ -384,6 +557,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, ] +[[package]] +name = "platformdirs" +version = "4.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, +] + [[package]] name = "pluggy" version = "1.6.0" @@ -402,6 +584,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pymdown-extensions" +version = "10.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/b3/6d2b3f149bc5413b0a29761c2c5832d8ce904a1d7f621e86616d96f505cc/pymdown_extensions-10.16.1.tar.gz", hash = "sha256:aace82bcccba3efc03e25d584e6a22d27a8e17caa3f4dd9f207e49b787aa9a91", size = 853277, upload-time = "2025-07-28T16:19:34.167Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/06/43084e6cbd4b3bc0e80f6be743b2e79fbc6eed8de9ad8c629939fa55d972/pymdown_extensions-10.16.1-py3-none-any.whl", hash = "sha256:d6ba157a6c03146a7fb122b2b9a121300056384eafeec9c9f9e584adfdb2a32d", size = 266178, upload-time = "2025-07-28T16:19:31.401Z" }, +] + [[package]] name = "pytest" version = "8.4.2" @@ -418,6 +613,85 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, ] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + [[package]] name = "referencing" version = "0.37.0" @@ -459,15 +733,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5e/46/c115296e1f9ca83e844c1362094ef6dd96c2320282a6a7dbaee2360bcb1d/rname-0.3.7-py3-none-any.whl", hash = "sha256:2e0bcde8f8cec0560ffa743a91effa7a58ca5e5a30aa025da28d35a2ffdde7e2", size = 727640, upload-time = "2022-11-23T22:12:23.649Z" }, ] -[[package]] -name = "roman-numerals-py" -version = "3.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017, upload-time = "2025-02-22T07:34:54.333Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742, upload-time = "2025-02-22T07:34:52.422Z" }, -] - [[package]] name = "rpds-py" version = "0.28.0" @@ -603,94 +868,12 @@ wheels = [ ] [[package]] -name = "snowballstemmer" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, -] - -[[package]] -name = "sphinx" -version = "8.2.3" +name = "six" +version = "1.17.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alabaster" }, - { name = "babel" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "docutils" }, - { name = "imagesize" }, - { name = "jinja2" }, - { name = "packaging" }, - { name = "pygments" }, - { name = "requests" }, - { name = "roman-numerals-py" }, - { name = "snowballstemmer" }, - { name = "sphinxcontrib-applehelp" }, - { name = "sphinxcontrib-devhelp" }, - { name = "sphinxcontrib-htmlhelp" }, - { name = "sphinxcontrib-jsmath" }, - { name = "sphinxcontrib-qthelp" }, - { name = "sphinxcontrib-serializinghtml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, -] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, -] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, -] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, -] - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, -] - -[[package]] -name = "sphinxcontrib-qthelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, -] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] @@ -710,3 +893,30 @@ sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599 wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] From 71e1d6224e7b40b484a58300f5e04f85ea283d16 Mon Sep 17 00:00:00 2001 From: Adam Walkiewicz Date: Sun, 9 Nov 2025 15:34:27 +0100 Subject: [PATCH 3/3] Remove python3.11 from supported versions --- .github/workflows/tests.yml | 2 +- docs/environment.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 65a604e..aef8f46 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.11", "3.12", "3.13", "3.14"] + python-version: ["3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v4 diff --git a/docs/environment.md b/docs/environment.md index 01c4cbc..4277deb 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -26,7 +26,7 @@ and reduces the time spent debugging non-existent bugs. Before setting up the environment, ensure you have the following installed: - **Python**: The project is built using Python. Make sure you have Python - installed on your machine. The project has to be compatible with **python3.10** + installed on your machine. The project has to be compatible with **python3.12** - **Make**: We use Make to simplify various tasks such as setup, testing, and building the project. - **Curl**: Required for downloading scripts.