From 400ad4d166706bbf75783fb56cbda24045ccc7ce Mon Sep 17 00:00:00 2001 From: Young Date: Wed, 14 Aug 2024 10:16:07 +0000 Subject: [PATCH] Init from serious-scaffold-python. --- .copier-answers.yml | 40 + .devcontainer/Dockerfile | 103 ++ .devcontainer/Dockerfile.dockerignore | 7 + .devcontainer/devcontainer.json | 32 + .github/FUNDING.yml | 2 + .github/workflows/ci.yml | 59 + .github/workflows/commitlint.yml | 27 + .../workflows/delete-untagged-packages.yml | 32 + .github/workflows/devcontainer.yml | 81 ++ .github/workflows/readthedocs-preview.yml | 25 + .github/workflows/release.yml | 131 ++ .github/workflows/renovate.yml | 52 + .github/workflows/semantic-release.yml | 50 + .gitignore | 168 +++ .pre-commit-config.yaml | 94 ++ .readthedocs.yaml | 35 + .releaserc.json | 118 ++ .renovaterc.json | 167 +++ .vscode/extensions.json | 12 + .vscode/settings.json | 99 ++ LICENSE | 21 + Makefile | 150 ++ README.md | 95 ++ .../images/bootstrap-dev-container-github.png | Bin 0 -> 88528 bytes .../images/bootstrap-dev-container-gitlab.png | Bin 0 -> 99252 bytes .../images/dev-container-reopen-prompt.png | Bin 0 -> 23975 bytes docs/_static/images/logo.svg | 1 + docs/advanced/dev-containers.md | 45 + docs/advanced/index.md | 8 + docs/advanced/partial-dev-env.md | 55 + docs/api/index.md | 6 + docs/api/settings.md | 5 + docs/cli/index.md | 7 + docs/conf.py | 76 + docs/development/cleanup-dev-env.md | 31 + docs/development/commit.md | 56 + docs/development/git-workflow.md | 130 ++ docs/development/index.md | 11 + docs/development/setup-dev-env.md | 30 + docs/development/tests.md | 27 + docs/index.md | 23 + docs/management/index.md | 10 + docs/management/init.md | 46 + docs/management/release.md | 79 + docs/management/settings.md | 167 +++ docs/management/update.md | 53 + docs/reports/coverage/index.md | 3 + docs/reports/index.md | 7 + docs/reports/mypy/index.md | 3 + pdm.lock | 1276 +++++++++++++++++ pyproject.toml | 134 ++ scripts/generate-coverage-badge.sh | 26 + src/wan/__init__.py | 1 + src/wan/cli.py | 23 + src/wan/py.typed | 0 src/wan/settings.py | 37 + tests/__init__.py | 1 + tests/cli_test.py | 21 + tests/pkg_test.py | 8 + tests/settings_test.py | 14 + 60 files changed, 4020 insertions(+) create mode 100644 .copier-answers.yml create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/Dockerfile.dockerignore create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/commitlint.yml create mode 100644 .github/workflows/delete-untagged-packages.yml create mode 100644 .github/workflows/devcontainer.yml create mode 100644 .github/workflows/readthedocs-preview.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/renovate.yml create mode 100644 .github/workflows/semantic-release.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .readthedocs.yaml create mode 100644 .releaserc.json create mode 100644 .renovaterc.json create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100755 docs/_static/images/bootstrap-dev-container-github.png create mode 100755 docs/_static/images/bootstrap-dev-container-gitlab.png create mode 100644 docs/_static/images/dev-container-reopen-prompt.png create mode 100644 docs/_static/images/logo.svg create mode 100644 docs/advanced/dev-containers.md create mode 100644 docs/advanced/index.md create mode 100644 docs/advanced/partial-dev-env.md create mode 100644 docs/api/index.md create mode 100644 docs/api/settings.md create mode 100644 docs/cli/index.md create mode 100644 docs/conf.py create mode 100644 docs/development/cleanup-dev-env.md create mode 100644 docs/development/commit.md create mode 100644 docs/development/git-workflow.md create mode 100644 docs/development/index.md create mode 100644 docs/development/setup-dev-env.md create mode 100644 docs/development/tests.md create mode 100644 docs/index.md create mode 100644 docs/management/index.md create mode 100644 docs/management/init.md create mode 100644 docs/management/release.md create mode 100644 docs/management/settings.md create mode 100644 docs/management/update.md create mode 100644 docs/reports/coverage/index.md create mode 100644 docs/reports/index.md create mode 100644 docs/reports/mypy/index.md create mode 100644 pdm.lock create mode 100644 pyproject.toml create mode 100644 scripts/generate-coverage-badge.sh create mode 100644 src/wan/__init__.py create mode 100644 src/wan/cli.py create mode 100644 src/wan/py.typed create mode 100644 src/wan/settings.py create mode 100644 tests/__init__.py create mode 100644 tests/cli_test.py create mode 100644 tests/pkg_test.py create mode 100644 tests/settings_test.py diff --git a/.copier-answers.yml b/.copier-answers.yml new file mode 100644 index 0000000..92a4e7c --- /dev/null +++ b/.copier-answers.yml @@ -0,0 +1,40 @@ +_commit: v0.0.54 +_src_path: gh:serious-scaffold/ss-python +author_email: afe.young@gmail.com +author_name: Xiao Yang +copyright_holder: '' +copyright_license: MIT License +copyright_year: 2022-2024 +coverage_threshold: 100 +default_py: '3.12' +development_status: Beta +max_py: '3.12' +min_py: '3.8' +module_name: wan +organization_name: '' +package_name: wan +platforms: +- macos +- ubuntu +- windows +project_description: 'Wait and notify conveniently' +project_name: WAN +readme_content: "\n\n# Wait And Notify(WAN)\nThis package is under development. We\ + \ will release it soon in the future.\n\n\n\n# Installation\n\nYou can install\ + \ wan with **one** of the following command\n\n\n```shell\n# 1)\n# pip install wan # TODO: upload this to pip\ + \ source\n# 2)\npip install git+https://github.com/you-n-g/wan.git@master\n# 3)\n\ + python setup.py install\n# 4)\npython setup.py develop # It is recommended if\ + \ you want to develop wan\n```\n\n## config\n\nPlease config your [notifiers](https://github.com/liiight/notifiers).\n\ + `wan` will read the setting in ` ~/.dotfiles/.notifers.yaml` as the arguments\ + \ for notifiers.\n\nHere is a config example of telegram\n```yaml\nprovider: telegram\n\ + kwargs:\n chat_id: \n \ + \ token: \n```\n\nOther configs:\n\ + ```yaml\nlog_level: DEBUG # the default level is INFO\n```\n\n\n# Usage\n\n##\ + \ Use in python code\n\n* Call the function in python code directly.\n```python\n\ + \nfrom wan import ntf; ntf('Finished')\n\ + ```\n\n* Call the function in shell directly\n```shell\n> sleep 10 ; wan ntf sleep\ + \ finished\n```\n\n" +repo_name: wan +repo_namespace: you-n-g +repo_platform: github diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..a57bd5d --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,103 @@ +# syntax=docker/dockerfile:1 + +ARG PYTHON_VERSION=3.12 + +######################################################################################## +# Dev image is used for development and cicd. +######################################################################################## + +FROM python:${PYTHON_VERSION} as dev + +# NOTE: python docker image has env `PYTHON_VERSION` but with patch version. +# ARG is used here for temporary override without changing the original env. +ARG PYTHON_VERSION + +# Config Python +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONHASHSEED=0 +ENV PYTHONUNBUFFERED=1 + +# Config pipx +ENV PIPX_HOME=/usr/local/pipx +ENV PIPX_BIN_DIR=/usr/local/bin +ENV PIPX_DEFAULT_PYTHON=/usr/local/bin/python + +# renovate: depName=debian_12/bash-completion +ARG BASH_COMPLETION_VERSION="1:2.11-6" +# renovate: depName=debian_12/pipx +ARG PIPX_VERSION="1.1.0-1" +# renovate: depName=debian_12/sudo +ARG SUDO_VERSION="1.9.13p3-1+deb12u1" +# renovate: depName=debian_12/vim +ARG VIM_VERSION="2:9.0.1378-2" + +# Install system dependencies and override pipx with a newer version +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash-completion="${BASH_COMPLETION_VERSION}" \ + pipx="${PIPX_VERSION}" \ + sudo="${SUDO_VERSION}" \ + vim="${VIM_VERSION}" \ + && pipx install pipx==1.6.0 \ + && apt-get purge -y --autoremove pipx \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* \ + && hash -r + +# Install prerequisites +RUN --mount=source=Makefile,target=Makefile \ + make prerequisites + +# Create a non-root user with sudo permission +ARG USERNAME=wan +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --create-home --uid $USER_UID --gid $USER_GID $USERNAME -s /bin/bash \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME + +# Set permission for related folders +RUN chown -R $USER_UID:$USER_GID $PIPX_HOME $PIPX_BIN_DIR + +# Set default working directory +WORKDIR /workspace + +######################################################################################## +# Build image is an intermediate image used for building the project. +######################################################################################## + +FROM dev as build + +# Install dependencies and project into the local packages directory. +ARG SCM_VERSION +RUN --mount=source=README.md,target=README.md \ + --mount=source=pdm.lock,target=pdm.lock \ + --mount=source=pyproject.toml,target=pyproject.toml \ + --mount=source=src,target=src,rw \ + mkdir __pypackages__ && SETUPTOOLS_SCM_PRETEND_VERSION_FOR_WAN=${SCM_VERSION} pdm sync --prod --no-editable + +######################################################################################## +# Prod image is used for deployment and distribution. +######################################################################################## + +FROM python:${PYTHON_VERSION}-slim as prod + +# NOTE: python docker image has env `PYTHON_VERSION` but with patch version. +# ARG is used here for temporary override without changing the original env. +ARG PYTHON_VERSION + +# Config Python +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONHASHSEED=0 +ENV PYTHONUNBUFFERED=1 + +# Retrieve packages from build stage. +ENV PYTHONPATH=/workspace/pkgs +COPY --from=build /workspace/__pypackages__/${PYTHON_VERSION}/lib /workspace/pkgs + +# Retrieve executables from build stage. +COPY --from=build /workspace/__pypackages__/${PYTHON_VERSION}/bin/* /usr/local/bin/ + +# Set command to run the cli by default. +ENTRYPOINT ["wan-cli"] diff --git a/.devcontainer/Dockerfile.dockerignore b/.devcontainer/Dockerfile.dockerignore new file mode 100644 index 0000000..593ed61 --- /dev/null +++ b/.devcontainer/Dockerfile.dockerignore @@ -0,0 +1,7 @@ +* +.* +!/Makefile +!/README.md +!/pdm.lock +!/pyproject.toml +!/src/ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..cc02aab --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +{ + "customizations": { + // Configure extensions specific to VS Code. + "vscode": { + "extensions": [ + "DavidAnson.vscode-markdownlint", + "ExecutableBookProject.myst-highlight", + "charliermarsh.ruff", + "ms-python.mypy-type-checker", + "ms-python.python", + "richie5um2.vscode-sort-json", + "streetsidesoftware.code-spell-checker" + ] + } + }, + "image": "ghcr.io/you-n-g/wan/dev:py3.12", + // Force the image update to ensure the latest version which might be a bug. + // Reference: https://github.com/microsoft/vscode-remote-release/issues/9391 + "initializeCommand": "docker pull ghcr.io/you-n-g/wan/dev:py3.12", + // Use a targeted named volume for .venv folder to improve disk performance. + // Reference: https://code.visualstudio.com/remote/advancedcontainers/improve-performance#_use-a-targeted-named-volume + "mounts": [ + "source=${localWorkspaceFolderBasename}-venv,target=${containerWorkspaceFolder}/.venv,type=volume" + ], + "name": "wan", + // Set proper permission for the .venv folder when the container created. + "postCreateCommand": "sudo chown wan:wan .venv", + // Prepare the development environment when the container starts. + "postStartCommand": "make dev", + // Use the non-root user in the container. + "remoteUser": "wan" +} diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..0715e6f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: + - Xiao Yang diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..53711f0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,59 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + +jobs: + ci: + if: ${{ !cancelled() && ! failure() }} + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + fetch-depth: 0 + - name: Set up PDM + uses: pdm-project/setup-pdm@568ddd69406b30de1774ec0044b73ae06e716aa4 # v4 + with: + cache: true + python-version: ${{ matrix.python-version }} + version: 2.16.1 + - run: env | sort + - run: make prerequisites + - run: make dev + - run: make lint test doc build + strategy: + matrix: + os: + # renovate: github-runner + - macos-14 + # renovate: github-runner + - ubuntu-22.04 + # renovate: github-runner + - windows-2022 + python-version: + - '3.8' + - '3.9' + - '3.10' + - '3.11' + - '3.12' + # Python 3.8 and 3.9 do not run on macos-14 which is using arm64 hardware. + exclude: + # renovate: github-runner + - os: macos-14 + python-version: '3.8' + # renovate: github-runner + - os: macos-14 + python-version: '3.9' + include: + - os: macos-13 + python-version: '3.8' + - os: macos-13 + python-version: '3.9' diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml new file mode 100644 index 0000000..88bda37 --- /dev/null +++ b/.github/workflows/commitlint.yml @@ -0,0 +1,27 @@ +name: CommitLint +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} +jobs: + commitlint: + container: + image: commitlint/commitlint:19.3.1@sha256:02c8c31b2c61c51eadb410960648c8b370f7583609f4ca1520155eeeefd63d66 + runs-on: ubuntu-22.04 + steps: + - run: env | sort + - name: Validate the latest commit message with commitlint + if: github.event_name == 'push' + run: echo "${{ github.event.head_commit.message }}" | npx commitlint -x @commitlint/config-conventional + - name: Validate pull request title with commitlint + if: github.event_name == 'pull_request' + run: echo "${{ github.event.pull_request.title }}" | npx commitlint -x @commitlint/config-conventional +on: + pull_request: + types: + - opened + - synchronize + - reopened + - edited + push: + branches: + - main diff --git a/.github/workflows/delete-untagged-packages.yml b/.github/workflows/delete-untagged-packages.yml new file mode 100644 index 0000000..841be6f --- /dev/null +++ b/.github/workflows/delete-untagged-packages.yml @@ -0,0 +1,32 @@ +name: Delete Untagged Packages + +on: + schedule: + - cron: "0 2 * * 0" + workflow_dispatch: null + +permissions: + packages: write + +jobs: + delete-untagged-packages: + runs-on: ubuntu-latest + steps: + - name: Delete untagged dev-cache packages + uses: actions/delete-package-versions@e5bc658cc4c965c472efe991f8beea3981499c55 # v5.0.0 + with: + package-name: "wan/dev-cache" + package-type: "container" + delete-only-untagged-versions: "true" + - name: Delete untagged development packages + uses: actions/delete-package-versions@e5bc658cc4c965c472efe991f8beea3981499c55 # v5.0.0 + with: + package-name: "wan/dev" + package-type: "container" + delete-only-untagged-versions: "true" + - name: Delete untagged production packages + uses: actions/delete-package-versions@e5bc658cc4c965c472efe991f8beea3981499c55 # v5.0.0 + with: + package-name: "wan" + package-type: "container" + delete-only-untagged-versions: "true" diff --git a/.github/workflows/devcontainer.yml b/.github/workflows/devcontainer.yml new file mode 100644 index 0000000..0c3880b --- /dev/null +++ b/.github/workflows/devcontainer.yml @@ -0,0 +1,81 @@ +name: DevContainer + +on: + pull_request: + paths: + - .devcontainer/Dockerfile + - .devcontainer/Dockerfile.dockerignore + - .github/workflows/devcontainer.yml + push: + branches: + - main + paths: + - .devcontainer/Dockerfile + - .devcontainer/Dockerfile.dockerignore + - .github/workflows/devcontainer.yml + workflow_dispatch: null + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + +jobs: + dev-container-publish: + permissions: + packages: write + runs-on: ubuntu-22.04 + steps: + - run: env | sort + - name: Checkout repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: Set up authentication + run: docker login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ghcr.io + - name: Set up BuildKit + run: | + docker context create builder + docker buildx create builder --name container --driver docker-container --use + docker buildx inspect --bootstrap --builder container + - name: Build the dev container + run: | + docker buildx build . \ + --build-arg PYTHON_VERSION=${{ matrix.python-version }} \ + --cache-from type=registry,ref=ghcr.io/${{ github.repository }}/dev-cache:py${{ matrix.python-version }} \ + --file .devcontainer/Dockerfile \ + --load \ + --tag ghcr.io/${{ github.repository }}/dev:py${{ matrix.python-version }} \ + --target dev + - name: Test the dev container + run: | + docker run --rm \ + -e CI=true \ + -v ${PWD}:/workspace \ + ghcr.io/${{ github.repository }}/dev:py${{ matrix.python-version }} \ + make dev lint test doc build + - name: Build the prod container + run: | + docker buildx build . \ + --build-arg PYTHON_VERSION=${{ matrix.python-version }} \ + --file .devcontainer/Dockerfile \ + --load \ + --tag ghcr.io/${{ github.repository }}:py${{ matrix.python-version }} \ + --target prod + - name: Test the prod container + run: docker run --rm ghcr.io/${{ github.repository }}:py${{ matrix.python-version }} + - name: Push the dev container + if: github.event_name != 'pull_request' + run: | + docker buildx build . \ + --build-arg PYTHON_VERSION=${{ matrix.python-version }} \ + --cache-to type=registry,ref=ghcr.io/${{ github.repository }}/dev-cache:py${{ matrix.python-version }},mode=max \ + --file .devcontainer/Dockerfile \ + --push \ + --tag ghcr.io/${{ github.repository }}/dev:py${{ matrix.python-version }} \ + --target dev + strategy: + matrix: + python-version: + - '3.8' + - '3.9' + - '3.10' + - '3.11' + - '3.12' diff --git a/.github/workflows/readthedocs-preview.yml b/.github/workflows/readthedocs-preview.yml new file mode 100644 index 0000000..09dfd14 --- /dev/null +++ b/.github/workflows/readthedocs-preview.yml @@ -0,0 +1,25 @@ +name: Read the Docs Pull Request Preview +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} +jobs: + documentation-links: + runs-on: ubuntu-22.04 + steps: + - name: Add Read the Docs preview's link to pull request + uses: readthedocs/actions/preview@cc0920454cf03ca8a3fbd3cbaa2ce2e509e70636 # v1.2 + with: + project-slug: wan +on: + pull_request_target: + types: + - opened + paths: + - .github/workflows/readthedocs-preview.yml + - .readthedocs.yaml + - Makefile + - README.md + - docs/** + - pdm.lock +permissions: + pull-requests: write diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9d4ff93 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,131 @@ +name: Release + +on: + release: + types: + - published + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + +jobs: + pages-build: + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + fetch-depth: 0 + - name: Set up PDM + uses: pdm-project/setup-pdm@568ddd69406b30de1774ec0044b73ae06e716aa4 # v4 + with: + cache: true + python-version: '3.12' + version: 2.16.1 + - run: env | sort + - run: make dev-doc + - run: make doc + - name: Upload pages artifact + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 + with: + path: public + pages: + needs: + - pages-build + permissions: + id-token: write + pages: write + runs-on: ubuntu-22.04 + steps: + - id: deployment + name: Deploy to GitHub Pages + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 + container-publish: + permissions: + packages: write + runs-on: ubuntu-22.04 + steps: + - run: env | sort + - name: Checkout repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: Set up authentication + run: docker login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ghcr.io + - name: Set up BuildKit + run: | + docker context create builder + docker buildx create builder --name container --driver docker-container --use + docker buildx inspect --bootstrap --builder container + - name: Build the dev container + run: | + docker buildx build . \ + --build-arg PYTHON_VERSION=${{ matrix.python-version }} \ + --cache-from type=registry,ref=ghcr.io/${{ github.repository }}/dev-cache:py${{ matrix.python-version }} \ + --file .devcontainer/Dockerfile \ + --load \ + --tag ghcr.io/${{ github.repository }}/dev:py${{ matrix.python-version }} \ + --tag ghcr.io/${{ github.repository }}/dev:py${{ matrix.python-version }}-${{ github.ref_name }} \ + --target dev + - name: Test the dev container + run: | + docker run --rm \ + -e CI=true \ + -v ${PWD}:/workspace \ + ghcr.io/${{ github.repository }}/dev:py${{ matrix.python-version }} \ + make dev lint test doc build + - name: Build the prod container + run: | + docker buildx build . \ + --build-arg SCM_VERSION=${{ github.ref_name }} \ + --build-arg PYTHON_VERSION=${{ matrix.python-version }} \ + --file .devcontainer/Dockerfile \ + --load \ + --tag ghcr.io/${{ github.repository }}:py${{ matrix.python-version }} \ + --tag ghcr.io/${{ github.repository }}:py${{ matrix.python-version }}-${{ github.ref_name }} \ + --target prod + - name: Test the prod container + run: docker run --rm ghcr.io/${{ github.repository }}:py${{ matrix.python-version }} + - name: Push the dev container + run: | + docker buildx build . \ + --build-arg PYTHON_VERSION=${{ matrix.python-version }} \ + --cache-to type=registry,ref=ghcr.io/${{ github.repository }}/dev-cache:py${{ matrix.python-version }},mode=max \ + --file .devcontainer/Dockerfile \ + --push \ + --tag ghcr.io/${{ github.repository }}/dev:py${{ matrix.python-version }} \ + --tag ghcr.io/${{ github.repository }}/dev:py${{ matrix.python-version }}-${{ github.ref_name }} \ + --target dev + - name: Push the prod container + run: | + docker buildx build . \ + --build-arg SCM_VERSION=${{ github.ref_name }} \ + --build-arg PYTHON_VERSION=${{ matrix.python-version }} \ + --file .devcontainer/Dockerfile \ + --push \ + --tag ghcr.io/${{ github.repository }}:py${{ matrix.python-version }} \ + --tag ghcr.io/${{ github.repository }}:py${{ matrix.python-version }}-${{ github.ref_name }} \ + --target prod + strategy: + matrix: + python-version: + - '3.8' + - '3.9' + - '3.10' + - '3.11' + - '3.12' + package-publish: + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: Set up PDM + uses: pdm-project/setup-pdm@568ddd69406b30de1774ec0044b73ae06e716aa4 # v4 + with: + cache: true + python-version: '3.12' + version: 2.16.1 + - run: env | sort + - env: + PDM_PUBLISH_PASSWORD: ${{ secrets.PDM_PUBLISH_PASSWORD }} + PDM_PUBLISH_USERNAME: ${{ vars.PDM_PUBLISH_USERNAME || '__token__' }} + run: make publish diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml new file mode 100644 index 0000000..48c5f28 --- /dev/null +++ b/.github/workflows/renovate.yml @@ -0,0 +1,52 @@ +name: Renovate +jobs: + renovate: + container: + env: + LOG_LEVEL: debug + RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["^git", "^pip", "^copier", "^find"]' + RENOVATE_BRANCH_PREFIX: renovate-github/ + RENOVATE_ENABLED: ${{ vars.RENOVATE_ENABLED || true }} + RENOVATE_ENABLED_MANAGERS: '["pep621", "github-actions", "regex", "pre-commit"]' + RENOVATE_OPTIMIZE_FOR_DISABLED: 'true' + RENOVATE_PLATFORM: github + RENOVATE_REPOSITORIES: '["${{ github.repository }}"]' + RENOVATE_REPOSITORY_CACHE: enabled + image: ghcr.io/renovatebot/renovate:37.438.2@sha256:afd919138fd9b2a65300c392a85d82042e6f0ca784ae512a272f74dcac6777b2 + options: '--user root' + runs-on: ubuntu-22.04 + steps: + - run: env | sort + - id: generate-token + name: Generate a token with GitHub App if App ID exists + if: vars.BOT_APP_ID + uses: actions/create-github-app-token@31c86eb3b33c9b601a1f60f98dcbfd1d70f379b4 # v1.10.3 + with: + app-id: ${{ vars.BOT_APP_ID }} + private-key: ${{ secrets.BOT_PRIVATE_KEY }} + - name: Warn if use GITHUB_TOKEN + run: | + if [ -z "${{ steps.generate-token.outputs.token || secrets.PAT }}" ]; then + echo "# :warning: GITHUB_TOKEN is used for renovate" >> $GITHUB_STEP_SUMMARY + echo "The GITHUB_TOKEN is used instead of a bot token or PAT and will not emit the checks for the pull requests." >> $GITHUB_STEP_SUMMARY + fi + - name: Warn if RENOVATE_GIT_AUTHOR is set while using GitHub App token + if: steps.generate-token.outputs.token && vars.RENOVATE_GIT_AUTHOR + run: | + echo "# :warning: `RENOVATE_GIT_AUTHOR` is set explicitly while using GitHub App token" >> $GITHUB_STEP_SUMMARY + echo "Generally, Renovate automatically detects the git author and email using the token. However, explicitly setting the `RENOVATE_GIT_AUTHOR` will override this behavior." >> $GITHUB_STEP_SUMMARY + - name: Run Renovate + env: + RENOVATE_GIT_AUTHOR: ${{ vars.RENOVATE_GIT_AUTHOR }} + RENOVATE_TOKEN: ${{ steps.generate-token.outputs.token || secrets.PAT || secrets.GITHUB_TOKEN }} + run: | + if [ -z "$RENOVATE_TOKEN" ]; then + echo "RENOVATE_TOKEN is not properly configured, skipping ..." + else + renovate $RENOVATE_EXTRA_FLAG + fi +on: + schedule: + # * is a special character in YAML so you have to quote this string + - cron: '*/15 0-3 * * 1' + workflow_dispatch: null diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml new file mode 100644 index 0000000..3e92eed --- /dev/null +++ b/.github/workflows/semantic-release.yml @@ -0,0 +1,50 @@ +name: Semantic Release + +on: + workflow_run: + workflows: [CI] + types: [completed] + branches: [main] + +jobs: + semantic-release: + name: Semantic Release + runs-on: ubuntu-22.04 + # Ensure CI workflow is succeeded and avoid semantic release on forked repository + if: github.event.workflow_run.conclusion == 'success' && github.repository == 'you-n-g/wan' + permissions: + contents: write + id-token: write + issues: write + pull-requests: write + steps: + - id: generate-token + name: Generate a token with GitHub App if App ID exists + if: vars.BOT_APP_ID + uses: actions/create-github-app-token@31c86eb3b33c9b601a1f60f98dcbfd1d70f379b4 # v1.10.3 + with: + app-id: ${{ vars.BOT_APP_ID }} + private-key: ${{ secrets.BOT_PRIVATE_KEY }} + - name: Warn if use GITHUB_TOKEN + run: | + if [ -z "${{ steps.generate-token.outputs.token || secrets.PAT }}" ]; then + echo "# :warning: GITHUB_TOKEN is used for semantic-release" >> $GITHUB_STEP_SUMMARY + echo "The GITHUB_TOKEN is used instead of a bot token or PAT and will not emit the released publish event for the released workflow." >> $GITHUB_STEP_SUMMARY + fi + - name: Checkout repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + fetch-depth: 0 + persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + with: + node-version: 'lts/*' + - name: Semantic Release + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token || secrets.PAT || secrets.GITHUB_TOKEN }} + run: > + npx + --package conventional-changelog-conventionalcommits@8.0.0 + --package semantic-release@24.0.0 + semantic-release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..edddc02 --- /dev/null +++ b/.gitignore @@ -0,0 +1,168 @@ +# Custom +*.swp +.DS_Store +Pipfile +public + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3a3ed0f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,94 @@ +default_install_hook_types: + - post-checkout + - post-merge + - post-rewrite + - pre-push +default_stages: + - manual + - pre-push +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-added-large-files + - id: check-docstring-first + - id: check-merge-conflict + args: + - '--assume-in-merge' + - id: check-toml + - id: check-xml + - id: check-yaml + - id: end-of-file-fixer + - id: forbid-new-submodules + - id: mixed-line-ending + - id: name-tests-test + - id: no-commit-to-branch + stages: + - pre-push + - id: sort-simple-yaml + files: .pre-commit-config.yaml + - id: trailing-whitespace + - repo: https://github.com/renovatebot/pre-commit-hooks + rev: 37.438.2 + hooks: + - id: renovate-config-validator + - repo: local + hooks: + - id: pdm-sync + name: pdm-sync + entry: pdm sync --clean + language: python + stages: + - post-checkout + - post-merge + - post-rewrite + always_run: true + pass_filenames: false + - id: pdm-lock-check + name: pdm-lock-check + entry: pdm lock --check + language: python + files: ^pyproject.toml$ + pass_filenames: false + - id: mypy + name: mypy + entry: pdm run python -m mypy + language: system + types_or: + - python + - pyi + require_serial: true + - id: ruff + name: ruff + entry: ruff check --force-exclude + language: system + types_or: + - python + - pyi + require_serial: true + - id: ruff-format + name: ruff-format + entry: ruff format --force-exclude + language: system + types_or: + - python + - pyi + require_serial: true + - id: pyproject-fmt + name: pyproject-fmt + entry: pyproject-fmt + language: python + files: '(^|/)pyproject\.toml$' + types: + - toml + - id: codespell + name: codespell + entry: codespell + language: python + types: + - text + - id: forbidden-files + name: forbidden files + entry: found Copier update rejection files; review them and remove them + language: fail + files: \.rej$ diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..b97738c --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,35 @@ +build: + apt_packages: + - pipx + jobs: + post_checkout: + - git fetch --unshallow || true + # Cancel building pull requests when there aren't changed in the related files and folders. + # If there are no changes (git diff exits with 0) we force the command to return with 183. + # This is a special exit code on Read the Docs that will cancel the build immediately. + # Ref: https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition + - | + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- \ + .github/workflows/readthedocs-preview.yml \ + .readthedocs.yaml \ + Makefile \ + README.md \ + docs/ \ + pdm.lock; + then + exit 183; + fi + post_system_dependencies: + - env | sort + pre_create_environment: + - PIPX_BIN_DIR=$READTHEDOCS_VIRTUALENV_PATH/bin pipx install pdm==2.16.1 + post_install: + - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH make dev-doc + post_build: + - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH make mypy doc-coverage + os: ubuntu-22.04 + tools: + python: '3.12' +sphinx: + fail_on_warning: true +version: 2 diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..8243fc4 --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,118 @@ +{ + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "releaseRules": [ + { + "breaking": true, + "release": "major" + }, + { + "type": "build", + "release": false + }, + { + "type": "chore", + "release": false + }, + { + "type": "ci", + "release": false + }, + { + "type": "docs", + "release": false + }, + { + "type": "feat", + "release": "minor" + }, + { + "type": "fix", + "release": "patch" + }, + { + "type": "perf", + "release": "patch" + }, + { + "type": "refactor", + "release": false + }, + { + "type": "revert", + "release": "patch" + }, + { + "type": "style", + "release": false + }, + { + "type": "test", + "release": false + }, + { + "scope": "*no-release*", + "release": false + } + ] + } + ], + [ + "@semantic-release/release-notes-generator", + { + "presetConfig": { + "types": [ + { + "type": "build", + "section": "Build" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "ci", + "section": "Continuous Integration" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance" + }, + { + "type": "refactor", + "section": "Refactor" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "test", + "section": "Tests" + } + ] + } + } + ], + "@semantic-release/github" + ], + "preset": "conventionalcommits" +} diff --git a/.renovaterc.json b/.renovaterc.json new file mode 100644 index 0000000..d7b2cd5 --- /dev/null +++ b/.renovaterc.json @@ -0,0 +1,167 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "constraints": { + "pdm": "2.16.1", + "python": "==3.12" + }, + "customManagers": [ + { + "customType": "regex", + "datasourceTemplate": "pypi", + "description": "Match Python packages installed with pip/pipx", + "fileMatch": [ + "^Makefile$", + "^README\\.md$", + "^\\.devcontainer/Dockerfile$", + "^\\.github/workflows/.+\\.yml$", + "^\\.gitlab/workflows/.+\\.yml$", + "^\\.readthedocs\\.yaml$", + "^\\.renovaterc\\.json$", + "^docs/.+\\.md$" + ], + "matchStrings": [ + "pip install.* (?.*?)(\\[.*?\\])?==(?.*?)[\"\n]", + "pipx install( --force)? (?.*?)(\\[.*?\\])?==(?.*?)\\s" + ] + }, + { + "customType": "regex", + "datasourceTemplate": "repology", + "depTypeTemplate": "debian", + "description": "Match debian packages installed in Dockerfiles", + "fileMatch": [ + "^\\.devcontainer\\/Dockerfile$" + ], + "matchStrings": [ + "# renovate: depName=(?.*?)\nARG .*?_VERSION=\"(?.*)\"\n" + ], + "versioningTemplate": "deb" + }, + { + "customType": "regex", + "datasourceTemplate": "pypi", + "depNameTemplate": "pdm", + "description": "Match pdm version specified in setup-pdm GitHub Action", + "fileMatch": [ + "^\\.github/workflows/.+\\.yml$" + ], + "matchStrings": [ + "uses: pdm-project/setup-pdm[\\s\\S]+?\\sversion: (?.*)\n" + ] + }, + { + "customType": "regex", + "datasourceTemplate": "pypi", + "depNameTemplate": "pdm", + "description": "Match pdm version specified in the renovate constraints", + "fileMatch": [ + "^\\.renovaterc\\.json$" + ], + "matchStrings": [ + "\"pdm\": \"(?.*)\"" + ] + }, + { + "customType": "regex", + "datasourceTemplate": "github-runners", + "depTypeTemplate": "github-runner", + "description": "Match GitHub runner defined in GitHub Actions matrix strategy", + "fileMatch": [ + "^\\.github/workflows/.+\\.yml$", + "^template/.*\\.github.*/workflows/.+\\.yml(\\.jinja)?$" + ], + "matchStrings": [ + "# renovate: github-runner\n\\s+- (os: )?(?.*?)-(?.*)\n" + ], + "versioningTemplate": "docker" + }, + { + "customType": "regex", + "datasourceTemplate": "npm", + "description": "Match npm packages used with npx", + "fileMatch": [ + "^\\.github/workflows/.+\\.yml$", + "^\\.gitlab/workflows/.+\\.yml$", + ], + "matchStrings": [ + "--package (?.+?)@(?.+?)\\s" + ], + "versioningTemplate": "docker" + }, + { + "customType": "regex", + "datasourceTemplate": "git-tags", + "depNameTemplate": "https://github.com/serious-scaffold/ss-python.git", + "depTypeTemplate": "copier-template", + "description": "Match template version specified in .copier-answers.yml", + "fileMatch": [ + "^\\.copier-answers\\.yml$" + ], + "matchStrings": [ + "_commit: (?.*?)\n" + ], + "versioningTemplate": "semver" + } + ], + "extends": [ + "config:best-practices", + ":enablePreCommit", + ":maintainLockFilesWeekly", + ":semanticCommitTypeAll(build)" + ], + "packageRules": [ + { + "commitMessageTopic": "serious-scaffold-python", + "description": "Update template with copier when a new version is released", + "matchDepTypes": [ + "copier-template" + ], + "postUpgradeTasks": { + "commands": [ + "git stash", + "pip install copier==9.3.1", + "copier update --defaults --vcs-ref {{{newVersion}}}" + ] + }, + "semanticCommitScope": "copier-template" + }, + { + "description": "Group pdm Python package and version specified in setup-pdm GitHub Action", + "groupName": "pdm", + "matchDatasources": [ + "github-tags", + "pypi" + ], + "matchDepNames": [ + "pdm" + ] + }, + { + "description": "Group renovate docker tag and pre-commit-hooks tag", + "groupName": "renovate", + "matchDatasources": [ + "docker", + "github-tags" + ], + "matchDepNames": [ + "ghcr.io/renovatebot/renovate", + "renovatebot/pre-commit-hooks" + ] + }, + { + "description": "Group debian packages to avoid failure when multiple packages are outdated", + "groupName": "debian packages", + "matchDepTypes": [ + "debian" + ] + }, + { + "description": "Pre-commit 3.5.0 is pinned as the last version supporting Python 3.8", + "enabled": false, + "matchCurrentVersion": "==3.5.0", + "matchPackageNames": [ + "pre-commit" + ] + } + ] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..fa99e8b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,12 @@ +{ + "recommendations": [ + "DavidAnson.vscode-markdownlint", + "ExecutableBookProject.myst-highlight", + "charliermarsh.ruff", + "ms-python.mypy-type-checker", + "ms-python.python", + "ms-vscode-remote.remote-containers", + "richie5um2.vscode-sort-json", + "streetsidesoftware.code-spell-checker" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..936f77b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,99 @@ +{ + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[markdown]": { + "editor.defaultFormatter": "DavidAnson.vscode-markdownlint" + }, + "[python]": { + "editor.codeActionsOnSave": { + "source.fixAll.ruff": "explicit", + "source.organizeImports.ruff": "explicit" + }, + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.formatOnSave": true + }, + "cSpell.words": [ + "autofix", + "automodule", + "cobertura", + "codespell", + "commitlint", + "conventionalcommits", + "datasource", + "deepclean", + "deflist", + "devcontainer", + "devcontainers", + "elif", + "endmacro", + "epub", + "furo", + "genindex", + "huxuan", + "interruptible", + "JPKXI", + "maxdepth", + "modindex", + "mypy", + "noninteractive", + "pathjoin", + "pipenv", + "pipx", + "pycache", + "pydantic", + "pypi", + "pyproject", + "pytest", + "Quickstart", + "renovatebot", + "repology", + "setuptools", + "softprops", + "sphinxcontrib", + "titlesonly", + "toctree", + "typer", + "unshallow", + "viewcode" + ], + "editor.codeActionsOnSave": { + "source.fixAll": "explicit" + }, + "editor.formatOnSave": true, + "editor.rulers": [ + 88 + ], + "files.exclude": { + "**/*.egg-info": true, + "**/.coverage": true, + "**/.mypy_cache": true, + "**/.pdm-build": true, + "**/.pytest_cache": true, + "**/.ruff_cache": true, + "**/.venv": true, + "**/Pipfile*": true, + "**/__pycache__": true, + "**/_build": true, + "**/coverage.xml": true, + "**/htmlcov": true + }, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.trimTrailingWhitespace": true, + "myst.preview.extensions": [ + "dollarmath", + "deflist" + ], + "sortJSON.contextMenu": { + "sortJSONAlphaNum": false, + "sortJSONAlphaNumReverse": false, + "sortJSONKeyLength": false, + "sortJSONKeyLengthReverse": false, + "sortJSONReverse": false, + "sortJSONType": false, + "sortJSONTypeReverse": false, + "sortJSONValues": false, + "sortJSONValuesReverse": false + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ba07482 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2024 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b6690c7 --- /dev/null +++ b/Makefile @@ -0,0 +1,150 @@ +.PHONY: clean deepclean install dev prerequisites mypy ruff ruff-format pyproject-fmt codespell lint pre-commit test-run test build publish doc-watch doc-build doc-coverage doc + +######################################################################################## +# Variables +######################################################################################## + +# Documentation target directory, will be adapted to specific folder for readthedocs. +PUBLIC_DIR := $(shell [ "$$READTHEDOCS" = "True" ] && echo "$${READTHEDOCS_OUTPUT}html" || echo "public") + +# Determine the Python version used by pipx. +PIPX_PYTHON_VERSION := $(shell `pipx environment --value PIPX_DEFAULT_PYTHON` -c "from sys import version_info; print(f'{version_info.major}.{version_info.minor}')") + +######################################################################################## +# Development Environment Management +######################################################################################## + +# Remove common intermediate files. +clean: + -rm -rf \ + $(PUBLIC_DIR) \ + .coverage \ + .mypy_cache \ + .pdm-build \ + .pdm-python \ + .pytest_cache \ + .ruff_cache \ + Pipfile* \ + __pypackages__ \ + build \ + coverage.xml \ + dist + find . -name '*.egg-info' -print0 | xargs -0 rm -rf + find . -name '*.pyc' -print0 | xargs -0 rm -f + find . -name '*.swp' -print0 | xargs -0 rm -f + find . -name '.DS_Store' -print0 | xargs -0 rm -f + find . -name '__pycache__' -print0 | xargs -0 rm -rf + +# Remove pre-commit hook, virtual environment alongside itermediate files. +deepclean: clean + if command -v pre-commit > /dev/null 2>&1; then pre-commit uninstall; fi + if command -v pdm >/dev/null 2>&1 && pdm venv list | grep -q in-project ; then pdm venv remove --yes in-project >/dev/null 2>&1; fi + +# Install the package in editable mode. +install: + pdm sync --prod + +# Install the package in editable mode with specific optional dependencies. +dev-%: + pdm sync --dev --group $* + +# Prepare the development environment. +# Install the package in editable mode with all optional dependencies and pre-commit hook. +dev: + pdm sync + if [ "$(CI)" != "true" ] && command -v pre-commit > /dev/null 2>&1; then pre-commit install; fi + +# Install standalone tools +prerequisites: + pipx install --force codespell[toml]==2.3.0 + pipx install --force pdm==2.16.1 +ifeq ($(PIPX_PYTHON_VERSION), 3.8) + pipx install --force pre-commit==3.5.0 +else + pipx install --force pre-commit==3.7.1 +endif + pipx install --force pyproject-fmt==2.1.4 + pipx install --force ruff==0.5.4 + pipx install --force watchfiles==0.22.0 + +######################################################################################## +# Lint and pre-commit +######################################################################################## + +# Check lint with mypy. +mypy: + pdm run python -m mypy . --html-report $(PUBLIC_DIR)/reports/mypy + +# Lint with ruff. +ruff: + ruff check . + +# Format with ruff. +ruff-format: + ruff format --check . + +# Check lint with pyproject-fmt. +pyproject-fmt: + pyproject-fmt pyproject.toml + +# Check lint with codespell. +codespell: + codespell + +# Check lint with all linters. +lint: mypy ruff ruff-format pyproject-fmt codespell + +# Run pre-commit with autofix against all files. +pre-commit: + pre-commit run --all-files --hook-stage manual + +######################################################################################## +# Test +######################################################################################## + +# Clean and run test with coverage. +test-run: + pdm run python -m coverage erase + pdm run python -m coverage run -m pytest + +# Generate coverage report for terminal and xml. +test: test-run + pdm run python -m coverage report + pdm run python -m coverage xml + +######################################################################################## +# Package +######################################################################################## + +# Build the package. +build: + pdm build + +# Publish the package. +publish: + pdm publish + +######################################################################################## +# Documentation +######################################################################################## + +# Generate documentation with auto build when changes happen. +doc-watch: + pdm run python -m http.server --directory public & + watchfiles "make doc-build" docs src README.md + +# Build documentation only from src. +doc-build: + pdm run sphinx-build -a docs $(PUBLIC_DIR) + +# Generate html coverage reports with badge. +doc-coverage: test-run + pdm run python -m coverage html -d $(PUBLIC_DIR)/reports/coverage + pdm run bash scripts/generate-coverage-badge.sh $(PUBLIC_DIR)/_static/badges + +# Generate all documentation with reports. +doc: doc-build mypy doc-coverage + +######################################################################################## +# End +######################################################################################## diff --git a/README.md b/README.md new file mode 100644 index 0000000..edf1179 --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# WAN + +Wait and notify conveniently + + + +[![CI](https://github.com/you-n-g/wan/actions/workflows/ci.yml/badge.svg)](https://github.com/you-n-g/wan/actions/workflows/ci.yml) +[![CommitLint](https://github.com/you-n-g/wan/actions/workflows/commitlint.yml/badge.svg)](https://github.com/you-n-g/wan/actions/workflows/commitlint.yml) +[![DevContainer](https://github.com/you-n-g/wan/actions/workflows/devcontainer.yml/badge.svg)](https://github.com/you-n-g/wan/actions/workflows/devcontainer.yml) +[![Release](https://github.com/you-n-g/wan/actions/workflows/release.yml/badge.svg)](https://github.com/you-n-g/wan/actions/workflows/release.yml) +[![Renovate](https://github.com/you-n-g/wan/actions/workflows/renovate.yml/badge.svg)](https://github.com/you-n-g/wan/actions/workflows/renovate.yml) +[![Semantic Release](https://github.com/you-n-g/wan/actions/workflows/semantic-release.yml/badge.svg)](https://github.com/you-n-g/wan/actions/workflows/semantic-release.yml) +[![Coverage](https://img.shields.io/endpoint?url=https://you-n-g.github.io/wan/_static/badges/coverage.json)](https://you-n-g.github.io/wan/reports/coverage) +[![Release](https://img.shields.io/github/v/release/you-n-g/wan)](https://github.com/you-n-g/wan/releases) +[![PyPI](https://img.shields.io/pypi/v/wan)](https://pypi.org/project/wan/) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/wan)](https://pypi.org/project/wan/) +[![GitHub](https://img.shields.io/github/license/you-n-g/wan)](https://github.com/you-n-g/wan/blob/main/LICENSE) + +[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm-project.org) +[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit) +[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/) +[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) +[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org) +[![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/5697b1e4c4a9790ece607654e6c02a160620c7e1/docs/badge/v2.json)](https://pydantic.dev) +[![Copier](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-orange.json)](https://github.com/copier-org/copier) +[![Serious Scaffold Python](https://img.shields.io/endpoint?url=https://serious-scaffold.github.io/ss-python/_static/badges/logo.json)](https://serious-scaffold.github.io/ss-python) +[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/you-n-g/wan) + +> [!IMPORTANT] +> _WAN_ is in the **Beta** phase. +> Changes and potential instability should be anticipated. +> Any feedback, comments, suggestions and contributions are welcome! + + + +# Wait And Notify(WAN) +This package is under development. We will release it soon in the future. + + + +# Installation + +You can install wan with **one** of the following command + + +```shell +# 1) +# pip install wan # TODO: upload this to pip source +# 2) +pip install git+https://github.com/you-n-g/wan.git@master +# 3) +python setup.py install +# 4) +python setup.py develop # It is recommended if you want to develop wan +``` + +## config + +Please config your [notifiers](https://github.com/liiight/notifiers). +`wan` will read the setting in ` ~/.dotfiles/.notifers.yaml` as the arguments for notifiers. + +Here is a config example of telegram +```yaml +provider: telegram +kwargs: + chat_id: + token: +``` + +Other configs: +```yaml +log_level: DEBUG # the default level is INFO +``` + + +# Usage + +## Use in python code + +* Call the function in python code directly. +```python + +from wan import ntf; ntf('Finished') +``` + +* Call the function in shell directly +```shell +> sleep 10 ; wan ntf sleep finished +``` + + + +## 📜 License + +MIT License, for more details, see the [LICENSE](https://github.com/you-n-g/wan/blob/main/LICENSE) file. diff --git a/docs/_static/images/bootstrap-dev-container-github.png b/docs/_static/images/bootstrap-dev-container-github.png new file mode 100755 index 0000000000000000000000000000000000000000..d2e18a57b6275d4a431b67a5cc33da7f10b07bd7 GIT binary patch literal 88528 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
    c`xW7XVBO=Ns#aYjMGZdE{ z?_;lE3_T3yKwB2z2V5)xVi5`GV$UOSH)Z(q57z5nNIlc49G#du{7BEO-*kd&0v z%FgoARqXeFdqo3BAJh%YQ0wKKt-;r47BRfy%<>YS5q>mxJypyl}e%GgOrlea(v2h?nU%rj?v(h^cS+C0sa?|BF6QOJwIWa-dX8x!alwZ zVV_(%Cq#MGkb04AB#+kA8G~S28Q8iZF{9*QiHF9|2x-T&;W%F4H?PSk>{hCZ#X&69mnz8NAJBQ72L&0 zGx5jkA4$8py~hdtDH-5frm>? zOhSMy)GKvx2wYi5^8UfD?6h+hfeVdR@#jVRp1|S*2D2oshNJNM#3v=je4Cp_Qgyfg z(6RpRlmc_NYK=Z@u2?!VqrK|bTH^{u+lkPReZX>e-%6UKFu7NxC0TFa@_`d5q7`7> zC@h^a1Olp?cdY)z%ET@8V+S!+X}he}Mkbu>=lE-e;X7}5)d*uc*0Dc2`QJMpeo__K zYZyX#HvX_^PrI%Ie(_!>Lxg`-R25fAku{Qr`wwF^jB^(q zjI!7#j~BqUNF#BNRcj;{ZK5;!qIj8iJxkKUU^n^v=vJ?__))n2VY|Z8TFc7ISW$+6H%!17smRUo2y2on&mQx&bfi1g&@MAe`x zdH&bF4es@BI}B}*5@N{4ODh3VJ&?Z%>?4|5O|dH;t<^rr7PT&ygVqc!+vFQ=Rg5Ut zO>lo)DD&E59j`PXvKM$cH7;#oW>%V=$=oz93&*GwV)yk3q3du~&i7bWQK*6y>O#a^ za64~-Dx^~%b!ZN1*4M4#3$Cow+b&-Tzz5dIM_s%06f}y}4){ByZ(Ff=r6=jK{G{lz zUD8Coj}Y;{iiiIg`B;*~PzNbhA5?fjSK5jmClW6t9AF(#Ij)bTrVIwn|1L=`Q3L|6_9z(L)k}li3sBD8q(UKKc zh-0za+Gu`PaZCSNRfT2ewb-iWqceB3li9zj>i+ma1=QPFNC4PwGmi^cc**>5jqE$xnyK*V4PL5@cF^Qt`j9yX$^2}ib?aK)q z!2~gEMYqg)p5!hHoxN;Z_i?MK7d@d0d&74;lQo(Yv#RY2zF&mt^mE10#BL47z8Bry zc`#T7yP^1PfR}oR#l4i}p*B>Sh(m9YZ;Rfqt(SL9kVWv*+_Vv?av5~Jj<9;dBTNtJ z!Kxim>ma$9SK<2DB$6b@ZOGaO$zA60Td1lk_!KH>ldd4=S9jei9H^D<|3@VJ(&N9V zbZnev3Q`Iw-%_^WZ?1ZuZNblbfK*mS>SVn{FTHMv$GMhMP_-peSM%|UTUrxwn=$I+ z7g*-}hS_rXet`Wp?leDbkHf}sy@2cRcAsmqQhxr(WyPMgs@};7GrAetu8rHF?o|e3 z;7SdTaBKJQLFd7h316ek+ZiHBNX;UP$2#4p{NB%y%shj%mJisX5nj80Fu5yB@BH)u)SsogTTa+oU@Fm8+}#^TJ!^)@ zc=n24S;$aeadC;}_JP?OC*?=w8{hz&FtS8bO3`S0%^|(;T8J*2(YEk6IHu!zPBY8u z;Bo?L{-xe7@=jxfI0a2f%U;SyXWTKzT4Tp6LL)C z(%%Sh*j+TGM2Wh;^mXC7Uw?n^#QQBGejN%am!XoZIIxY*i9dt z3tc`g+>}XAsWXfAp;kX&SDQ$%$PZ;|bge z@zH?VST9f5i44(6d)#|~A#^Zh02jPp#}a3m6y=zc;$ffVob&8zc0Om{*lNt`$OMM* z8>~N3YZxq33?L>m@fyR1YW~iVX?0({td};K#;0S96Emla&UX6c8XlUo&8}Xk%Z0oz z=R#8lQ#tyW80H~`>_fgtL_TfB+%o)LGb~kYYs29PJH4U$LadMu6DbGHJx|B6+fSGGYwB|} z5uIwGyaW~l)7s{%UYvVrhDtJju&j@D;a(smT~G59#(BnJFZZfP=;N5(i5m5!33e}= zclBkT0KpFRJV;}^J>)#6*`YTbU#bW7C|*}|*EC;^#&dLc=zS1j)}lIASQnh^RmX?^ z#9sxyQH4E6LxsPy*PLVCRwZ089St=&+D|pT&%?w zXMUQijp_J94j81D$7JX~Tig!Ieyo$^ytBR6=fKzkRj_0toeJ#)JKaZDn-p%lmj|I| zTJjr>R`2=^7UDuR!ZW%Ks)QJMT;##j;uE5AGQD7@JF7jn z3dONtYoZC*k@c?90`9pn2CP*FN$Q;WM5BQW;Z8*z9|Uz%+|V7(6qYpdQ0g}Vf5ORn zvP}}d6Eyw@ahMFwx|;(0yM?gmZJcT^xWL3+3PW_ zqxa+G5I%XQsOMr4Gt)uZA4>17T13lPIQZV`NMve!1zH9gm+kPXmgy3!P^(fOXC0wL zo_Qvxc(>K=<>Ir{ZiY`w0uY<@tuD84rQtg;&8jCw32nUnm$KCqr3eg zbw2&n;3Q{yFM|Ug7g$b>)8V{lvdC#VOzfaMV&~*|aMtq=gsD{5g;Sg<&q0{l!UC&R z>oYT%nEa1xnc=5-Dmk9R<_Ag<>Vt)S(NU3knb|i<={bkOCnf`}F)AeOV9xJHr5%5G zeBTV-u}^7v)5LukK|G3Nd!k*ujo8qHiwo>^xcMJn53R_Np7H(zJNNoG%sMJRd}m|e zzKuWl41|#b!Vt2*_$QzE-(`^k*{di~C;y4ras^09il2uQ{x|7CE@o_8IAN<*M&BPW z2L$9HD{=k+zkorN1tdN13fn!S`V-0lDddAcuzjxk!P9`8jUaPQn9`qU3EV4wvvmJz z!v7DGqlf}XaB;r8$Ldd*`aR!^^+$9LR0ER#X-NViVShpfDNwlAAE^E-Qjb;euJ}<$ z^~vV^fi;Kmy+nZMe*>~}L=wn<&(u4QF7f?=9QOkj&-$OB2K4{p;yJxI_4)JXXY;Mm zcZIqB;u3+DKguBRWl&IlVWHi}-X4eFFaapNyGT_aSuD=X6!MQC-K~*VWG9Pwb}%^D#@>SxzWFc1yr?{R?q{ckj4WpQkH>{ z@gmfa>aS|0rFbbBnV0es9IAbd*(v;UZUUwZ#_mnzX` z?PPw`{MJ#743B!_xJ_**M0}@fsi>*VG8cz2p{eGjQX*}j+4&@8@&C|av#O^N4NfelDf1Ywg zn~_OL>-qCaph|=Bbg=9F*ZJRLz;MU7b%9)vTglGOPDIy94Y)*XmADtUcPyv9{gHm| zI&cX53xsE8OUrLGNNr+=O3q9?>r;er=97_-H%!UzYWBeFl*1r5|2C_ODSoPjL&KM$>mee^LOo@yjw2%@34B(Oc4K`hF#gTV zCF0-ExI%^5($WG$s<5%KX{xAnXWT78trF8S{gad@kiysjy8T_Ca$x{*aq4~#!|#E? zZ%pN44)ykaxJ6IDED)-?cL3~?iry;3g*3P(zB`Z7`WuludWQ@QL%;xGChF-{8|?d> zZvGz6-{1)ck#V8V?%1|e#2RuR>#6FdvuWF+-;TV1nAL~Q|o6g#gi^n39UjOFeZjoOJss^}T%#PgSV8Xq|hkMX>B764!@6rE;D1Z%r zj607}C-J->_tKd;&^nLdUn?yxNoeF%_j^#16N=V-+{9)vBSHd`^jwAlb%E`Pf?b0( zDHo=6(1cT$vTc4d`S&=!qe=X#K{CXl+b;$2|{fnl56$5;m&W{KsJ15Ow^i8t?hF-nU zcwR*;)qsD+Z}osB?OcURr2=YmRo$NB)$iv2wg|bt0s4`!^ioF6`N;mR$NoF<|1Waf zhukl*;a-HfVmGeb-n{7EjA*0(0iQ)YU9xD4o4tZ!dJ3YJZPUf;`O|$i!rHwlIX^1#8bh9Jkbv!AxIOf<+%G(E z#a*}voc-ecEVL;i{OvPU*Hpu|u3RR4+RFYPA2M{dYxKrB>e|R_sCa4>esZSb)*@-5 z#Glg|7#f5uJG)cCEZ3ktrO@8zTF@}N39HPpMaKsB#PFX2>=c&((9mdcf|9ZLJp??t zJFOrUXMJ;t@?0wYLaaaDt|5rSKHBIMX_vtBsJH4~q4B;tHkE0c&jO)%0;wH!-PAsM9Zb9g#KrJ^u}5y$hZD}SG{|xImHN+uDoWBd}GBwv?r1kI%^}@ zy@O$t{NIxT-0xvk3RN>o3rKV2_{i!Pl_hB@SK0#=Ar(8IEyT}V8o`{egX)cFD^z>m z({Dh11k)}p1vrjJT1<9h!8VgMqtPh!iB!bPR#$MbGKd4WPnzT>_Xy+wIf&&l+N_+I zQ*Oh+ACsT<@!qG_7lf5PmqS!rwR`z{Zsw&MV9VU4u~DI$BKD(pJRqRG_g%a!l>kzQ zj$~gRs{kDUr@~xqxX%2n;Z541D|$QW&A&+!xD@eHA1G-Zl_jC`j&)X7*U+RsMx0U# z)BaP}-k_;&sZ6&#qSr3McHO0hMR+GVO&&Swd-L@WP%(Y~QNoY@q#i%~E@R{R#Glgn zQJtDh2UE}$!4wLuYp#Ah!fnM8!*slxMEvtzitFFy^|$+#u7P{TR~8s94Eo+xSpt*X z-C9M>3;%new7>t&?g|Vcc6HP~sXVQjMhNp@F}Y-VVe-RD*kL*3+0M;Euuod|UOD}R zDNojKN54p?`Ga%|LH$_WlL-N7V(?p_A^kq-pK|hy2@v_{wKK!`|K$Lhf8>J&)E~Ah zKem_egG49F){f+2${~t9WT;A?-(L|%j?A|p8j7pu3N|zGn z_o4Na3>((ZEQgek%=?o8POsa_)I{s|vBWnPJA*rP(#DS{gQ4yv^E*$Fqa}R@aTi++ zYJ2twYP#pz4d(ooQusCv2Uo7vfIyq`Vh zW+{uhdMhtazA*^WZ+VhuWq?{YUEB-HE-V#9+I$WEc>mkdtD^E&&z2BHol4p8H-nY$ zi1!5wtP4boFFG`f6wNFJ<|!u54!^@|upKxW)#DfTMlP7+I3yEByzZ^ce=x=>MO{3& zup@%#Ui0#vq?@Wj5Gg`M5RV(QYw=teK;%WQbDe_UJlpMtG`TDeO!;D-*58t0G-nfK zQBw<(mtY;x-Qe0kne3v0;QQe3pMCM-_%4;;ek8bgAez;N{S&rf^qKit&ZQ=`+FB`W zQbjO0sODqS%5L)Y+8x)bsxZ)knD?BHOav{%BI~5iiNJAQ^|&sm2q)F0_A+qIHU3AB%yQc4D&W9R}?rJ=+eLMMijBTPJLw<}J1(rM7gO`JLB%)5v{K zsYxr*Yd^Q7$VHDjb?H-W^;>tOu03C3&|E*QUia+;E;k*Pr9B>?)!RwYH+9qgfb zR|(3B(yzG+eMncUF*=DK^qr!6;sRXi+naVepb+H=U3^HTwBEarBe3MdIbGw2=_q(d zeX_bHO8gVQ?4l-zAjEmdT)bu)OaIE--{vEMxBpu_xG?>2dC*I$SzbO<`SLp^w2SG5 z%Te-|>D2A=PfqW%akDRJe%+>0SXJr66ZGWNiR`YsZJZ4E5F$5fwaJr$ ziV()HnZN58-znfFu)$|}NBfh%UKo1&5rZ&oqK1)5+P=k`Y;I9n5g0igziM7zwzYTW zi5P`HXa0&3xF9kZe>+a80_QouX&)c2S?!`ufh#K~i)y1s1X-xA+DdJ?61|_^lWgmz z^5-(6fiVljI;*XkdV1+1HbV#^k-FHMO>F$4imS~x^Un?PdOFZVV$)b>l7NsAS;N$C% z7ct3RMewi66RtwKbOK6RVB08cj<&l{#}TvAAtTwl;k|^|YeQBq%Fe3$CgY`?gbxZs zO66L?Yi5P|TrH#`WqJdS)1g$anpaksL+*qJ-(YgLp1?X1d0PL91>~M9B+JVqTY=s! z)zs2`wjhZ~0B>aPDWl%#3w0`LDkP_NU3baxc^xF zMdJs@2NXqB@;K;|7aY%UKgMG@;%M^QXRC#}W|u6KSY))@l@G+`FFk&lFn-T*!k3Fr zZHtmOn!>91f`u3X&z`YJerW@Zx?RqDTh-H83oA%Tk!@b@r-r0%Z2HB@UdXd2EwtlD5@ zYyN44OH@`GJvL4nIH7ONDots$2BNOz?z$XYF<8W?{3aLQS}Osm3r;ECAEVL$r#&P^ zW}RY!j{uB5iE>u2W(?=~?BFWmmaCI9KDuFq2yjGS5W9EzN7=vmh-6| z6{6IW6#51RbwD!JxXy(}T+kVQp4F+?_kt^Lubmiq^mXsj4IXawkxrS~esd@!Z@P9= zHe9`*d1x{HRRei$Zf{|=Vd{mcn|u=d`c~nb+KG}I_bXAC9oEd%)Knm4ll2+B^bSb| z|E8<~BVbn=q?EArerR{?REK(Z>!7|U2t4269lu>stOD6`%r!3_^ggiCer>m4UANti zsmOEBK6X{3`i!&?J-{)fl>tb(`;*ok%3Ny3TG94KnFGa%MbiXuC^}Kq1Q|w-meH@X z<6p_aOk(q9)K%UXU_*EHc_PY@D^WE=t0Sb8FnKy4n`yH?@)&O>9@7zKq@$^Qm^~B9FgKyLO>8I6JXjKFe4&=_FQNbx)h~=`g)@0=+ z)M9W@KPM>gXO0t|3h&Kw7x6Vvb1v_@V&LW$!_H@M!s%d|0Y;zrZjerO1LK73sl7?ip~%0lVyEf4MHfBbA<8N*Cmb(N z!;*)3u}_;DDgA~2V#~2d{AIerbrt^`Vytq!4)PjN#LNZk1M9c=X+K*m?1V}5N5|%t zLzJ{4ES`f|;e^!1{l(c<0o;amgb*Qboq6N91-ABH)Mh(bk&Tv24>&q8WI~vJit_Hg z*|*lTM>g@+ii$c#^1ZvuZ-RMxZ3_8Wj}-Dc-Ezx&Fj z99q2V1_ca)T|MPa&3moxz7SfYq>T~a{F^Mj%r>U-y;Y*sp-xkgi&LSFW73k7D|lPN z5xhaeot8r+h`!^%BK#wKcw>?0-9!gv*vnN`cZtH2RJPrv)aQ`%fuRkW?f>cqGPSJ4s-Vky*>=2T83pa3&m*xdAEgQt|(-iHGll9R+M6|Of zg7OuKG(_z0j%ui;1voqO@T$MO!$}l=@g7LYgj+s7x#$gXisp@^19^=|XC4x>IfS)> z`|886)oGo>CCkQU1{R4@S)7nM$>-FfW-;bQ7Vq@(HEVMoErcc?VL%)nWH5m-9jD2{ z>dZe}y~@<;>D>_SfxktVn7fO9ck|ZDBC#bO&Xiskp4&B`7*Sy(q`N zI}8!r^@dMu_f~WXyD3b*9`em+hB*|^O)rd(Y!nW8<$VckyBJOGk$-3COZ`zE>(y^( zeIu2J!rzst6dLb^IVgOOepRwX6QlE?GGXUl>U=c-lP9N61BLg>cI<8$kn}FL?iyUgOnd1xrPyc#WF_3?S9<*?uPAr;TjfA`k@)=>EoeJF)dmYX*c$8*vn zQW&)88(MTdQKM?ds~Rn=J=Nt7AS(j3&p*#d;rr-L|4v&i&Ti;>yUs~MO0vyv&zM%B ze`uuXPv-#F&|m7FPdnRQ_8eCyh?BSzyO1~ZLy+>5Ovtn6>vxPTfSwiOvZw8E< zu3YPgpR5;G?P#XY+jSWt!nqGpQfrT0U=|;I2-jTwHpw$kZ8xw&@X;_&wPjr`+4aOD zr(*b!uS0>_0XKIpLoJymnWYmR;;C4g?VWl8K!Hmxs>&LkQ^2t^A-Mzn{f^ZHBrE9KQueO#fa7?_-I?C&N)<)X~Sn7xV zsi5(nQIdG;{whLysL|0ZpewDbqU*E9=$sh#y>X_rn0-%p#>h%1VM<6xf0JHe>joFWUEK>y#fIYM&AOYb^G$%B5YP+;E%3*=rLUX|<%vOotp1%+3a{+yI&W=1{InTeAi%W7s|GFvTr`V46nN9Qf(VOfD8#*CwJMcnx0~0_m~O1>q^q6`%_RH--GMp z+V3tsR7?>Y@i>|+I$fyjeoFvn`0mg4Dp2IHncP7%UycJMd3g1Vsv#xRW=GctbU$@M zAb}^(K1U-~H`%U8JSq6l95Dpde!%8g-nid=N38vmH0W__hxL7% zCN3o)Iylta`^logw_V5-fHej?blrke&Pr{;J2)lG0kAIJcVkr97DKEg$6&^Z}5L- z8@OfhyBDC%R#zopIkGyDgwb&Me}b?Qa9OBGbriV5NE||3U$~=oo03^ z`sd3;dQT8^uB$`zgT>+t%vw9Xm0Cp9q?4gRYU{;qTKq{xYG3$Ug7>sA*!@%z%jA5U zCqF*&SY21!zu@36*fOe;(<)*mf3F;k=U7MUxB6Lp(h6G1QQnyTQ?b5C@bkj$6s!Mr zl!o?=p-zc(GQanChRm!7uXVMWcLphUkg|>%b1d@mH-}NsWxd#4mJi>D3D~LIs0Uh8 zWgglz?^|OFDYR>JJPe5yKN#4ugX`p^=4-YMzX_(CF2*!)z?rJvUhnsS3c1(-0{_f7 z%+A^lBKEH{6=HZ zVU|%<&6!vWr22gptMIdjUMQ`s>I^T}rSh$fB8XL;ItGWrDr#>r!E|i0|ImDlGCGEA zRpo98t2Has2K{E=*ZtzssjdHL8%E`;nTp-dovnWBxIa#05O8=v-EBql;>TFvZ;3a_ z0#@5L6EPG)9Od+W*2DL+&=J=tsa=hPV9Gekx>+V9Q4&m=+$L&YwtQHR`|D~QUN9=9 zW<=$W`I3$$Si7$5S|t}2YVTxe>FOhiMw2voJ@YWfho8>3KYFX`_ei^-TE#_vfFBC6 zv(;M7(t=W&aH&Vvfb&7_RkB%VpL?ztbuQ4nfl)cAkh&;sfGwe>$l(@wa081W$*T&7 zKs_Uk%wX9re9^8|E5x0x1YsKp62ofhKw0X_&pC8Q0KrflG_X!gKt(w=1t2gwdF&-j zEC0E2yj>xst4}x&Q&^NO}qq_-oa{MfatNBnqIl6eR=rjv|^I(ndY;9mjP;>4LED;ydO;(6M?@G<33 z%7aZX58ihFs{|@R04-ertQEq> zB`-&W3fYnuigUX=JW~}Z`R>Buy+M^v-RGfKvAEdD7vqhZ4*nL>~_Ut0ks4%Ztmxofwanh%M z9NS$J&F3>s%IvEtpGhIy)+@GM(6cj=9J8@(*NiSy4FbCc4c0C`Xd5ES%{LzGba)im zpDSHFp3cAV++j8)Y=7&UGPcmIZwKS<<@PxT0_LZ4{NkdB*9~&b6+X&DcFtkL-;GnE zy4?gaD*YCtI|GSqzL|&-)>#jaMl(xUjgre}?C_dbzY{o8z+pVShde;~_v|KUaTX(& z>e&pZ48(d%;?{KM72SLY(T3`X@Q~9jCNtJW&s!1;w;r3*Pzf02x%BaU!sXtx1}XIp zuq5#Me7L!GR-zOS2xNV>tOe3DIIR6oi$GV~>xJ3QC=YgS zK(mLjqU+aF>%kK)MmNf#$_RNNa@b6~oj*DCwZQi@7JzIdaY= zAkhZ9anMSZ8!}|G8i)iADR&1e1E(i3yo%ka6hPb7KMA6&+a&k1A=)Xdu?Vyvt*Rt# z_06k`Oyo%IJ~@ymAXmIA0FaGk{}cIc>&(+J`UeDoLEzc}1)Xj)GjZR0qTBR?Aznv@ zzba$={qIPDI)|`S^7eMFBGHEh7JFqMOXN|lj~FPtTs+6X%px)_JfZOTjUeTsV3J8J z$4`afSH2sl2^1z5pz=?XBh60`bVRi@g4RzzoJ}XBngRh{b|%GHyGsR=c_8wKq+(?m z4WOh3u2heF<}P*SfvC(RvUKHDM*ICiK4U4H30Bx+C&Ds29k2d;ug<*77t=SiYtS z_Ikq^q$GZpL_$^=rAwJ0G~OI5L=#A#oViwTKdiPtZKYRQ#I5syT=BW@gTE>Ye*6M_ zpJPc-4uSYq&0YdM;O8e(6@_bQFp>5wpic?K-YAS`0mB8-1N%#nfa==_lIEg11J=BKxZDi8rj} zjP_8wQ`!A8MWnic!iS^hAkRF_!Y{Y__kq|~v{rsgeVy6iYfFYK3+7LU3jwOL$YBZE zX9(%m)5i}AA^CUu-n8oRm%~`RpGP$@DXYsD^p8{IJ)|efO(Lr4ha^N|MyEjKzkDVI zS9O#<(FeIp_wNa}Ch@6R+sC-hJ=CqmK1f1VV!BjolJ)qT6yZKA&gI-x78xZ$}b@ggq2T#n^^LXW*&yo^rQvf3er@yuoEP} z*M4f7V4nT8TwAS1qj1K@48p6e_P%9ioEyoRr)3k@KWcrz z=1`Zsy=i{reY+)pXdI78j{>v-<5>-Al}qpoBeRbZPxCTP7hwu&}g&cE*6$*s*} zZv)ZNZQ&l^6Opia(RMXCt=~#6Sm2(sHpkL1Do|uTgVh~f8|bY0Zy}QO>s%nfgZ2nf zruOVGDm+^66PdHQI1{rp5_SM}2()f~Eg%_s%FGX`z;smmRU?6% z=AJc!wpxo>LUo>&X!_Xnr_bnheB*-21AY!Krl)8IDktW)sE9-K07Xb4p;sT1JL`tO zcNd-$KDelYt}T*nohffxBc8_vZ!RU!m9<4H3s%wKDuR`4P z=O(?!jzFQ#&K795>?*0TQi-HgS>w|AR zwLZwP%>!qCqtx4Dtf<)tjpM4k=*t)t`@R)mPnDDKntfK})*_AEyZ1cN9(Aig3JWZ& za|h48D6bG{e1XUJQ-&l$s7m19{J^(YDXsuC+B(o18FJBN)r~er;cA}*f zG$s-&e}r$Yw7s@y2IMK%2B^^+7wga!H(WP(b$){XVj)nbh9HuXWEC%tW8sY=qhBuI zF;85AF>3lc>oiO7YHDmcH=a*k`)c(j9zxkSL%IwT;AiEJqT}cr$pxxjO31Ms zWwpO#L^;le$ya+mZ5FP4qB+qLp{dpbd48g$490S#kA?`a-d*l{Pl|-iRSZVwmzUpj z)uMlG@-A38wdkn@y;$Ju=?q5ZBL%qxq0Yk8CL~ZLG~XPaw}Nj>zA5gJ39 zQ}iQwfnvL-|AdeKmg3ez*Y)r&uB;$UH@8r=#VijZ_{d<)7Eo!c)&B6rB5tR-e4{w$ zsZq;5U6L zt$jt^1h+7mz37*$VwDQmK6G>PTKkeuS!@<=hm{O2Eq#(^9X2f34|`Oz&(riiAtAl^ ztH8=q^8?piNj#s62r<3-8ww+=ySyl!j<`ffKXqA@W!|#qi6J%K?*l8PI4^xKQsU$u zP7KrdApU3|oplUY&9Y&tyRX|sj1f=s@0qufyG}C90(CSg>-IQRYu@9L#{C+J6po~xjQW>0Gk_;`gdVOz zFXgUy86P_EyzswqA@I|Mo0nc)3?sz3gNKK6`BV2(IsdCs_eus@d;3-lSLrq+_akP{ zX16?2Tn$!Jnk81NM(OH2GaK)zPF?w$c+FbPS?X?&idshY{i_5Q!tTG~dU`cdY_-P1 zyvu!m&6wA#>$bl;%F1j%VgroaK%quc&(4D5(>PO`dPpoxjRF|o;@Qh%;HmgwW=K6Q zz=mhVgd!zj=ysQ39XqsHD7oDv&7;oRSNXA==@lDPuU?TnPiQiG?A`R%Lw_U;ET36C z-v%FOizUWo9P3n`8m(l(W|sQV+_f~&&!6ynkK1wJTbI@SFn>Ptr&jdCaNMR9e2(Fn zVTNbKiCvDFLK#=F<~DwZk?v@hOUadi)aRl0_d#8wV8A5sGd*#LdMd*h_^W|`X+KmR z<03q)b?ozf)!!Xpm;#Tsu$fbd@N_Oc^<6ab-WYrX-xRbw>Qb+K3or1{YF^m*F_yPr z;LVb=Sd>9CuiE+NKRW&~eE*VLa8PB5OL3gq`NK3^E>Jk9)Dg3al=5}a2Hf{S$6R1N zV*9p(8(30^So-O+hNDZeKgMWk08G>t9kz9+eeQhve;d7j6do6dBdbD9`nLibAD0# zUnXJxopz|-jPS!Wee|91go&>Mju6uCh~R>$(@Tqp(2|;#IW;(g|0TiMeUFOSg-f7g z&e_jZoQ|-3@-qUk%cZ!Wbf9^z(x0q&>T2I?*|0!Dm!kUsjI5Sx}$ADB4@FHkb-fT6i2|FT@=r3K zKmRp(F4+sCqN7n!65D;vQE1u%h40xA+P|QHMaXk5&eBw!7Crw5oC2WdI7N-gBaZX&Ix@pSLP37x$$!o3Z&RGAzS4~k zK50M~FA`Hq&Js8dHQFu6{3e3qEdc%NvXyPMvcCt)e1#N%p$pb|`@f0xy-|1=$Kz|K zj0O}S_l(8MMv}i@GF1YQXu2N5{pp;x@OJ>8X||j!&Kv$aK>WEm9+RCia;ANSYGOdk1&u6}5a`N1|g*7lR(2DX!?WB&N6!aoR&zHD= zKi=zogyiWLNoFRG)xwHM3Cb~Fxjv@{=k5JV-^ACr@WCVvVPAw!cXK4w)r8h@hzjWU zJ?n(rQ8dRVCl9zr#Q1+t?OK}OJNS!BBwQ{{k1hn>O|q7V=8JlcQEffI`Y4_Un@K4N zKHnDmUV_X$^BgYM9wz%)7PA{vs#p~RV`lKV2}4I_&xW59=Wh)1!@PC-G3hB|B>xQ; zOaTY54y7b@MQN?G&|)@?!M5=|W#ukhhQyq|uy~D&i=WxTUtxA)Chr`Qev1Cz)*PgzrG@&y7lD%` z%d2uw<`t8kZ0q$W_M!BWDP?fs$hp6IyUvgKZUj+eSo4ZV^7M)^_$Vubq~vVzb%f|Y zFRn~Exc%l>c~as#QE_rn_u9PB)G#*I)6UJL8R08s!LRQ^i|bLr3hCL)*;{<)bAroD zU1*r#IU{4xQEVUds_qzBb9lEi;nF3}%*y(CAYXf{g(=mMMI)d36XINQNhMskzd4rd zKKVxOJ!5)Z9WA~0razm7`AHY4EZvL0NcuPKU6;Xp19TMSLV_~g0K1+(y5vWKW&N@Y z@5aU9uc@+U*2M3Pu$+=R&=VF2h7r+cb5iVBEG`gkbJgXuv)fz%y_gpQM$p(`)MoUFVZ~T#eE%* zKphX6U%*`VKD|=K149GX0hr65y(~FCV0Gxh3+F5j39~UMdB+R;vVT;as5smY= zMfNwT_b}aW;86Dw$N;bJlk`7>^tU|yyO=pAy8$3jlk$_qDE=D%Uqkv^KmYg7Oa(x! zE=MkS{4@3b!&A5>pl+&KTLS;GqW)19o)7Z8Evf1Y6rflRtCXO>xcWE1|EHh-o#=nW z!FLk>m!tm)KtDkEU+Dgi(&4{r^nVtm{}o366-K|!!T(C#{|BY6a5V+T?^=L=huHtW z1k<9%=&CfTu<={t(2@{>(D!loGI7*DZfDYbmTS0zpDV-n_vo$H`CTl($~>3QaxG9$U0ru5_Fr5;|Tt z2-DOP+pa6blP$Cj#PzSa!N<1OI@rEm1AQvi>+!rH z)KqL?%OqLzk>I5|#;$MJU>65`e_}KG$zC=oa{}(JcP)|oPsc@j0&kWlGo zr7n)>W;q&G*y-b{$P4Kx4wm+V@Km{XGkGtW+1knYajPXAWMYx`+W2qKF;n`7irqO< znV2?h3U8B%&zwFYub>KHnnyvWCj#lmMKo!}SbL&GX)+tv zTQWJ{`P6za$BWW_AoZ!rphU*5ZHTej@%0@8@w8i%`eLbQS z!w&hF?tH_UNxpeS*q>H3T$-RNE{wlYZAhfy0^KK=pG=jPG}OzPt0)bxzAA)^Tc6CX-A7Xa$4~~EnDsN!-vcKJZPF0jD;I21H zn{j5?PpGM#bHXxvbZ)zYu&)xo#`kOEFnR?cH7f}W-6jqSSVGxgSx1zA@-+lgEq(cn zL;q<;|1-G{41*Kt&=a@tc&kZKCoccU!ir1aU83Wey-hRENPbu2cB+T;=SyYxA<#idMjfLY|)FIjup1lUauF6GH{8{NRqcLymQ%sM6Tod z=;iuQl~es2T6TtEk(+`-w+3HTno-h$KN85ZRZkBMAG|TFQjG-n&6VDPdI=hi*cZ%s zXmbb<;*_X&X5OF-SAJK9OYK{JrAqDkMJ%xRuB#Jy=uVvsx4qS13aZAFLAYLCuF z%D&ZITC(w^OWxZP(XUD7*fHStF2q4aSa-X42bq0LJv-&!hqdeMirDKX&?{9YdkOCs zy<@2dUx=ht#`@0Yl`&e=DS*wu!7-9u?8SdYAPl-NxiK7%Lg+rP)VO4D8e9xms(Oxr z0@FL&x7>vdW$0b#qHj#}QZ|a^HJ_iXxkTL%o6!#GLFEWKPVsh>QVWM0$ z_@d{y24$WpgZN|jwwty^Mz50yxD&f>*!t!Spw^r?3<{EY+B*fZr%Tm9^6&7=_IQsw@WPp_Ik-X?;-{Xb;A z1y`Kg)`eL(1Pu_}5<-9=72Mt3T?4`0-Gc=W?oM!bE!^EH+}&Nfa?W>0pC0`S7`(NY z>^YycHt8tBYS%`M09iK-Iy^(6r{}ha#4Jwf*W0gP<`Xv_VMG{gtO^Mm=!p5jGnqO5P}4Fmk(D1lWeG zbNUC{qMzJQaN(@40gZ~%+Al=LW20S-A%_^>FpkxXe-I{eKqYVGE_bWR+hCf!yAZ+~ib0BEK{?n$Wo~)dfq5G+P>{>f^SrzA-J z?~3j%GL&_~l0`N>LeM8J4r@ZfOh!C#nAqrg^HB6Ft=N|C+6)-EGG&ykMg6dmKJ#Ss z0U#^Tf6%suF%swMzYV>P?k4=NlYtamS-2c1+bJoOYo|^1QK+>2Iami7>b}dN4^+s& zr-Qe98B3q>Q*I8~*p$^5o_0&=z7O{>oKRNg0ldDuD_~pK>oV6wUD~jkWX&(>iZ0NN z*2{i&F3-Q)y~x`Pr+`)~((GJs*5;f%s+Ta%07kEY3`FfFqDpOpJ~Pg`CopyQv87>h z`TJJU;aZ)3LgBOY6^(ZF^2QWm#keyaw=ejBy~8ruqfW-wbD3NHb4fsF<6>?8t%eD? z?$W$v60?meD>sZctf={eRmzKk{2oMC;B+$wl2S;K%$c!`||B0yr`$feph3jtZGd%A@{o7YyDM9sr*v<+C+ zOW{T6mVKjcSY6<{tSdITT)F84aVmiIY8X{{Qh*%{-Trf?TrTiSLq3NNe&9KFd1o9& zd=gGmUp9&3nLAP9SUSFy0%7JrI-oqxMPAG=&KnbwPwNs*;=ct0t;*1B&hCy(vietVB2UYHlU5Qg9#ty^ zEiM}WsPH#o!-SXsH_2?;ZeJF0+IX1|`sAN1m22~V55hYy={eU+>@F`;>guEHJSf;d zX%`8J4%Q`6ben;nMePV+8m5dfZPo#eO+fwIL&cCA)}Rh6!M$?5Pp-WobgWcmZxt2m z$D}U(mTBUE<(^pS%>WB4h6kY~3nYdwITzapOLMSPa`Pmg8}e_B@ULA7t|Vtcs6`&B$zehBUOB2;6j zXHkG=xrSUR8)H^-avQW?)-<5FkqP*K#O4X_c0#{Kj@@nqdE;k{BV=u%Z;V_4k2V0w z)Bf(eT^Piyd}pAnC-JJyH)cca9{yt+4)SP6?ZuIMXOHz%M*Jbjk1ufVK}Xic`$G<~ zEZ(+kyuxF2HBAtEEu{>lF|>oZJEzkK)-T zBx-=PLGGyt&-;h_!VMcJK>XYNARb@FsxK%PrgTx6}CGqKrEvHOer1Nvqv{ zu(oPS!t&Kb@QK6G@e#%R7Tt69S3PnzBl80k*TGW0yBtTMa$=#AfHCW@UF_nUm^64o zis0r@MsOg)K${6q@u|E$W8}-J9HNm?(J6G6)|lIsJU81VH`=Cs|DI{bkJ_INgDgX# z&PN;(L`;gZl1}N0eYo2onkCH4h8(FTFV<-jRo#O$WF&kF`@3VCBUym9XVcVUFC5q@ zF}E6A$Zc2R6=%DGP!~~^O)E?Rqeu(WD$HU?_Omt{{>}sJ5iFOH`6nyn7}`Iqb~l=U6+OqC;XJQ$wF=QE zv?le&cFcSYz!+)&tvHMbcuWx-qw0nF=LCB66~@~!?bKKAIy(&(l$^IFtEVUv@Up4g zG@s3Cf%Mh88c|XX!dx9cka4HFNptn<5?bXADXt95)^?Qeh%=5i1vE1mx#=naQFISM zd&C9@(gDsI3!QErYJcd6tgm(+TM?Zba+%)wAoY1RD-O#50gyxU8Ox$#k^nU1GZy4y5 zWN@2C9>5*%mq!?T+YL=x)IUK0S@DmJllIq2@Y`%*HJ*PDj$4Y6R-?klcj<^+9KMWS zJbg^b5Hs;=gS5%;8hC7Fm{`a{{g^&NdhOG4-+llwP)92-#S9oJ-es=hvykZ{#Z$GN7l=B@@=b%LXHrmnK zgaErmk&VUI*P!ey=5rDb^t=w7KT!!lyi z44!pJ-J)CjtNG{NCVuYTu&+TSdNcSonV=Qv=VX~`S?6V7NC%b2P1WcHbMTGdmbaH= z-}G@^(@npKRe1bx!{=-}*8mjrsj=F%Q}HaH1W-$1BR1tkU-~HVIzXHbYT_>|XzZJ1nz5GPqIa1AKru0Vl(IQ8CuEOWBlX??w82x)kQHvwv z!c3+h{&KIvba+HC>Abjo$cS8dkMKdAogCAi+=>fZ_)d>d-Xjmy+lt_t;P|j3Iql36 zMt5n=Kh1;f`_)~K2*O0Q4dJ0o!GP2c@IbOuaR#V(^W4(wtsPh93xlmO*m$iSx+F2- zlS$4P3+lthhk@8FLPgwWy#BU^%n=bNsxelf2AT45^jaq3yY{i-8pBE^XKDD024pZ#naG z_W+GA42yGg9WQhQKB;;eML<58guPTne-(>i1x&XK`plvV!ckNw_T_>rL2=8(n262% zc&ayR>-{6W(ad!F&&If6d+O8;1cr%DtTe&4O{l?dcORK862t0MPE5n!G<}`;wEdw^ zt_tH+g3p}|5yHRhLKehm>mC*?o|Y0#T7W8mvvpnY6Q=+PKpbB1 zO!o4(F9?;b?Coht-cHbUPm$y;hqzRkaO?I=&M)N(UW3M7G%^_z->i}96c(lVc=umI!a zF^NSh+p5r7H|Yka>{G0rm&kfWOKqi~H1QYAt7omfk{@7&B@@O<13J~UqG@$j8p5(A zwIQDKto7A8^*S)eYVjn zzM-M1q-#p>S_Dx~=j-5ndeOiYFE*W4#Je_LAw9~-S25I-%lXa051$~*ByNC%;}L`> zD+~3uUVY}=*LQ)Fm(*W;LiJmFoy&^lSAnXxr%R>0j*1s8gj7u25Eb&D-_dfZDDU+MGf$$-=W`XF9Y45*ob) zpoU1b!W1X}Oh37@9(ZdV!mM+{AzuW($CD&+=~`1^6C*o$-&i?L@PSwJip_QdM%(qt4faJ*f2kFh;g3P& z_peVWx48|jsP;F(d{Ak9O}H6dDm#c#$K_FOgnw{oo8 zNUP{IrI(W1tk@eH(0GvR^&vygCV6HiqEQ*=jaJZSIWsk%C;L!Njs(4D33J5@(T%+* z8{z&d%^xEcN@XQ*pCgy1&^ce^8m-CBxDbrO8ak^#LBUG~IT2*7p&=lkT& zyRZ)8?$UZP_=slR7SXoX8jxmPMD*a%ZsF`?(w4RY*`7rRgWM--T___D+n)YUSNa93 z_4zk^8@z`ETs=JvicV`>P^Uh|d{Fln6T*wbPF4M(PnOSvg4@3qANk5UOU?-3*d)@! zGO!k^w%8rJMmIb6ls8Ff!s7A4&8r@$9=xm}zQa_#&6KKHWH5M^Tt9tEP~{xp$b1%Y zlxc`-CNdk*-Wpc$u6I6}*k6-8@Ofi_*TPT{{jZ^`A7-%QL?X$MIxmp=qTvl+gX>OIqdwctQIbe+35SGk>V zFaoggIY!*ASh+D}Jfvrxk$1J|)#&*atl6Hb>;Wk76JF(nYVbTso>G3CTKeafFwVyf zW~6SB{Sm?QguERoU*12};=qm0rHfAsC*OJpF-yB&L3x|&(X9^SA`k-4K5IrAaLnoBacakG0> z5xvretOsxtRq6*XV+0<7+G97E;EpM7DNcb>^IKNx3P|S>JdSP9R5*{x$mkhD^s-I` zIIS_(&d@2CsWR6R83Ia1zrI=(@|DC2iy1WxQnXC++83Q(`7DJGI}FKVBojBsJWbtQhNS#tM6e5Eg&v?2wU{x=GsB(Qh_wOUA!iSnDcTjOLQ*` zL>$YGFckwI{@KqLsL&nl+(ekqrCp{~dy>55VWOTlgmDub&uqKKZ$LIUw6X(0VArsM#lIaofS2_=X|r(2GCfxgoHORRr`>l1D^ctETMIQaf&h(5qe+awYfCDt zP${0|=EjuVqv?*lFHRc+H&@*|m9ZB%c?Dj?EC*eaYEHa);ck<>A@$9P3MJ{ErQBnP z*>H>+q$i2FB&+~wx^251GZDU&xYK_``#bzi(7r!$mD$l4upf@6Fh}qVJL})B7%bP| zu5|cdBw|`921cgEz@dl)R35{FjA-468|cOm-1+$XX~u(0$dHNcKTlIQ6qyMF+ZP|m z+Iceh=gs>ZlA10^q~AsHq3a%lc5D!QC8nd(69Z5#&V+dOS8v$q(-Zv{;*@@TbXcTG za&n0zm|=0Pbv(6x#n$!-^n8CWZt(-{j7OAO5C5v zHyKE}`(&-dA%>b3JDtK|2HlrU%7btiUF9Bu8G?%oNK^q-Yvm5LcX))^=$69p84if}G+wGKr!hO2)9N&3!r1n;m8OL)OD-ud2`QG`C zyP5v_vV1Q$ec__L?3@i^vimq%QK|RsAL&$mo`1esXjb;@;0mb^018F;#CEhF9Q9PC zz_5QD*N@lm-65P0(q%_=+9-5R;26af_hX8{U<&z}kTd;^uj!`Hy!$>b7>2-|x2W5% zyQ=2GD6y7pi2f|v=xZPZg=dq~WnJ}jt>{oc$KiP$dr6Yx!+4rd&Lnn>8B zoAvmq=XR;R>Q2nYRwFy^)JZxzFU)%hA1Ust83XeBh8Jh5Jz}D!yw)@Z(^j6# z+^5o~S4b^9!Wtj6xyu>c?^NaIf}STNTGC{As!Q<+?w7_ObM6kJVE1re-=LyC5GXiqIjr=<6_@D&!khxUI? z9W(a4j4UoOaVl2qq`(NdC#BO!Vu#>aRLG!J3lJBKfhV;CJ|;H#=F#iEko=mlV=Vt+unu@C}M; zbr+Xo@Z=9z_8ZqQQ4$08TBE+ZBcXwj#8sX&34Eq#8p3EY`DcmH;Su0B2Cw(MN0Qt2 zKXRAW0-NnNU2Ha!G!eL1WWEE^8nBPNn?EU6px$KdM4e^nX87@v6B?C}_So-qbET^g zrPb=tUOwg>YL3uCM<1h@aP~Jqa$KOqtPS-Z$)hJ>J9{Pht~hxj{V3e1D_VnfGi7bu zehd2MQS1^w3%S18ZKFOy^XvJV?GB;Y+90HrjzLZOispHNIA-ZV?<^Ahuk@L(i{EMs zyXV~D>+OUzMf<~ZFEggYU4W`_>&FCCQo{y08I#`Uc2>9FqR`NU?HdOSL? zc#c?L1k;V5t=bCT|Iu`llTSM9wF}~FmESBdGXP|g4qL& z8tkk@dUIjfzGe(_@AEn0%Yu{Wx7DT@-f?+-BV_xT`X9Yo9u&mS43MSWQ7X_V7IM4= zx@-+I(V1GCbtkSsg&C0;CNf>Hops)JyJvnI3NTy((3qJ8NsTVl95 zS?c|d1z+0*LI@4}XMUZFwVcqzq#aFF?0d0(0{Q_}r zY~A+=6fj`eP+SajWG5~4w`MwY75fAz$^YYU!7KMX{4uhQ=}%uZg})SYUHnWxny zD}0~|84F5Z_`?OJ6$h`l1>@7jB^5AJ^{_0`fei;La&sJr+HJGp zZ=j0StIpv2rFNI0tOptfx}d)mz>nJLl|EMLt56i&)ootuX-zs$dY^xH+~v&un_~w| zjT!C2@<1Ew2b`^%e+UoFqp|W5OFsEto;x2~%!OvfB9v`jCL!+_6(byP>vwl|^tJEa zV?FMwWgRAv@$#*N&(&v`VgyZ_$kT3J)ldxJ!b~?ar3OwZR$jg@Z6R+}c9u-wXW{7J zZY*gCj~3zhZ3;+RMYi0*p7Q#Y*)-#t^)-IHi0Jc=a$yl!@57Y9-G`jr;v~1yOyj0rWaOo8dU& zqm|A>ptQEud@0@6I^c-0L`3^Uh|gjPJjpey;kXUqWPV!}KAd{B`^Q#2w%i@y$^N^A zG>#>SbTR}Gs^jK4Akcl89jQEfy+o_mgqJ6!vlku`SuNxzy7AZ-#Y=n{1H+lW z^;jl|uX!rJF>7}em?A0HXnf6`Clwxkoxe7zW~L24p24>VESmzQdi%9SnHW;8U9e7o z=uTTbqy|qB_8JM0HkEl?3dk#CJRO1bTgnNLrttv#=O(Ee(3r$e;$cX)LV6mW{E_RH zJYzcpeYjq*7-l`~mZ6j$ROc*6xqN~kmIx%~)(Q3rJ7^L0M$XxZMW$-2k>4{^GV>H| z@%J;F#)dSH#<}~E59;SGy@;(Hs0ej6OQBEHbZ-QA3cq9P!_0IweiiX~urhnh&EMP` zJY7l9VHNQNwgDPPlWz4$1Y`>k&D|mPz&5BlMmq7bm(65_N@VD^!lzIn_cONP7VoDtmfa1%dK~b5l>?0(*e-% zc=f`VxO_fjy0k)a+yx}ZK`)QZ=UDAkbk&Rm{^rQuq#H>|%pc)(wHwdfH=9SIj|I1mTE zjoosE+?8v}<##vCt(>5eg2IOW?U#^Qx;Q>bHVc#0I+Cbg8Y}U9C&4&lPbNd(>DELz ztPDBFD|XFlrx9veKQ8}&0Hk_Y$SLa~$yjDAEmi;d+bqV3I)5vK0ud~`e*QgRv3H*)Huf`WbHAroF&e$b=pi<7>$LY`X?rc9X?LgE(S&(z-tr7LwvlJpEs4x}xXPcd zLznzq()1f~zQ!Uvl_<3!W05IT{^~{_j<8C%E5Q((6GxM%Som{Clf{}L5_}`|yDKAk zoKUmq1m=hX$3@qJAN@n0=^lnj1)P%QOwLs@pkz%FIJw+L4d78(NHu8Xj@m4E>c0}} zq-%`Orv0P58od8ml&OZS${Xb5;_COW-h`7nOfD*GF$|=DvYmV~#9PLd&6{KqMPO*Q zJHBDF`;@&nOS@iX>RL8TzLM^!>4x*-{-|{ zZStl~zCBuM#;GW}74el6CjTBJizGs{Vjm`#uRq0=SKXFmzaJZul6NCKkw(3A+WGz< z2f1tafwqQVxu9%M`TisfGZzj1%?LCAdJXatNtULybXZVt$3oncd_9ib*JN2O8xCL# zUByhb*N^4)8g6G-7%itvBT&((r%@bLtaBU@GbZlB7g9Mi7`%h z58(M?^GERnlPflZ{sDTR-qJjdXQUf1aC+T^o}AC0Qc>q-^vnAbGjXm z@t+eD1M@BNHudx`XZoFWkw8EWsNHjd0Gl`~A z9kE!8nD)@EidQU&u!IABctL(wf=h;_v+sVOpdCuhDfUgr4tI|mV4bz|!Exra-XQF? z9KPaa3+&<@Zo|uz;$#hD@BPYNAOjr)cFC1#_c25E#gd9E@9iDGp$8(jBdm3WYq;0U zh)kE`5>b-U5m4ds!K863ttSHCFa;VOk?T(r2AOE!K*@81vQKac2etEkRgkX9)N8#} zFZ1+*xg=@`wO^!cHA-3oa{t#rWNIV0V5u>J7ur?t7#o!A`-nO5f{;Z|dgzxp{?#Rd1YgvoU z->T{FO4hnf!pF`Fuv&i@!ed|kl+ycl04pP$SRig|_SJPg^>@I5(XhOeT07%ThaDg- z!WWpTYBzs)^U*`|eS&f+e^rtW-6=u(9t%Z3J=j0uswX6uwL|18#t4CfQ9W%$ihbHh zJV)TSs=$xPXT|pb$~NT&PX@Oqb8a`E@1A5q*q><<-gC}PgcP8)869H!^!yFe0D@HK zcE4O>DV9RN&rr-~s|9@1>DHK5?cA78l5W!8O^~}uZM6fhJ|zN-A(ij#){QCmY<5j} zJ}cc=roatc)DET@hkCUU7EZ{HD;Any4Hm#eS2d+=yS7y*$VlB$j;p38v}~5Y6&8AZ zn<8b|TlS;?totp1dsyfBrP71mki3K|e)&umdR_X6p2bzza6@#_YD-ZDEavd_A}ZeC z!J-8HqoZt`IJon2E8qvrdMQ}p)?ZX`{!hJA9k5ttNzGjUw~^bIcrSveePnpDdllqJ z*7o3p#(cqFdi^V%94}n1;cTVUpGyeM+^RRlvuD`> z1o0Y?V7MvdPs2t{v$tBC0;YXN#DA*{7D!V<6ms z3+pC@*;hT6Ls^fz<$dkGVTL}FpQaPW=861u$6P5p3d8Or8UXF znVNibxc5}&&CNzt#Qo=zafOM(T4PO_SM5b-EP+~AV=zot_bTt7$yNDnne7)6t;*f( z7|~JC!2kr#si}@}IPxk~*Fc%H5Ag^}uho%e8Xka4DH5=6W*U#sZr*JAjp`elz%RmA zp0*TaL*Sy%uhTbk-xuEU&C%@RtqlqXn&&PKE<%wD+)%CH4WW^A?-n0}%U0Rj*6QpaN^!zHKGrtlCynbtEdHC~*5MQ5CN{iC-9GI`JRub#R%Wf>YGx*B9XF zQr@?_6L>D^HxtlF;<+*zdRsp}IhCFMk@7YrW}C_Ms8=J2EXK-kHVpw(bT`SUPVwr! zI9TFbuh29948607d?5_I9^Je*W8FLr`Sg}QZfGg)Jcgjx6*Zl~jjBb@}5~4BVGSt?BKHvr zIM+KCG!dg&;^x-9fKiZV5@-${Ai{whQ$=5AdcvU z45sRewj(Z``}jtxWdi*gnZpF715V!t}1hm0)n>eeCW=9MUS~RKm7Qo|4SYcfG0r>3s&B*N} z9$6vBh5RpBeDtw(Wx;PhJx(`op`$Sgc#DPq69OhIY%lLa*=BQ6d>Ai!=@bp#iSM;v zxO{2PhMYUsQ%rPzy9r)NvlU#2hN{!S4?~LQ7fvlTf8*u^vOmGkqmb*#NR;&#ZW-wJ z1Khye11nS_*!CXc>yH{su!sw7I{6Pnl<1|;_Gi~}-&HC!Ur0EM(;>`cB2^tSCX%_- z4=ou3MZ%CDPCL$rC|uyA5!$aEjRYQteoS|gxsN%0VsFEHz=}v5kSabgi0S`QUM|qNjC28|jI=Ft zQjh>;Yc8+BM}MjjmT`L@8zJ6&UG8>@+-T)Q-DB0FtQB~g0Qi7nT91?Lj0zbh|YrI&7AxKAsdsF7!Z7WQEZFQe6jfPk=NVK zB(}XPFt9|vW$oH5_z>v4U7$d(;n7i~{xX@XbGZ8Bxe$!fE@Mcx)fMh)!N#+>>9}C)}-Hn z#&GDkH%B_jZULFi642bZ*14Mn+w+Sztbg`4{&@H{cSSD|pEZ&)2kC59!9jId|9MKB zvldrKL|)OsY(-^n$BQM>C6jMPl(RwqQ;Nop;;G3MM>S;SgRsYzEOSQHAG@;gDBn(# zaS}axYdTs{JBj!2E*)ZsA2dDwQHMTPUhg|WMr0k`%$)R&c}?b^Y!8zm#9z9?PmW#+ zs+9PsW$MYocW*^J3#)h<9o-L1NdsispTK>^3;@|%+bfPbzJ>kDRs#SLn$L&!F!SV7 z-9;l;mgTBzUwot=F5huI{dvKOl+$E%@l-af0FGW^oHb7!g$GopSCAMU;GlDyj;>rDf{lTS*;O7YWphT~G`$c3jv>dU6orEG+dvUxI}?qvDSv}Q|G zJ1my^Q*KLA+JAuILSgGDs>|TF`jC93R5Z+MR+%h!DeC!P);~qlL+%3Q{dfS}*fPjp zeUQs9$ULh}&+>9yvDBmKMt3ReS7jh!o(X+Sw3tw=gw~pm>!KMyF7U2B5St!jv%Mbj zRJPIa_pB23T4vlHd$OWN^-ZmVjw+{CN$}{A$KW9@yML}3pM0D(f~|nXQ0^Pfxv4O! z%sqK6Rna31p>J4>vRQjzXnzti!2|)vgzyv6h}iYqoYXmD^~rtjy9sMkU-Ao}a|*^1k}r9>`@HmW9l^ z(upitTp^6~9pKY>jVkmf$CftOf^y~_1Q(!O~{X5lVt z>dc+rVN0-A&l6apX89dDGE>9jgs9Fd_D2Wk(fqjXs0?O3$D~>Z5=Rws|Hje3rDGR- zNVjNykvYHXkXYaSk;%0T;mn8+~`bgR?9(U45LGCE_VN)8hPvA~$I)p6d8 z%Gm|4hjn0=(b`=NIOQBtxz)r``?i0tRX+TwSLk%mY&)JffKH z=|0M7uwqQ`4qusQvbt7pF?T4rAw<}sx4%qVBDHi>*M($#0zhI=wbm$bur^9j_inIh zkxGxlMvS7m)@rd?Pru2O_U<34GrN72*({6zs9>zJ3x0u=;-}(^fEN3Yo9jfQ#-%*@ z-~Vc!8uKjXPw&&&pHm5#gNJ?ou!h#6U$c}Qs+6n=iLrboC2l~@V+1h*vMlK`lo|ir zyi90n-$B_@1Etb$U9cAQmg;NX14Rh3%V*QaF1cqs@%~Dn@;-BgL|6ZgMaT_S75Wsx zPloESrG<*8oc#OhXXCz5W*bRr`XRN!qvJXh@M~;jy>V+*5zM0`>R+T=Xnty z3irX+5Vsg1v#!OL;q(3CWs>yaRS%_9!xj$MHF#99PSWHS3Jvcx14xnF!>Nwqc#T3> z?3*u<2V>fVC+M1UKB2WbrPc*^)Y~tfsMUM@ zmEf<>WL5v)Xwy-;DeTmT#PEL&5h_w%G?&wU+!oy#xsv#*)w5)a=$G7n2Crts@}pih z8=erG?i(@Y`*DGZ6;pKIVb^!lZ$|`1&&KN&632naq zEm!gUqpwQ9&ExEsdS~a?k)@K@^jqXoU|+;-;DZLr5e)89&Mg?_H2lxUK|2K%s*OAH zIhSuS?U_q9^R-OGcjKQ1Yl{)4SyTLqf*qv$d>(gLp^@<)}9<+!^q~(Mzd|+@VW;@o-Aj zn$zdmzE}MKckbpuv*eMt^-pZhr-{B`O2W3DAm@DIu2GwhnXlZ-n+9d=Ga5*O!2NKp z_nnMC$bA#M!1AOG&E`m|Z>`WG_*H(vc1>2Q_cZI+bbcugdZy7Tt-jHE(tQO&?h5a5 z<2D6#Yh3Mecgd?@4{RX2zp=SvHv;FegeUZO8MWl9IZF(v)<-)wAqb=q(ZWt~<|&yF zbLKvRVo>?eJ%#u2rE|p@FEyQ2(fh&cE-pM2AGflXQ3O)xpqj2C7?e@5>{$wV`^60|r-C8T!Q9D)sl+8&wV{&NeF#JPQ@79w>{>XsnF00=k zxh20h>11x$;uRe*6@L}8vg)ryjGN~iJ{$I}WUcN5C_@&thBVl#1ExsH}*!Yd8~9@I7hCOaK3NJ;e5gctuMm2ws*iaw;iR4 zEZpY?4yYu6rXkBYCRgk3s#n|~LglD|!Pn7k8(y4`@ws+h0FU`!3WR`Q(6K<{ns z;LLp^4?)4*2!bl`N@*CkIF_3aND%vyK;>rR2D{`^3=%*4Sa>6lNmG{5Z9ZbmaJ)j| zyBqok&ogi!mHyMZ?A9`k+(t3vii%!M;!R(hJ|}TfG1A%SH;p$(3@q!BiQHRQah^bcJW-hR3jbwhzahVVK&-A8F+|@t*ER-!P;|I3C3(@{>d5d^3qyo$8 ztb+O!McWli!L876261Hcrb1|v(C}P@7cE|+7kZ4r61B0@k~WgNFh5N|L#~h zWGwNbE40aoyliohF=nW~`rR2^?SyXVCSdAS5;p=c>HlVfPqIqp|8VWExIAEi1H|~3 zl3^snX<;@zZX5bbU>Ggp9h>#GJfUZ^Oxkhm*!C8>w_^4te>$&$@@r9}dRwz)rDJ<> z)YBG2=w+A)?Y5c8(jW{YaD$J}7vDn2alqmEIr<6s=^wB3E>!oM1$)IP0D48H(Cf(6 z)j8Fm)V&m%0*mLH_aGhWzBXqlu? z1KmDf;M?Zmum9A)BC$jt|A`;#`H$6COJuzq=J~#Kv$nOiQZey8#+@r<+fWU@n|gab zfsv9R!qo2K<`ZdmF(!~Z;8BV(%*+0C<>%-c*7xxZ3g=IHJ6sUF8v;$#3A!cpj97cD znhL8egDfrG*yfCVYpz&|u5f2WVFrr4AY!VPcW9!eo6((i0q}y!L4mshkt1(&Vmw$Dov%iIIz7BEkrSr%}b}4xlHpLe#(bW#BquY$@%wLiuNH zV9Je463v%sqz0qrjN9MICFFnsVe*R)?Wf;n#xeiHbaLmzdAP2Jco`my8q--O0_M6| z*zYwObA~lS4iRua@=br{m!sDkC+dWmY-Fr`i$h88J+|cj9lF&K)w=4Xy%~Ls9LdpP$G&-pK_9Oj>#?HvaT`-X;8XqB@=9AI=Hl#jQh>QsfaQ4O5cQTto?=t zr7t{wTfb{4(e~(>C>%MHgH`?8v z&k$;bmVY$-lfM9Ln{L(>JK9VJzuLV89<*Tih`@GoQ#7<69VL$jTfH?Dl~=cR@L84+TdSq~T?b&~k> zB#fC>rw-bv;iq?$6huhtJiKcxeQ&mn-sST^Q2obM#^3$-fZAcAC=@I-uTcR-P4aUN zgu`xLt>|oz%EP@;dROUcM1k}5ePnh=9OTRD9c?Khn_Cb}ICI#GqT8QQ^%sAj7(m*q zyU)Tt7%pE0lp8(#9kOAAFcP+ZsM%iM^&3dg<0A z35Zjla_*-$ONfEB$>$taBlFFY8)-Hm`UczYtq6Ha@k3n;K|DUMzu&$|=42-(L;0Ma zA*$Hqvk|&K38_6YuE7pp+(#2ol!a3D#w?Pr(1=tGS@YYH@6sK3Ju18zLdrP%d`K8q z#bFRRcO=#=vrwAdPSjZWL-2Qk=ykw1%~+3%Nv&@+(iD`9h_*mk?gN6UaKSjt`)$vG zeJtwWMU2)Eh)X+m{^_mdL!qW7V&*_@CmPYRH=qnjW*?7u8~qx7efTnaFP4)CV;-ON za+j{>kd#)i{dec}Q1dw;DED&eQ?4YC3FBCFIHsH3`4JjAK==Mq5~6P4|Jn%lk*t5k zES!4ntVmJNo5%B-tBbUQQ5wtaO!8cw_Fr;=Oh8c+rEHIOcNNd7YXe~2`@0i&@ExSG zL}5aD^uMDz6P@;C8LNuyb?Wp1^AsP_mSiAvYqG;MEqjdKp+LCw{rV`(QjD(DC}BX_ zbTwBMO~lwYEJWCiD~;MHqIoZ8T}iQW5bc^6G{tWVv7$RC$g{@L=peT_^T!w}AxQh>pZ-p)h~^&rw87q~l>~?f#A$Z7O zWQTEZ==wKp582Kd5SaQ+H<(psy@rWUrp;oJccP&4D>_8P>|&v-NxRM6PV^HJa3taL zT`EA{NOl)l)d-p`k&J=7bRJD%3?R0U%96BN*QZ1~D;BsiI1BF zpokxQYX`1UU%~U{iZ2Ojg)>3 zWaEBinOO0+iJHx6pdrd;&BxZbqG71}ObVIqMyWp&?axr#Ops|4jTtdZ0hADL;vmM+&u(pjAFpDs?g`1;r~7oRj2E|@GDWN}Ex#7XPE zteR9`_;L}+IVk_5?e4jzn6bYFw{rDA6zE3wV$&%8tY?(V-Gd29DQEqI9odK|ef`1PMSDMRG z;q@K@Z67h5XY0(3U1AZm2o=B`RL?B+c*=+d6I+3lm=m8@rP9qnkuI8!iK5plO$4cl zxWzF1cm%?gZv=gEAv~hv{T`KDJn7>&OqZ40VzcTP#QoKo@c(#|oUW4;D7{f=1#7I0 z42NNG7cEIuhiedmnF>$r>NlAIaulwv5i9Wh@{pH0W`za zj_cg>3<^}$><1}XT-yYEHmEOJnD}Hs;`>8(*DBO&0|6B7Md;2suW~%<_r6K_BPdDeQj@5lH3Sbt`lYp!c%&ht2HKlY=ZP*Dxp_i>6d zS8m*sx3JzAo2^6JUsw2!{ZNMXJ=mA;>R=ovKqGv-x2B(f!5vN+J}6acUX-7qp!jHV z*~@p$;HtfWaP~#t;L&lF+-i zvyBQQ$dqfv-eSSanUrilpo1@q7zUk7L>?$d$e^Hi(OTJ|w z1TcU4Uht##`Bh)~*MWCd`GKqDyVYdI#7fz|t$Nlnr0MTwOT1>EAMmzql-w)ptR7_T z`Pj$ANFld#M_7U7F69Nu|mm=Pamf9nY`#a&@-$T5TCYu?jnuCIlWNv2K zYxk+g*ER>~x@a(evqXnNSJpHasQvTNv zMDvGn0x_jJY0307@v*>Wdy_Nx;>zA)3jcX9&mv#svHnA1H2qZ%jL5{lWXstC`v%V zezPunAd#AGq_d;xHafw;WHc>WNDFhoo)7c0p2F~Fd#P7d)f9)OU(pG7 z9`N$K6MytB0rim{ac>D8&befq&xbNPJ>W^+c`w{{x`<}ifg<|RJJKn6WfoSDKsi$k4 z4t!!km`n;QfqkyWT{!kdyQvTZ^)R9(w6jE3K21!qFz6oj$@aKl*1Cr=p9fv@FD^Tk zpf{crA@4ve|B`54?BU7fR~-Anvp!t<^BonkZb!!`P7x|L0zEiao8bg>GVt?6RM~X% z;9S(d5}GcF5XNCHN$Vw=G~Ze~VVCOAW@(pcTAXK-QT+3WAaTV?+X_jq9u+)J&nwGrgn^OmqoLF8ZHRKa>M(JvgnawEflT@=Dr~HN5Ty&C*?Di(SQ3~w%w!*OqxWH=w zfH^2P#<3TO)E8zJ6$6k{@#P!K%i;I!R8l~8-{dkvsQA6@fM~9aNn_d!-vY~@I;53sI~+= zZmh%X=NoQcDiokD6@9zD+t9rh=4O1)Z9^x=PO)-`m+w}v_4xJh!lk^t=Ynt6b&fPK zheoJE=!XP?XU}TazTw3Xes=9t5U3%xkfFlC!B_iH%iK2Cw4s6+avGjCvmQDgn%)wg z9(VUD&iqOt>h+S6@}-T7i$=TL4aez`?spc`Zcp+XzC7pgJQL(Vz3=WR1yONEthTZv(w=b~MlVC@lmYs%2EDczCx76^v_i1oT4 z#z zxagtBsVfr*X%-|gjin&0vkB0W2?el@8! zX49Ks&Z4gr=BC!Xj$l~cP;ax`do*l6XdU<}b>+;#D7B2T&-2nhhyZc>1!?+1#o%g$ zi_yF5ltG~>W7oa;9lw1IH}Uow`X}oMM@t>U##&jt{kHJ}?Tr4F7Uq=%))U*U8*HkM z^0CwctWX5Z`5qQB8Ufa8u|${u@p_BkIGgJk>`4&ZDw3QpF+f7oM1wRyyuQ*i~OvG(b518FK%AC$r|UmvaMF%G`DdQ6LHi> zOy{-&W#(&H;5pS957tuDFqP3{tynqd*_ez6j03rK$iTVT+`wbpdc$xcZSYXo60Tes z%=s)nG)#9L@5svk=3#@vwz@< zT&$H-x4hjRmi?$JU^o%h#z}hU%*g%z;f8&TwdZl$o75|dYr?B0!z`JB7yqinCm1JX z2;c~ER7;+#ZU*9q55MEvv#l7yyZLH{e)Khcr(|vSOq#1sU`r74-p!TS)OAaP-B14S z3d%F zb7|srhP27t-Nh5$61A7sx79zDmGTrDR|ENi!A3Dl!pH!)-h)P@6F9c$vNfea*U4ce zVM<~EJ~y=Gq@%0TuSH8fZOn1{`ruUR_62o!YeR>__L#oRIG=$YNh9Bw@F)Fnk~bR@ z?(2sauw2*Zan>*P^-II+j|L8BzMnj^UJdf0&oOrpg=K7fy9QXO>iPv7BxQ3BJofsK zhe)1A*_C5#JlcYD4^3ziIOLltC`rdeRpDV~Y}gNoI0(kpd<;a28&>qa)y6 znITaD&h$6YyP&fbLWGzWGBs@2f0AzWs?>s&zwR0mNfgc;8)3mStHRGD3m7asmjVNf ze~7&sRW-wNwiewww7|{uZ{ve$zUDW&FZ*+;xK`yYh(-p{5~IL^e%D#L6K#=0_7m~< zCVOpvM14k3?Ch}GV6Tcz3C}Yi21gOea_1-CUtR|#l_eMY^zdD!84sXb&`YGY)_EXU zub1+y=>NnNCr}z)9?^mDvC(mJ zYt=+q4eKj`%vh_QH&TVvye*XH&Ajf`&X=NrYgZzPTOZC(%16)c^>liU_C!3nU*Tl8 zAm{(^jmyrz7V#|=DGW@PeC|z43I0ImXn531zcUAQ5z4^t)c^KS6dC%V70ZH6X3Tun z`wL22>h`O&ny|@AyqqRGc)PNahZ%mA9_5O`TEC2LZQf09WVvu?&QnITlpo4p$?D}N z^Z71xx-BAA2j5GWwh0}3pRY=73$>az26f_UPugyQ@J$-OkM2Znucq1!Y)L?_?TTY8 zOYa7B`nmkumU`>K156h$)z@Kz=P%r&sf&(Li_^L6&U+O*ULVIf{#hxm9gkHCu!~Kj z&v7U8C6+PJ1R19bm1`>;o|tpdn6GexEpW8rvFm31*6OI>&?=*AHFqO8AM{p-<=O4P zdfDtBzE5?rbbHz`^|%(W=9DM5N1c5LlewwKO5YekHUbw;x=~YO!T%;YIaZDD0OP`> zAQXMr^^G6n;YUAO!5@$9=Yodb&2R-tCkIvtd4ddrl@c;9*)ALrUK{>18aLv<1 zbFs&IwT+yTXg&{Z=lDN&w*UH>3UR37VcT&97|LFfAfvhIklZ*#eE++vPN~!Kk3H*f z3B>b_t@e_J1}8I6G#hYDyDesC4tUI4C<4)1FtT4ueYhnZE8-{Tr8)#OgbukX;g)R7 z(?*vkYMK!3tg+ReRIGT#8VK^Gaa4n_N3LircPPYATcS> zI+IjSDL3A6=0K_VwXb)M2Tn`?ev%bl!mg6d?a+Nzb3^4(<;SPOMnL84=b&@DL-B37 z0D%Vn>lizosMWwC?V%c8TucialeNZ~+m*X+^n3n)vVs2~OW_Odr~^a98Z`OWK3&Ko zzt=MOhC^5pGda;_6@1^FBlco11Cv%YJL~Ai$Am}YGo8lAIlYrM2WUa3yM9or#T>Fx zu=N>}xLY`Zz$P@b*t<--g>6)JOa&VQ27_(yH;Iid8pfKa9unCZ*u14um3%WlbK+3e z_>PfXzmyqKp|kovL?o!%0B1Nx;_Taox$R{8rWv>OGxPG>DU-LUw%h*U3!qtJAL?DV z-6eB1irCz-Khn-0_E@0WpVlshsPp&L_ie9>oim7H3=6%R)Zw`NtNp*_9BMdzaRc&% z4_=Sl-b@0C%w-Qput7Xlu=&Z)>N=cuE@jIa56|=?V)o}CPh;P9dedk6c~&1^+;x5%^GAV0MZ`RUP)P*sckTU(eLJc9PSt^5B-P-$d+D`L+7D>nt7YxE5$WN zeIrhAd6DlYY>}EBSU9-9+Tuq=J9iD(?S<-l&*VFyi@)K$|8c&Xw@C>Bn9cHO&5W3n z2}1q-%W9ibjGo5@pmuF}zqNvYuoS}Y#W+JvycYu6}>w4M%BqT!j95J}@vW#g3#ldu2Gp0E~7 zM&pX8ctQ`z`jOQBAu2#=AdK6S=ACxmr9p=~d{@}QH#lZ^W2(Mr;ADy}yv(iJ39>Ay zGS^SiB&lCR&@kLYa~~7I#4qp0Pgh2$wl%t21j8 zpU5|dSFD(goWR?MXI5>_YIUEubjQN^_2xd%QEBuz3v4e9^8WYzx-8o$r>r`1u z>_$%)^)iv6;wuiui$gdgKga|mVo?E0$d)>x-#H5mKWDG4A7Bg6-W?yq(FMM6deUqq z(%~XCUr}eb*mQN|D3l-GV4qZ0SZSJ78fI)p%iB5tO7l;H9`VN(niOrvn7IoP`)ZF< z!fcQ`q%IUYs)1}{-M6IAb`A4&B3s-HqJlRa!trZpHBY2~;j$rLw2|!jrkeNpvT^OE zQP$*$K#0s$6b5hdI;R;ZQP;ww(g@{M3k=>zA1?Af)w(o3esv;;jl(}Rm*=!_qoaqkiAqcg=C`vf3De9^o71T}MIY`rZ))8JakX%0; z9-O`-OmOLAd8q_>QmRu3z2u~>-<{kBp`gp^w?7wRcYJX#H5pplh8)Knp>#HXJl~mi zeHNHxL}6_jp1a_+{M2{w4mJ~eKuC-Ew<$1A22z~lvw?a*RMOJhr>jVQK-i>v)3CnTpq1=Ot0 z2OHnRc2OAxO{|?HVz+K0>-D+16KG%Nc{3mQB>T9GZO6d&Z6}*fuvv8y$G~0|zeAv8gqhK)$%+K%G!5x4 z5`d6cEbMGs%sv1o$pgT@kuPU{93D13NivG|z5^9aVsy``e^Z_8oEx%8{(t8<4g{-8ErkgV|VyU)s2=`b1xu!$b@=qb&K}wCF87gi^ylo zI+5yt=h>|QW1zpwo3wRVd6&nJubG2PDBWyksLh%wjW<2gYn!RhzKb1O;J5E=?b#sb zO<5d*`P~#6w7C87PPV6pKz4O~Y9zJ{4cgw<*!*2z;<1n&4*`Pq5wvHAeqp>%;+gs> zn%;NBNmn|k=E#T!xj!2%iPa4dr1TS>FDf=ui_Th`ZtE8p`Rp0nby^tpkz1TIoLD!8 z;-1ImQmGxNgp&sVo6U{cLVko0H<^ZO4cS1XR}uo9n{#Lo`YKg<-J`_Rs2rIaced9e zbrhP#9`%?P*Iu4$)QEgqZSj9IIiITF{Z)J*a8O{QO8mC5r(sj&^ZlqK?raWZKb^-n z-ZGvS1n|*TvXc_FQmF~@M*K3Ad(pO9x<3bd&}rqj7OvwJNg(^|OZSD+8FU`3M3&Fx zcX}X>?*0K$<(Mw=!;`=lFO*IPJ#foVQTz6Y164yZe~DLAP0Mj=G;=_4MEZKMEWl}z zuGtWYx3ZkPyfN-2-gfAtWHVbjlcZ{>6JL1E99xD`j?_+O03;vJ4fq@9;SBx4a)cP8 z6T?))jVIVOr!fTBOG*%I5&Tl?g@cdt>Y6uH_pR4o2^UiiAJHRe#aKc5njU~%m-Lz` zpIB~j(N9^Z4z-5pggk+0!Fo=wNyS{{jp=R4uA=D;f(+>&(@`EQ1I^vaiP zYFV;tht$#+ES^Y^w+7=RZTGIHef2kjyXK-XsAXB>AT0enD-ooXG+cGGq2JB)?go6S z!2o9kaYq=_rSuSLGxa^t2ECdbiZ1Z~jD-1gQw2k)w_%fB+&31T4A;$jn|H?li&Fn@ zIO|(mrY)?RlScjRREDP^s-;^&qpL*Z5T)mlBN}H@FaSD-E>3=MsqcGP22C)R-g{Mm ztNY5nIwAWBhR`8dd+q|m46<*uK*=YPN4LcJ%6oeT@frnXh1>maJww zkVx79WSC`KO4)fPU3~n*K^ZJ&iHm#J69F4OSwDpM9?d}p&zFH|E``PIIQ}&&kX5C? zh^5}R#uIS{_wjxEm>@;k13Kt}iTngr#mn`$jqNgsR|Kb~!H^qj?xEu&9S(zv=us}^ z&2e-mj1EslS6dwmC;2Czv33?B>3c~1itJnzNp8m%Ss&xNtY2ZN*Vy*hXBL5;;pOui z`X>ug%aM!B7j2mBs^ES|D|0nK8v+(*$~{&2KZ3$LL&q=5aAY|;CxR`W;GjHwU`{mr zI%94yKD)tes4Q^%u9rQ6(-4~ZO5=x6(M@XUAkP{I97$B@C zXHPC@wVJM)KA&FFo_`ZtYHRw4Z}vKEOl4)kP>;R znm5|}qTWVB&?8=c!2s+tB65L3D@6XaIwqCe%6RQ2_^d)*mIf?ibFmYs%<}UWp294! z)Z^yIUdFEs?Wcvtn-5z!6P)nwhDp1XwC$lH2x@0)I5ZWVg-Wz45TmBRp){jGlz#AVz;({HGjxgx#oD7 z@|A~HXQ16RRE&x z>^7v}tzP)+AY>+9uW%1rEL#JyHM~jTd*HaoryR2u>o<*X7u(w5_+}$H;_Z-c<8+y_h{)|U_Kp#gO67T+T@>2HIou*tO(7CU@TLI%mrEj#~K}Vy@ zR6YW^QL|FdVyn43c`-|ByPrMr_;mfwj5SFP@6i4#4+VEq4QHHc$J^WmnR6sK=Ezag zB5;^6#9bF^v!BgZ;?&Ku^FeP-iPmeeMcrn{Q7v*$&CQ%~q*8{HsV^plk{c)BeB!D< zQ^YFo8)Zmj_<%IraTaK@4u4k3o6@!?2pkl127W{5yrsD)_3|uGw}s^;+NBbWg)@sx zKv!J{8LI8$@K8+P+rkLqvetnV(b?Bn(Ir z2>$?4#KkFc_9oqy5ql;eRsaqhPFV*IVhCwn^XSy^oNt;`DsF#)&T78ND+1Uhu|5Nf z(v7XiVYTk5w?0iyiSfnLckrYTf5N>$@7a1`eBhPR6_YRg)|#M5No84yeZKxFp4`4* zxW3z)ED2$hai8O)aL!yR$KJ2ugy`%VvY0rgDlYH*K|K74=Wg9_f^YO zEcssCq`FrFHy3)GNqrSHdqf9KVy{$k$A`{e7o?Fs`of<(9$piuF8?sW=4Kx)IN7&) zMyujV+yCmmBR4<5`odL68={9JA(kJPujCocZdm!i(jJb69!G4IT$Q#9U80nli|PI~ z8&ecv?+Ob($J@p*;#4bfaTJZXUGT}B!t25(0$(VwdYA1kgiq9Pd6w-2Anp_z-(YCU zPU+O7U{gyvn>cE*5o#-8*I-z_+AvcBoig`QAE;m614Kz_|1eDeoda!y-l^5VrxQ-f zKjAFBG?GHt>z%Z}@@=ctWIxd^#*&Ese3~_B0jKil^OvvIm6w^?7q$dj8JZSDV+HMk znh9+bT5y8%O=u!S&1PC&*2|-UYMD*DID#@qi3(Z{Q_JeZ%AAgYfg7}*rhF1{rI^NC z4X+)29F4TmS!60m0wik!=Pd)d_LcvHfV!_hpn%`52y{FP)rAU;m90OMB)=C!0aezN zHapwWwe32YEDdT*(9LC}Rr!2tqCg{#D4mq2>C1!N*r?7cJ{iq#bkuG*uazU@_2jiaMrUX zq-YQ$xyC&Gtb9Gru#YrXcJ}Lrte+3_*_ZhPUD1ha*I=RYPp6f_05XKx`EiHhB`=n2 z{A7f1$a%N>%zliH@3VZy?6fTX{Kh@frZa4lm*QNY&>E@a(qx@}u_(5~!1}6$b0)$+ylvI4mmF z&6PBG`|8uA`|a++qB9&cR|l-MG%y%o{j9ecNROiIwa1Iv40?&1vObk1zCTdo)AkMW zb#OQ)io~Vx93rWE3Z;jn71%yOEiM4rozsrrsSA78o|KQ_ERAKa?Vr@^w`rC=Qc}Vz zG0=1H{HDXL>U5$CM~KH$*QjUCDw+1!VhBarLAoiu@v(?i{09uMmb`4*bc-CKGnOTJ z>O&_@z_x>kKQa2GJjS%esQ*fKtQ-1?5)#lRT!mb}CH?59Q^i6+o$i7W5qKzG7?4bO zT16TC5qk+uXbta`T$w>^ToVZ>zY&J?A6o|2t3wPg^App|n8GBcK-Q`xu{=0SgikXv zjA{lAi{u5L;2JSvMGau^mVRtkZ9Hi)SNKNE zm0uJ7y;r;PJC~A^K&(%nF!8!(A7Q5TLah$SDg}Ses3DLL8^mE8n?37e^W-nX=H4+l zXwA`B1;8;Y!dV8Jp<~w*lAAf!+VPVtGQJRE(mCxN3xBr6=$*nWvEeqeA!)Sg(JOA> zngnvtj;<89Fr1yP>x|Cq-QDKGdGlpM%>9{B&|>10m+<7rpEM7tR>~l&OM>V2aGY98 zqk;cb9PNP0opuAKOg0vFp?KQQHPrMLPl~j^9WwV%)I6>VbNRu%WtvVJvYn^{>94s; z>p7l;`oUZ6#wlLIeYUU)$?ovuJZA_`M`>Qvr|c3{E*#O0jgwkF9Us!!3#9LCd^}32 z(T!64-ojvEIin9#86LMSD z=SDs?$=p>kI1xSip37_7(n3FJf)UGtFZ%~Z?+=&e4{sIVEG00m)_yjSbO3+sEIF@6 zds9U3U?;QctS6kXAsY+3nJZxVA4=7PSBxwf@oPl^8!690MsPdrmBT*K&ca@;47Y?r zF9Br$hxIp3_j*Qm00+V6F%5;>4u^4vsthfL#6Zk-T)9uibrqA{Bv7|Bu=V4K3U~1q z5$I*Ei2u;z6v&RshG*&S6`q};`T6&msh}TU(2hcL`9yS{@QLD%qa_v1u;RHFkL=|RgVl@S|kQ8Pb%L${YV&@jM}DKO|Q+Bu=3(+xG+%rR%jE~?{y z%>?3EWXN;0oNW{V-J`hCU35m|D2TiwTj20~@n%=wI6n<-wiqTmTwB9!|HaPmg0nX{ z2Q2If@~Z7*)^}VjUJx;6yTmZMgx7%Pq~FsMqeFpp#pM@TYY+l#&qG{r;gDIRcV_bp%SlO5u4!bOX8ts9 z`9j4f-4{xXvzC4y^A8)w7kUY^Z?}zSY>th3$8053W;$Om2QC!j?P$avU%rfO9IJIj z*UI9kFyhCd{~xLHUpKfqu%2MLe5%;z2DQv5)~cE|zmzZP6aO?<2cAePGTi3m50{2t z7wF|q^B<@|Dlv^4)RkcZWiMhH&J|u3gkxX8ujX=Rd=sbH+NWtk*vtj5p8v17UvjieZ(zvuF9|C>u-A%45g zLW?35g3r#qJBVkvbOJ;>7|0T2OsJz^A>K<)s9aXA*DgXH#xDin;CbC8(RqLiPJDnS zJAN`kmOij*%`OVV_CQ^KiLFs_OcJhb~);qCUhmJd{ZP2 zC(HdPU4n>UjDSnlcC3YY(0otT4P85bd+i*ye+eAi0fYe(}2 zVImBjF_I7o-t}UQ4UKaAki)e@zttF>11kIyi;eXH_UjM#tW(QQq6Uhl_S#EyLYhW$ zO`2laDn{E#HJ4t#+KUt%vR*yBlf6c!Pcbb-YK-AjB9C*u9Ork?AZ7wB#MowiXG_O< zSi0qJuT3_XB3HY)JrQmagr#E7qoq@V*6D0>Qw~i;PEE~d4Ka}9vux?H<;Li<9G!1p zXRT=YH;)~I0;faVb@B~v$1n;}$3?1P+aA$w%905*iB{4vg*A1=OMFy@_#uqUl*n(5 zy^(g^P6y`;7m?i$@b55MXt~l~f4}2;*VBzPImOrtr-_qcR9F zCozN=UVV0bLm7o>TgfWE&pG@CK8Jjbe^kWVU1oO|<>@i&MI+%XYf?zEXjFW@C7^@O zBBT=Qq)&V`#y>R=bo6fmvE@K3Mzz=i&?|Or=Jf#agaRJTD|}Wo(EdsZRZZlbqHY@rdy0iKBRqc zIoEX;{tg-)$>s@l&7STCO4~cTD|NPr>>1&YvHyzqA2UNh`JM%N%64JVHl-3^0xhl-TCRtDF?ofJ6#^ z(_9{uzC@FSPHza$>Ow@k9igEMKV}({!~n^pOjPLM;T?5}>HS=;W*`%j{lF#3^cX)}(x}gc|xS2AG`7 zgf~j;>OGdgM#BPPgqcPrXIsvVV&27%8EWCu^zNVKKe1@v|K*g}e?OO(!g{8g=P)%A zuU%0#HoxJEdM)TZTe8hcH#UXAe5;`8NQ^g+^XayW2tP6FliO)i@G3o=;94V^BztIS z*F8ysQjt`z;DPb6_3gOQ%Ww78^_<$1rMAz*hLFfo#0u|$JlnnQ^$&-~{C>@&WTs}z z*?Z#Udfq>s3@YJqxGWVwWjRg}ug$IkJ4+5|MW8lYz&fi&k&A`h-T>TJTemE!;Hp5( z{t2+|7pl-AeKz^vd6D<5HNu+TviG}9xPe_qc* zi~j0~LIr?~%6S7+hTIHGj2Dw>AFD zw*BAVN#Tb^Vbr@QuuyCBelhVUF>DnvhCDI)%#zLN)WRlUYZ6!h3};7^D^ib<%13BD z+|*u>J(-hw>RS~Skicp*$9>8sFS?aKU;33!{IO)Kghq#X;ba^ zoU)n{ju^A&MCie~zL8AKoxIhBimZ_7YJPQJ6iT@z(GMhUFwc6>9K7O zhF?0ETEiFsdPhR*R3W_15w_2_m>ma`vDSjED{5(k;}<*Wvo)L?%A-i-DMPAJA_;~K zs$*-WGz;UveCvm~Qaw?WAfFrqPr3KP=kdfE{KNB`2#eg#uYMn{9!`K-+8k7IYYOxp z@W$ZvUSCm(_|)h<-B5vY*p7{1jb2(=WOC`H@#&o6Ui;OnhYKPmMyE`_SUN!~u4;7$ zczetoZndY%s1&6V!^MG@6~Q@IBdQ1dlR9zNT`NEQ?I{ zX~WC1w=r^9^*&wwQwbvO&p3C*fKopUbe~s1VxJ^)+ES#+)bZP$1y!@~v4yG8jUBhp z;68hEg0KE&QljSBg3o8&gEol4Yz#RSk2RWMQG+hDDVC8wl3kjZt<`B-h!vObnQT;U z3I0VBxfF^9-TxDh$_Hkl0~kW%WEV0)Z5+O0ZfyRte22CAq4x|SO(4&uBKN zw*7?Nhl?q~koc`gs75wEVg{6d^^6^_&N(72jcPTWa$9yCFgMbb16K1^Y>}_AMm$H# zM#>jr%c9v{Xe~pp<#$5Tr=AceSVwHM9cPD4A$KyIb}pyLMuA}@Pyuz%R|^f?XfLR~7_J7r2&X*AV4+avp2fPdaYxJ`k0* z&OA{ya{3(&zMC9pP>r^CGj)J%6|!u37>N^Huf9i~#7WZ^XTUz)5Ln(eyvi|jigdD1 z@-ta(C9$=rF~=p}d>M=1TBS!*DIC{7sU7yM>a~UhMnCm3sNf3EV|xiPJ3)X)uZZ73 z#-XKb(IVE(MLv7`dgXYP^=(m{x!rpfhk)TryM`9cj>xACQD^Dag~eYdzE#^9Bz;ir zinVABjC*x+gcg`Qn}SHbgr7Qt{4Sq8Fn!u%pi_}J*q@J)6W3^zt-J{28E@orZt%_3 z^7pP|oJ^xWn42uniG~2999@OK12P6-FN_y6eriQ|@3kZ(J27ZxD-Cw68E}|imyO;_ zuYgjEMPG@WqMd%O4fCX57;;&26~uM2SWjNvoY)^*|4RCi6gtl*R%dv&`#^+sN|#m=Sf4tJL7=;wrL;8XUp~5M_f-`Zf`K zH0xSNF!jMl=-5< z0YgYpm*k$-jTH;4`BWft4~Ne$ic`KQ@5|X-r7-sYjygkcv&S(4n8!)8pXc-L_#GFn z^wme08zkyF7#E-GW6?))^2+>fQPg{(2jE}?SbEIgGQ6u8Uo4cr{5~Y6MKGt!`?N|o zgcn#1Y0{Oy@#3S`JL*w^yhp#>|328-gQh%yzXN)fx1%RNxkfeZigKm?)@rp#BHwle z$#AXK)0VmX8%8H3yrrMgls!+JHR2n-D8l(EFUfadm6=A+EbGcL7nq5sVN34w!xfCD zwwrDWdRlF9yOLm<>!~d5mH}hruDQK}a=y;)7c;wi!mE5bZXee?W%oZ+Mbs?+vfbK# z8Em>IpcfKpnrC?pHdY-N-8&8QfG_FpMCgGO=gOW)O4_VG%FD%IFrHe*)1z#ZK*RC9 z=L6K74*+EN;^3cbM+BG7(E^d#;q%5TZ!epEs<0=wdYb~`C+7+994UokH5BwJQg@ki zX=zX^D(nKUGrMjsIkd*?9hi=kK-fJa+D(gk7Jm;F0B=V37_V_$q#iwZaX$H`cbUIT zYA`ew2u-MxwaHVaKUFU1%RgElKn-V8z}=S~BVt|D~KXshf9o zYQWQwn^VT@V=~2Ts)m#dr2n`4_kzr11?0)XLm##JlU$|z>^jEZ42Pe${hbB zdx}JWvC@N4plGPKD4&ab3t>N(=d5MqNlMg7evoH#vk8vB#WlA~3?SoUX!R7X4$CZY z>}inxnCHfC-VToys8E$tl!CCMwLf!~Q}GBb#}F#ip55}l6y6ca;=UrSeDW*a5XvQJ z`O_eNf!O&+#9`glYms5joX(A2*K*WkqT#qco3|1H0R>6jaSgDuNlxA1-5Wx)@^>;s z6=u(O0`J-BI6f4(FLC`(hoC4O17ipqWOv~i-Ood0W8D#ib~rK^E3u3W*t(>~?+gB3 zVrst~Cuz9Gomnj7L5 z+m?GnUL|okuT6da7y=`IQ#4caK})Wy2_1>r2)411oqjgs0(%1MBS9V%smNMFXfgrD z1;NS_9w#r)tP0dLSvC=4Min#)+Tdz(i4#z?VW4^@tLh8cmCqW^Oor@rN9l`rT5f4KS?r~#qMfD~n;tg1nwotl_G5!`#EVG(aM^l0wD(3< za04&nUB^mLj%~Wxwz*o z!6>M_NF}$L5dGUu4Wv&-fopgNIw>N;)Y^-cmorGK3MXGKWwQa8&SrhV&~jDZUZDTh zm%aj^pA1>!(ai28ywSFS_VV}}ri+}V5(*|odlLV<+mk8$u-+`w-+Q}VF53k(CsGp)Vg*L13lb#&6Z{>>|!3i>}rf9_$x(twZXSxR)yiQwLZYKFeA-uag ziNNb>)c7LNclSjQPL|yOVaOfjUiVoyQ2jQkugTVM$G|Xr4x?TrkpQ(YS5D(BUv@xY zLVjl(Y?mq^QS+EkWr#3fm_O`H{GV|`|DFFKGI-z*0FzS`D`x@E4u)JFZz7&&OXlQQ z#+9YSub!97fN_7uEB5n~Yy5KlPGM+IE>$d6-Ze1Q8LkJmnzo(ey!LgJCv^hPF($t@ zs8|%92lWB%eEV)-)j0>$zD!bIprAifKQ6u2bSQ%wO9%&|w6h)|~Rn(Uy=s=$52SH=-@Z zmNQ??*!_57RbkvAfjmc%++wP|VAmm29#yMcN%5xpWqkN12m{5rB82HQT;BFeY-MyC zXXzB4xzD@Z94_6^YHOMFGLgT?i$bmNsm5Gimo;jC3uH%NL{O)Qr&z%IM+%!wqJ`Ho zh;6UoYhMuTSfPYBD)t}gregWan1|eu9)lO9Ei|ImSThpL>6PM@#Kre+%{!g5(f1{SAf-r9` z9k_ol5xdEnTn=kI$5j*;Ih_mgT-&F>e+meVppUDUd{!Yil1tMjoOc!BdS=Y{CoADM z0Z%=W0t_+fr~Qdd<3CLtpY_n4X=$yA`Ad@feI(7}(cy~e=C-8&I~e-UyX~gvQ9C{# z6ZuP>`CS7JQAG>O;dP8Zn#*+_wxsMjudH)Kfzp4U-AP-D8@5w%|Pr|?nTr7Wn^p~ zFQo}^`eaeH&Jn2ZPFh#;QVqhS?%MZUp!fG*Hn%xV1DoEqU2=#WqMa>Mzt>h^FQez! zaGzmM*TA5(FE!Dv!8lFKw~87+oP8s2w35yIEv-y$TL2eo918{;z2{$^9FZO8#_CNLx9jE6C!nzQrgTEOJ2KAE-B^^C1Qc2D86&${U zvvm6O0h9ULWr^zxcjWOg+-;MG>o4dX=ttV$lHI~tD$;|N>{edO^I8qweq&tkA)73% z=eY)tn{sviGE4wa!Hj28)M66l8x%I+EmDmrPd>DUo_)D4iL`E1e(5=`Dp=}g3Snhs zeYk_eu{l<#Oi4}s>dwTcTd@^#QA#0eYinr&j%il))^9~6xwvw)iq!~SQ<=#qI{zhw zryV=g1>m%=)pl1eh>DtWvf)lL2_<#avNm5tdo<(H6K|X2s8Uw%gx->y-aoe59`|B# zlpBzPFT9X&olJ3WT|KZdi((TW&lOfwUx>Ta@NMVt*~P^QqIu@-Ygt#Uza}Rs0?hc` zg}pY@rk&7hQ%lSEqu#Rz%XJUA&NjaiaY?(FWvz|v?ePch&0ec#*IZjXzg2BDIQIJN zj<&9Dk-Eg?+dZS_X@cwF(f8+)H-dzX@%C0rL65-B7flMx!45aUMLhqQgmdjjU zwG!0v+KxSf27^r1isRwV47wTQbWu8?O#x?BA`9Colq+nmJBk6A5fBejR?2&Cp#)m!m{c^hw8QWWaW+T6t`c}xE` zxw~Z$@?wu#`26^J-2Wi8KdiXW+idsmwO{TJw7->I`a3uh@xA|QX6Y8jj% z=2di~jqilg7_HOPlR(2Kj7K04I+Y;q+&K7&QO$mpBY`Tw)5=tpq7F zH+B2IZQcX)Z(+H*a{Z<6&gGzq52umPwJJF@Lo>JO=Ptnd*Yj=2pfj`_0zwII-49{I zc&JMJNDAx!O{b|ymQrr~x$J*-EQDSP5aSynbsL=?BoXkD370Sj)A*?|b<|%HnP3Te zbf`Sc8_Gw~#EM|!LPj*M%fNphoBv~`wWI009xwm!VYJXffl7d^Vok{F&Uv#Cb>#OKANswffcrbF`o>Xdh@`qKBAKsvzR^%@Tm# zeKMTCbol)%3zogd&#X*fLF;_XznuPv>!ut#z}xzb{NjNSPuV>@c*{b+Uj=VTEYrnQ zg8ijPc98Z?9N2UeVJZyD_K4+9s2KczTKmqZCbMq;&;&t62I&H#qbPNx3P_dSr1zrI z1EC`|G{r(ys+0tzw~zr6DFOizP>>D@MT$b`5FsRxP;&F$``!=l{AbqX!~gk~XFY3W zpR?O(A}^|(FgR~os=FJJo!X^`yrOq#d2;qc_*J^Oio4Kix!+)Kt^Z+U#>jIDvfoa+K= zW|)3~cN3zCc{RtKf`IGt9veCf@9Kaa%Q@C63UEKr zrXa5O##T(rPHhN~jD2$nB5?IFpIo$I!pb%10KFy6z5Hv7N5iM1h?SN}k@lpDbnD9=so|DdUbJA(-2mX^M&u8!7B8OqAcN^Ka?D)KU z?-yPy%*{KY6vI7&Yp{5VAIdL>8>RWg@!~w1L(9BWd4?)GtluBGYaLYxK{j|tR+2l? z8_q2@q?kibVh-A(Jp`J>MEjM7VMl&O$qQLY&TEqgv?X@ozHJPPcBkE{Yw!+R9;f`%goW^=q4*%u{%;mJYBvu!TZZX z6^24`R9QF?Td z_@ct^Hk|?qHw@<9eR$RPMIg$CE$bz-orMKD@umI%ZSSY+*Ir@O%YHt&$2Y~S(EpQd zI==Ev<0IhBE4MV_@3OyQPdC(UILgm;b(hL;{muQG;T{xqe>oI~o5!@PQpg23u7B_z zOtosd=N5y_8}@p8rs#ZDmbCIt)yK=1vhboFA@>Z*ZgtqA6MNM_c^Ky^r=_`P_S&Lo zGe}3!8-WgqvFZ6yQ0t5x78_GyDXhdy9bdaP5g%eD?8mb(bSP^)61-i*vcChP49{*HxjuYm`r- zfE<{cl7MCFZk#0-5WifppQ@_z6_0ovRDSYttSZWF$YEV!<3*L-;dkX$*`7W(dEdPj z+HJc=HMpP;NeUBD%iwogNnXzz3MqYWMAN#`2NF>}EQdzkZ6YWIbX$l!g~5A&SIF=a zfHzbj9_7fv!yX*ju{0oMJ391N!1f3ql7wJrBA`Ik`jy9->?j~kjpeyJV5b7(c`(&M zG_m`G&i^RQz(q%Mdcmc}8!@Y`)tXSX0Yrps@_@EXSga0WG2#5LlQ7Mv+Coj*(;NJK ztGlVyK-g@w)vSG6Hwxgex+?$4&wQstyU{$qx})X76}I=cOZuU^-j$fQbRIGkJf~1| zEd63FnOtq-_F1=e;&y%j{SGeMVlU*iz#(1>7a23B1|o;Yl*z%zo8YiEv!r>E@%L&m z3gRm)HGuESW&IH8F;k&YrUK=R*#L-ZhM|XnqdFpg)vKE&S0B_5nVfa4sWbDk%rrcI za%FNKC)Y@9yJsNU;U7~L3Ggj6zK~nAe{ZP-q0o^#Z(6qtvaH1;&*kIulLA;i+cNKy z%~>*MrRY~z!)B|Z#Gx%_g%Oo(v73iCpV0rOLj99>^(WB^@x%_adcRs>y&G?vLf#wE zQ$EcpPdV2>>rmp8bKO-`32sTk&dgp>Ge{gSuBGAS!ZCfaHHMC7LeQ6VKf>zO&EVR$ z#+GZ&l*Uh%vei9GTUkE?mD&AI=@)}}@cF&YHAW@H{6ADTwLrrZW4?U*25sQa!y3Zp z$`0b2OkfRi2iZ8YQ+JtKSY(UHkno}iuOikw&6Q?3alVz4M9T$FNZVYEO_ARIOPTv|Z-f*%`}q~;qX*b95lXQ$#YL7#P%NquFl zH+pvA9DRXEmA>}=JUw>k2@FcMtzPQjpDosV2nx#o1iKCy)UCDM|N3IVE5ONoz#`+; zw`i*%oWM$R8bPanFs}xq%=xyeXLiNQuy{93E=wTnK~l`7Rn_(jLuJzPg}JvYmBy?5 z$3cS5W$ZY=k;E)gol;2m@8VIXrgM2)Ok=rtF3(=k9q~u!I~{k#pWHticSd;P-mrA$ zMrW4Bd{jo8PH&pQKER){sxna9SE?HHhyBC|b(gXgP4ag(;1(s~o^DwyeqxhssE|3d zCp{=}KvooE&G+!&vNeRb^N08AX~J(PT7L+1VS8?J((a%xltIzuri-*W($%IEY=Eh)7%c z2JY5L8hdMZh&G$cb6uXj-Cc} zf!2B8WH#S?d@@|Fss#B6Z;u5PLYQRt5DZKOb6E7b5R$3&i3teQ03~VQ5LVg1Z}0Iyva^k^szClFm(0zo_K) zJoM`l_d)U(rPvi4k76fCM$r%Lb34EeNdu{EugH~I7tn4DFkul; z-*pFL{;;&wE`wJm^-r4=&%p|GdL_-Wg4*j3&+(HEae27Wr;XBu2AeLQ?f_Pq({qul zh3;NjkM7t(V5D|5ZF}?qZ3{2Fm0_{%Q-JTdk!|&No>Vk!Z6x2KYzsUsY10b%pmuI?=8~2y<46>e;uFN;>+K`D z=vL@bBsaJz87bYL&g|Ci?FF5N0~~}`Lm9e#X4)HU6hK=Zr>N39-mz)d9#O{zXX_h9 zHGVsoUCP)eKB(ti=79-OpFr$6xemCvn7E}S+ui7;~CI16V|bf)zQ+P68tj{HNMQxMN60q z8)T;e^lo=nM2cQ{^xMS5*LzSzBh9@Q4R1F%Z@Iq8dRzVr>dIqJ{c=|u!$7a;BnFGwe1gKM5$GJ=5e z^J!i`mNKq#%tsyjaD9`)ypxf+Q;p|XjD7`hVBCrGK;EPE=Pz0^JrgEZyY`4yhnd*-v_N=D&(6#NN7g?jDUR;1Uakaqh}Vr& zOU~ZGU>)Ftb~PtGAv8z+cE(q%XqrtWJqO0@w_uu<2!ruxB)YF@B?(yCAUHfh(5^A{ ze!GWWsU8Uv3(vFaSn*K@Mxi(xJMLQ*l`yinNr+Cw(e~vOoa{yBDKt3iGA`CK%pw#Q zwlK=|E!#%EKiZzoR+42Sk62A<>cBUke+e-D{%72duY)~s^tX43bosZMxGuk@x(9`WD7^hK zFmC26Njmy%b;0J1o0DFYOO2eQoP*sfYYhO0|1nf=(_y6=wm7?EmE1=v+*UOAQYPXD z4P=F;FW;FImNdrvd=|at+EEI6m}V8v7AX3?Tn{z>lUv5GeJ=(Iqzor^d&}bFKSrI~ zi06vUFV6}e0yqV9lq)xk4XZhiLmiitiCD(hn`|PTA+M5No+-Z!hy$E|ZUQitI@#w1 z@y=Qk75%d;Bcffrk~Ule`g23Fq>`B}EV+=b4_*_=v46}#i(x~+Ku6wK^Y%+%fBj*> z1F#(rwFW?X%chxOd{x#Pty9PB7R|7zs6=_CJ`;V!p`ZD0l-FYgA0Nr&woR&Or_*xe zj7^$gKd1oisog+Xm%!|YJxfI8*ILpJx!p9aH@~z1z~Uf7b|>mkB$-I0+;@mO1?|&A zvOE5w51zR-?nyPcT){et;OERuhUhj}Dov;a_+gMX&(}$_?MTnoY$!o?R98I8yUN!{ zY7EK{ak9hE52D7}15fW)2j8f-`=V zQuAlYzEB}#7|U}DfN`rvl7K*Iz)4Di+{S0Fo;*Um$87)fL4{W$TeMX5=WU8MUe#|D zEv4e5aB#^)8{yLE$QOG=*|1rKMMUEjaB?NPuOkT2Iya?dCq!_Aeu#eYFIZbt#c_P?b{^pYV;gkoHon2!tgSg+s}+RP_qqk0C6QE zJg^Qhg%N}`t$!S)`W@RpM3;Y2cTeYQpQ&x*+EnDwRsybyLL3IOs;-;0cN}jrw4b0j z6fO8l0x$=dZq?V8)x54LJCg))6G_>Aw6KPvb6HB{0J43G4b7+cQ{;qDqNsM0Jo*``#=SAT-th5wi<`pz`}$oswWcLD-n7ry*~5S*J}xzJGcs^gvQ3utD^qLF(`UEbZfZ|0_=z`d zY^RA0cIa=wg?)`Itn~eKWV`+iUbbUcA<@^5sSERsHvI3nk(f59n`*hH*(FSNb$%~> zoK^aR-FLE?Z#;9ct)_trWqz-2>vcpfg4FA-_>p9(}&*k z7QS&og7U7wp=7UC7uWbDW7|vKJyZx<5&l94=^pyw1#jg2P&LuOr(b__nXF(;QUq7b z@ZEF$b@}Kx6q$%${=>RUcp9RN*=L>b6c% zAE|LtR=-^t<9Rn{bC+Mdy0(XPgv|I;7LhhP_1~b0L`^LBivG-!c8irN(E6GO=6HX* zNwx~c97=Os+bsp~*rKfHAh%xY4R-x0r&p^r(-KvOZhpD2Mdy$;>cI8&mVNsbj-@t7 zxyDq^izcn6S`xRZZTHGvAF@w=n3nNz%;!lWj6TepCIXokcob0PB)j|LIs+JVuc*GM zfZ*%2%SDEHq?rh}iWX&0ggN9mQ;zW$wB;dnY>e)ohDrYvjQ)oedVKS8Jhi#z#yPK} zZR;;km#UgkG|U4r3RA8e6$v3a(q(4xmf1A@ky}k2nYv~#t}uflY&-^i*a?O>1_1_j zI9fkEY}QI>giJvpGRY?cBx4kuOzcbz1F07FAhEWGmH>op}?01H@!y%UVDM(K!V z`EQH`<8aO+;1WZD$I?rZAA%TWknVB)jSG!UtQYM7Lt(ai^n+1*>PD@jk^I$lBd_VU zx4OAiJ*uU2%0$rOG9C+0+Ko80822kI>-qx)?7mLhwQZ@V=mD9#EZ4@d2VOs3cC|#( zFUBwR*PaQ~U3Q{XwE;-n6MNg=tYY^X{CiE$h7XFTK%S&pgX1hL&y41MoH#nwe2!n$ zykseXYnF)}N%(MWurN5`)+K6~RH{2IW~pdKg-=7-uS%ITj_&Sm4%(>{NT<2 z))&s>51$=PIF|eAENq9Vw9)zdMs_?#+$xnLXl7M^JKC>mOsRC1`g$W|U@bU>WSU+K zbLS`j{FBH~f6;T(TYvmr;YG|ZzL$62H<;)=d}nzW5I20S0;gc8FQ{tR?Ryp0WxBeL zt(PQVU%os!b~n;TDd?3^alZ;GSXtmY023gseWn_N+5tNg9^i0W;1w>`ZqbT&i$vEn z29+^yI^RhseZYcmr(#Jwoh#{VyLy?bhcu6a3xA)YK|UH5^nW98SBR!rAmE!2QjgYO zDCDZx|Ir}!Z-3FMODzg^{&>c3!a_WzVO(cp|1EZtt?#N?{_g-Tv%an;XUd=zB~hzv z3|CeD{}8i;SpGrN|LU!4l?7U9f#L9C7gV)#U|VRMnt&2wz~QeGSyKlfs16RNLIFM0L+6+iqAjj0VJMZdRBHe zuIErsb8kvTIDLowi;jx%3u*0_V_DLIo@AYk(GFBbcM;r(0@tZ^P^JT>g+0=H4Gc3UI7M1FOweWz@->7szjHT}rsduy8A9{VZ^8jl8)H);sCTBYG z6_pDDfg?f)BdT-EzMkHl3Nda&J~dL~IxE3%Ax#V7~$ zP2QQc_7LZ?w6|vEpk)d+xz>~;uL1zj&g*HaTPQX(rL)6LKt?G<$-Jqq(Yn4Alkt=r zz81m3h@tF)tU>q9eTNHM^R%X>ruqVzwRw5G{7TWak$%~8|Hnw6|8;U8CQU;pqTZ6_ z9n7XimJz47xDC^_5%svwQ=UD9q_NN*=gqaemx}jh@Vf|v%+1fjYZ_PvOA8AJw8Mp+ z4%+kQ&nIpQdZ2D-2`9DUw5NH_!e{Cqq^f;>SaDju+lPvBXphh`VMyJKS7T(zt47Jn z$ZWtVgzBNw;g9?UUHIM4pEWP?+}CW6AQUrychh^i&}B5akW8$oFfKF;4-Y?>6H|Kd zS4sYRd^^MTin~A&ardO&s8xh;ZgNt-a!cbP%%nw*=}_p=^M!N01WQ+(6M5)Zp5IYv zF3ogXHT|h$UNWFf>dyGdBytW?3t)z}t$dt3@U!C%;ybd*B}DH8nMFOG%lXkO_@V%CgZ5F_d=W zLKRrvOdd3$%lAym3y9;SB?1a|{lH6g=ro+OJDk3cm4^P9{SOh;NyuhUb;~bU4Bc^5 zf8~BwASki@x2vl3dGyJEWfFchWaS&rCqD<4vq}CUh2fO-rE@Tk*`0SE0MtiM%UH8c I<5B#70en=WTL1t6 literal 0 HcmV?d00001 diff --git a/docs/_static/images/dev-container-reopen-prompt.png b/docs/_static/images/dev-container-reopen-prompt.png new file mode 100644 index 0000000000000000000000000000000000000000..b0d18dc79da78e4537a2c616bca6a20684709d1f GIT binary patch literal 23975 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 diff --git a/docs/advanced/dev-containers.md b/docs/advanced/dev-containers.md new file mode 100644 index 0000000..072995d --- /dev/null +++ b/docs/advanced/dev-containers.md @@ -0,0 +1,45 @@ +# Development Container + +Instead of manually configuring your development environment, [Dev Containers](https://containers.dev/) offer a seamless containerized development experience right out of the box. + +## Prerequisites + +Before you can use a Dev Container, you will need to install a few components. + +1. [Docker Desktop](https://www.docker.com/products/docker-desktop) or an [alternative Docker option](https://code.visualstudio.com/remote/advancedcontainers/docker-options). +1. [Visual Studio Code](https://code.visualstudio.com/). +1. The [Dev Containers extension](vscode:extension/ms-vscode-remote.remote-containers) within VSCode. + +## Usage + +After installing the prerequisites, you have two main approaches to use a Dev Container. Using [a locally cloned repository](#open-a-locally-cloned-repository-in-a-container) leverages your existing local source code, while [an isolated container volume](#open-the-repository-in-an-isolated-container-volume) creates a separate copy of the repository, which is particularly useful for PR reviews or exploring branches without altering your local environment. + +### Open a locally cloned repository in a container + +When you open a repository that includes a Dev Container configuration in VS Code, you will receive a prompt to reopen it in the container. + +```{image} /_static/images/dev-container-reopen-prompt.png +:alt: Dev Container Reopen Prompt. +``` + +If you missed the prompt, you can use the **Dev Containers: Reopen in Container** command from the Command Palette to initiate the containerized environment. Here are some frequently used commands: + +Dev Containers: Reopen in Container +: Triggers the containerized environment setup upon opening a repository configured for Dev Containers. + +Dev Containers: Rebuild Without Cache and Reopen in Container +: Useful for refreshing your environment in case of issues or to update to a newer version. + +Dev Containers: Clean Up Dev Containers... +: Deletes stopped Dev Container instances and removes unused volumes, helping maintain a clean development environment. + +### Open the repository in an isolated container volume + +You may already notice the badge [![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/you-n-g/wan) in the [Overview](/index.md) page. You can click the badge or [this link](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/you-n-g/wan) to get started. Clicking these links will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. + +## Reference + +For more detailed guidance and advanced usage, explore the following resources: + +- [Dev Containers tutorial](https://code.visualstudio.com/docs/devcontainers/tutorial) +- [Developing inside a Container](https://code.visualstudio.com/docs/devcontainers/containers) diff --git a/docs/advanced/index.md b/docs/advanced/index.md new file mode 100644 index 0000000..a48434c --- /dev/null +++ b/docs/advanced/index.md @@ -0,0 +1,8 @@ +# Advanced Usage + +This section provides recommended best practices for enhancing your development workflow. While not essential, these topics can optimize the project management and development processes. + +```{toctree} +dev-containers +partial-dev-env +``` diff --git a/docs/advanced/partial-dev-env.md b/docs/advanced/partial-dev-env.md new file mode 100644 index 0000000..a08de2b --- /dev/null +++ b/docs/advanced/partial-dev-env.md @@ -0,0 +1,55 @@ +# Partially Set Up Development Environment + +In certain cases, it is unnecessary to install all dependencies as well as the pre-commit hook. For example, this can speed up the setup process in CI/CD. + +## Minimal installation + +Install the project in editable mode with only the necessary dependencies, which is useful for scenarios like deployment. + +```bash +make install +``` + +## Documentation generation + +Install the project in editable mode with dependencies related to `doc`, +recommended for scenarios like the documentation generation CI/CD process. + +```bash +make dev-doc +``` + +## Lint check + +Install the project in editable mode with dependencies related to `lint`, +recommended for scenarios like the lint CI/CD process. + +```bash +make dev-lint +``` + +## Package build + +Install the project in editable mode with dependencies related to `package`, +recommended for scenarios like the package CI/CD process. + +```bash +make dev-package +``` + +## Testing + +Install the project in editable mode with dependencies related to `test`, +recommended for scenarios like the test CI/CD process. + +```bash +make dev-test +``` + +## Combination + +To install dependencies for `doc` and `lint`, use the following command: + +```bash +make dev-doc,lint +``` diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 0000000..3d301c9 --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,6 @@ +# API Reference + +```{toctree} +:maxdepth: 1 +settings +``` diff --git a/docs/api/settings.md b/docs/api/settings.md new file mode 100644 index 0000000..d336919 --- /dev/null +++ b/docs/api/settings.md @@ -0,0 +1,5 @@ +# wan.settings + +```{eval-rst} +.. automodule:: wan.settings +``` diff --git a/docs/cli/index.md b/docs/cli/index.md new file mode 100644 index 0000000..d41bb3c --- /dev/null +++ b/docs/cli/index.md @@ -0,0 +1,7 @@ +# CLI Reference + +```{eval-rst} +.. click:: wan.cli:typer_click_object + :prog: wan-cli + :nested: full +``` diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..33bbcc4 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,76 @@ +"""Configuration file for the Sphinx documentation builder. + +For the full list of built-in configuration values, see the documentation: +https://www.sphinx-doc.org/en/master/usage/configuration.html +""" + +from importlib import metadata + +# -- Project information --------------------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +author = "Xiao Yang" +copyright = "2023, Xiao Yang" +project = "WAN" +release = metadata.version("wan") +version = ".".join(release.split(".")[:2]) + + +# -- General configuration ------------------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "myst_parser", + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinx_click", + "sphinx_design", + "sphinxcontrib.autodoc_pydantic", +] +source_suffix = { + ".rst": "restructuredtext", + ".md": "markdown", +} +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +templates_path = ["_templates"] +html_theme_options = { + "announcement": ( + "WAN " + "is in the Beta phase. " + "Changes and potential instability should be anticipated. " + "Any feedback, comments, suggestions and contributions are welcome!" + ), +} + +# -- Options for HTML output ----------------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "furo" +html_static_path = ["_static"] + +# -- Options for autodoc extension ---------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#configuration + +autodoc_default_options = { + "members": None, +} + +# -- Options for autodoc_pydantic extension ------------------------------------------- +# https://autodoc-pydantic.readthedocs.io/en/stable/users/configuration.html + +autodoc_pydantic_settings_show_json = False + +# -- Options for myst-parser extension ------------------------------------------------ +# https://myst-parser.readthedocs.io/en/latest/configuration.html + +myst_enable_extensions = [ + "colon_fence", + "deflist", +] +myst_heading_anchors = 3 +myst_url_schemes = { + "http": None, + "https": None, + "vscode": None, +} diff --git a/docs/development/cleanup-dev-env.md b/docs/development/cleanup-dev-env.md new file mode 100644 index 0000000..fe63f29 --- /dev/null +++ b/docs/development/cleanup-dev-env.md @@ -0,0 +1,31 @@ +# Clean Up Development Environment + +When encountering environment-related problems, a straightforward solution is to cleanup the environment and setup a new one. Three different levels of cleanup approach are provided here. + +## Intermediate cleanup + +Intermediate cleanup only removes common intermediate files, such as generated documentation, package, coverage report, cache files for mypy, pytest, ruff and so on. + +```bash +make clean +``` + +## Deep cleanup + +Deep cleanup removes the pre-commit hook and the virtual environment alongside the common intermediate files. + +```bash +make deepclean +``` + +## Complete cleanup + +Complete cleanup restores the repository to its original, freshly-cloned state, ideal for starting over from scratch. + +```{caution} +This will remove all untracked files, please use it with caution. It is recommended to check with dry-run mode (`git clean -dfnx`) before actually removing anything. For more information, please refer to the [git-clean documentation](https://git-scm.com/docs/git-clean). +``` + +```bash +git clean -dfx +``` diff --git a/docs/development/commit.md b/docs/development/commit.md new file mode 100644 index 0000000..dbc7d28 --- /dev/null +++ b/docs/development/commit.md @@ -0,0 +1,56 @@ +# Commit Convention + +Using structured commit messages, we can enhance the readability of our project history, simplify automated changelog generation, and streamline the release process. We primarily follow the [Conventional Commit](https://www.conventionalcommits.org/) and [Angular's commit guidelines](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits). + +## Commit Message Pattern + +```text +(): +``` + +Examples: + +```text +build(dependencies): bump the prod group with 9 updates. +doc: Add doc for commit convention. +chore: remove deprecated key in ruff config. +``` + +Type +: Describes the nature of the change: + +| Type | Description | +|-----------|--------------------------------------------------------| +| `build` | Changes that affect the build system or dependencies. | +| `chore` | Routine tasks or changes outside the src/runtime code. | +| `ci` | Changes related to continuous integration. | +| `doc` | Documentation changes. | +| `feat` | New features. | +| `fix` | Bug fixes. | +| `perf` | Performance improvements. | +| `refactor`| Code restructuring without changing behavior. | +| `revert` | Revert a previous commit. | +| `style` | Code formatting changes. | +| `test` | Add or update tests. | + +Scope [Optional] +: Represents the part of the project impacted by the change. Examples include `logging`, `settings`, and `cli`. + +### Breaking Change + +A "breaking change" refers to any modification that disrupts the existing functionality in a way that may affect users. It can be denoted using an exclamation mark (`!`) before the colon, like `refactor!: Stuff`. + +## Commit in Development Branches + +While the commit convention seems strict, we aim for flexibility during the development phase. +By adhering to the , all changes should be introduced via pull/merge requests. +Using the squash merge strategy, the emphasis is primarily on the title of pull/merge requests. +In this way, individual commit within development branches does not need to strictly adhere to the commit convention. + +````{note} +A CI/CD pipeline checks the titles of pull/merge requests against the following regex pattern: + +```text +^(build|chore|ci|doc|feat|fix|perf|refactor|revert|style|test)(\(\w+\))?!?:\s.* +``` +```` diff --git a/docs/development/git-workflow.md b/docs/development/git-workflow.md new file mode 100644 index 0000000..604cc01 --- /dev/null +++ b/docs/development/git-workflow.md @@ -0,0 +1,130 @@ +# Git Workflow + +This pages shows the recommended Git workflow to keep the local repository clean and organized while ensuring smooth collaboration among team members. + +## Prerequisites + +Make sure you have [Git](https://git-scm.com/) (version 2.23 and above) installed and properly configured especially for authentication. + +## Fork and clone the repository + +Fork the repository to your own namespace, and let us take `https://github.com//wan` as example. + +Clone the repository and navigate to the root directory: + +```shell +git clone git@github.com:/wan.git +cd wan +``` + +## Configure the remote + +Add and update the `upstream` remote repository: + +```shell +git remote add upstream https://github.com/you-n-g/wan +git fetch upstream +``` + +Configure `git` to pull `main` branch from the `upstream` remote: + +```shell +git config --local branch.main.remote upstream +``` + +Configure `git` never to push to the `upstream` remote: + +```shell +git remote set-url --push upstream git@github.com//wan.git +``` + +## Verify the remote configuration + +List the remote repositories with urls: + +```shell +git remote -v +``` + +You should have two remote repositories: `origin` to your forked CPython repository, and `upstream` pointing to the official CPython repository: + +```shell +origin git@github.com:/wan.git (fetch) +origin git@github.com:/wan.git (push) +upstream https://github.com/you-n-g/wan (fetch) +upstream git@github.com:/wan.git (push) +``` + +Note that the push url of `upstream` repository is the forked repository. + +Show the upstream for `main` branch: + +```shell +git config branch.main.remote +``` + +You should see `upstream` here. + +## Work on a feature branch + +Create and switch to a new branch from `main`: + +```shell +git switch -c main +``` + +Stage the changed files: + +```shell +git add -p # to review and add changes to existing files +git add # to add new files +``` + +Commit the staged files: + +```shell +git commit -m "the commit message" +``` + +Push the committed changes: + +```shell +git push +``` + +## Create a pull request + +Navigate to the hosting platform and create a pull request. + +After the pull request is merged, you need to delete the branch in your namespace. + +```{note} +It is recommended to configure the automatic deletion of the merged branches. +``` + +## Housekeeping the cloned repository + +Update the `main` branch from upstream: + +```shell +git switch main +git pull upstream main +``` + +Remove deleted remote-tracking references: + +```shell +git fetch --prune origin +``` + +Remove local branches: + +```shell +git branch -D +``` + +After all these operations, you should be ready to again. + +## Reference + +- [Git bootcamp and cheat sheet, Python Developer's Guide](https://devguide.python.org/getting-started/git-boot-camp/) diff --git a/docs/development/index.md b/docs/development/index.md new file mode 100644 index 0000000..24ff799 --- /dev/null +++ b/docs/development/index.md @@ -0,0 +1,11 @@ +# Development Practices + +This section is designed for developers and covers essential topics during daily development lifecycle. Follow these guidelines to ensure all contributors adhere to best practices, maintain code quality, and collaborate efficiently. + +```{toctree} +git-workflow +setup-dev-env +cleanup-dev-env +commit +tests +``` diff --git a/docs/development/setup-dev-env.md b/docs/development/setup-dev-env.md new file mode 100644 index 0000000..48e7704 --- /dev/null +++ b/docs/development/setup-dev-env.md @@ -0,0 +1,30 @@ +# Set Up Development Environment + +This page shows the approach to set up development environment. To simplify the process, a unified `Makefile` is maintained at the root directory of the repo. In other words, all the `make` related commands are supposed to run there. + +## Prerequisites + +[pipx](https://pipx.pypa.io/) is required to manage the standalone tools used across the development lifecycle. +Please refer to pipx's installation instructions [here](https://pipx.pypa.io/stable/installation/). +Once pipx is set up, install the needed standalone tools with the following command: + +```bash +make prerequisites +``` + +## Setup + +Development environment can be setup with the following command: + +```bash +make dev +``` + +This command will accomplish the following tasks: + +- Create a virtual environment. +- Install all the dependencies, including those for documentation, lint, package and test. +- Install the project in editable mode. +- Install git hook scripts for `pre-commit`. + +To speed up the setup process in certain scenarios, you may find helpful. diff --git a/docs/development/tests.md b/docs/development/tests.md new file mode 100644 index 0000000..6685a07 --- /dev/null +++ b/docs/development/tests.md @@ -0,0 +1,27 @@ +# Tests + +In the context of CI/CD automation, dependency updates, and the release process, tests play a crucial role in daily development. We utilize [pytest](https://docs.pytest.org/) and [coverage](https://coverage.readthedocs.io) with proper configuration to ensure everything works as expected. This page provides general information and conventions we wish you to follow. + +## Running Tests + +After [setting up the development environment](/development/setup-dev-env.md), tests can be run with the command: + +```bash +make test +``` + +With the default configuration, this command displays the result for each test case, the execution time for slow test cases, and a report on test coverage. + +## Writing Tests + +For guidelines on how to write tests, refer to [the official documentation](https://docs.pytest.org/how-to/assert.html). Here are some conventions we expect you to follow: + +1. Organize all test cases under the `tests` directory. +2. Align test modules with the modules to be tested. + + For example, tests for the `wan.cli` module should be located in the file `tests/cli_test.py`. If there are too many test cases, they can be split into files within the `tests/cli/` directory, using a prefix for each test file. +3. Unless necessary, do not lower the threshold of the test coverage. + +## Coverage Report + +After running the tests, the coverage report will be printed on the screen and generated as part of the documentation. You can view it [here](/reports/coverage/index.md). diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..a92418b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,23 @@ +# Welcome to WAN's documentation + +```{toctree} +:hidden: +Overview +management/index +development/index +advanced/index +cli/index +api/index +reports/index +Changelog +``` + +```{include} ../README.md +:start-line: 1 +``` + +## 🔖 Indices and tables + +* {ref}`genindex` +* {ref}`modindex` +* {ref}`search` diff --git a/docs/management/index.md b/docs/management/index.md new file mode 100644 index 0000000..c78bd51 --- /dev/null +++ b/docs/management/index.md @@ -0,0 +1,10 @@ +# Project Management + +This section is designed for project maintainers and covers essential tasks for managing your project. Follow these guidelines to ensure your project remains up-to-date and adheres to best practices. + +```{toctree} +init +settings +update +release +``` diff --git a/docs/management/init.md b/docs/management/init.md new file mode 100644 index 0000000..eaf8525 --- /dev/null +++ b/docs/management/init.md @@ -0,0 +1,46 @@ +# Project Initialization + +## Prerequisites + +[pipx](https://pipx.pypa.io/) is required to manage the standalone tools used across the development lifecycle. +Please refer to pipx's installation instructions [here](https://pipx.pypa.io/stable/installation/). +Once pipx is set up, install the copier for project generation using the following command: + +```bash +pipx install copier==9.3.1 +``` + +## Create the Repository + +Create a blank Git repository on the hosting platform. Clone it locally and navigate to the root directory: + +```bash +git clone git@github.com:you-n-g/wan.git +cd wan +``` + +## Generate the Project + +Running the following command and answer the prompts to set up the project: + +```bash +copier copy gh:serious-scaffold/ss-python . +``` + +## Set Up Development Environment + +Set up development environment to prepare for the initial commit: + +```bash +make dev +``` + +## Commit and push + +```bash +git add . +git commit -m "chore: init from serious-scaffold-python" +SKIP=no-commit-to-branch git push +``` + +Now, everything is done! diff --git a/docs/management/release.md b/docs/management/release.md new file mode 100644 index 0000000..a20bd8a --- /dev/null +++ b/docs/management/release.md @@ -0,0 +1,79 @@ +# Release Process + +With the integration of [semantic-release](https://github.com/semantic-release/semantic-release), the release process is fully automated. To enable this, follow the settings for . Besides, adhering to the is strongly recommended to ensure the release process works as expected. + +## Release Configuration + +The release configuration is located in the root directory of the project: + +```{literalinclude} ../../.releaserc.json +``` + +Based on this configuration, the following trigger rules apply: + +* A **major** release is triggered by a 'BREAKING CHANGE' or 'BREAKING-CHANGE' in the footer of the commit message. +* A **minor** release is triggered when the latest commit type is `feat`. +* A **patch** release is triggered when the latest commit type is `fix`, `perf`, `refactor` or `revert`. +* No release is triggered if the latest commit type is any other type or has a `no-release` scope. + +## Commit message examples + +### Major release + +```text +feat: drop Python 3.8 support + +BREAKING CHANGE: drop Python 3.8 support +``` + +### Minor release + +* `feat: add an awesome feature` + +### Patch release + +* `fix: fix a silly bug` +* `perf: performance improvement for the core` +* `refactor: refactor the base module` +* `revert: revert a buggy implementation` + +### No release + +* `feat(no-release): a feature that should not trigger a release` +* `fix(no-release,core): a fix that should not trigger a release, but with more scopes` + +## Release Tasks + +The release process includes the following tasks: + +::::{tab-set} + +:::{tab-item} GitHub +:sync: github + +1. Generate a changelog from unreleased commits. +1. Publish a new GitHub Release and semantic version tag. +1. Build and publish the documentation to GitHub Pages. +1. Build and publish the Python package to the configured package repository. +1. Build and publish the Development and Production Containers with the build cache to GitHub Packages. + 1. The Production Container is tagged as `ghcr.io/you-n-g/wan:py` for the latest version and `ghcr.io/you-n-g/wan:py-` for archives. + 1. The Development Container is tagged as `ghcr.io/you-n-g/wan/dev:py` for the latest version and `ghcr.io/you-n-g/wan/dev:py-` for archives. + 1. The build cache for the Development Container is tagged as `ghcr.io/you-n-g/wan/dev-cache:py`. + +::: + +:::{tab-item} GitLab +:sync: gitlab + +1. Generate a changelog from unreleased commits. +1. Publish a new GitLab Release and semantic version tag. +1. Build and publish the documentation to GitLab Pages. +1. Build and publish the Python package to the configured package repository. +1. Build and publish the Development and Production Containers with build cache to GitLab Container Registry. + 1. The Production Container is tagged as `registry.gitlab.com/you-n-g/wan:py` for the latest version and `registry.gitlab.com/you-n-g/wan:py-` for archives. + 1. The Development Container is tagged as `registry.gitlab.com/you-n-g/wan/dev:py` for the latest version and `registry.gitlab.com/you-n-g/wan/dev:py-` for archives. + 1. The build cache for the Development Container is tagged as `registry.gitlab.com/you-n-g/wan/dev-cache:py`. + +::: + +:::: diff --git a/docs/management/settings.md b/docs/management/settings.md new file mode 100644 index 0000000..83b790c --- /dev/null +++ b/docs/management/settings.md @@ -0,0 +1,167 @@ +# Repository Settings + +There are several settings to utilize the features provided by the project template. Although some of them are not strictly required, it is highly recommended finish these one-time jobs so as to benefit on the whole development lifecycle. + +## Branch protection + +::::{tab-set} + +:::{tab-item} GitHub +:sync: github + +1. Navigate to the [Branch protection rules](https://github.com/you-n-g/wan/settings/branches) settings. +1. Ensure a rule for the default `main` branch. +1. Enable **Require a pull request before merging** with **Require approvals** and **Dismiss stale pull request approvals when new commits are pushed** enabled. +1. Enable **Require status checks to pass before merging** and set [ci](https://github.com/you-n-g/wan/actions/workflows/ci.yml) and [commitlint](https://github.com/you-n-g/wan/actions/workflows/commitlint.yml) as required status checks. + +::: + +:::{tab-item} GitLab +:sync: gitlab + +1. Navigate to the [Repository](https://gitlab.com/you-n-g/wan/-/settings/repository) settings and the **Protected branches** section. +1. Ensure the default `main` branch is protected with **Maintainers** for **Allowed to merge**, **No one** for **Allowed to push and merge** and **Allowed to force push** disabled. + +::: +:::: + +## Tag protection + +::::{tab-set} + +:::{tab-item} GitHub +:sync: github + +1. Navigate to the [Protected tags](https://github.com/you-n-g/wan/settings/tag_protection) settings. +1. Create a rule for tag name pattern `v*`. + +::: + +:::{tab-item} GitLab +:sync: gitlab + +1. Navigate to the [Repository](https://gitlab.com/you-n-g/wan/-/settings/repository) settings and the **Protected tags** section. +1. Add a rule with wildcard `v*` for **Tag** and **Maintainers** for **Allowed to create**. + +::: +:::: + +## Squash merge + +::::{tab-set} + +:::{tab-item} GitHub +:sync: github + +1. Navigate to the [General](https://github.com/you-n-g/wan/settings) settings and the **Pull Requests** section. +1. Disable **Allow merge commits** and **Allow rebase merging**. +1. Enable **Allow squash merging** and set **Pull request title** as **Default commit message**. + +::: + +:::{tab-item} GitLab +:sync: gitlab + +1. Navigate to the [Merge requests](https://gitlab.com/you-n-g/wan/-/settings/merge_requests) settings. +1. Set **Fast-forward merge** for the **Merge method**. +1. Set **Require** for the **Squash commits when merging**. +1. Enable **Pipelines must succeed** in the **Merge checks**. + +::: +:::: + +## Pages + +::::{tab-set} + +:::{tab-item} GitHub +:sync: github + +1. Navigate to the [GitHub Pages](https://github.com/you-n-g/wan/settings/pages) settings. +1. Set **GitHub Actions** as **Source**. + +::: + +:::{tab-item} GitLab +:sync: gitlab + +Nothing need to do for GitLab Pages. + +::: +:::: + +## Package publish + +::::{tab-set} + +:::{tab-item} GitHub +:sync: github + +1. Navigate to the [Actions secrets and variables](https://github.com/you-n-g/wan/settings/secrets/actions) settings. +1. Set the **variable** `PDM_PUBLISH_REPO`, the repository (package index) URL to upload the package which defaults to `https://pypi.org`, the official PyPI. +1. Set the **variable** `PDM_PUBLISH_USERNAME`, the username to authenticate to the repository (package index) which defaults to `__token__`, used for [API token](https://pypi.org/help/#apitoken). +1. Set the **secret** `PDM_PUBLISH_PASSWORD`, the password to authenticate to the repository (package index). + +::: + +:::{tab-item} GitLab +:sync: gitlab + +1. Navigate to the [CI/CD](https://gitlab.com/you-n-g/wan/-/settings/ci_cd) settings and the **Variables** section. +1. Set the variable `PDM_PUBLISH_REPO`, the repository (package index) URL to upload the package, default to `https://pypi.org`, the official PyPI. +1. Set the variable `PDM_PUBLISH_USERNAME`, the username to authenticate to the repository (package index), default to `__token__`, used for [API token](https://pypi.org/help/#apitoken). +1. Set the variable `PDM_PUBLISH_PASSWORD` with the **Mask variable** option for security, the password to authenticate to the repository (package index). + +::: +:::: + +## Renovate and semantic-release + +::::::{tab-set} + +:::::{tab-item} GitHub +:sync: github + +There are two approaches, either with GitHub App or with personal access token (classic). GitHub App is the more recommended way to avoid the issues and pull requests tied to a particular user. + +::::{tab-set} + +:::{tab-item} GitHub App + + 1. [Register a GitHub App](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app) with permission listed [here](https://docs.renovatebot.com/modules/platform/github/#running-as-a-github-app) and `Repository administration: write` permission as mentioned [here](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/configuring-tag-protection-rules#about-tag-protection-rules). + 1. [Generate a private key](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps#generating-private-keys), and download the private key as a `.pem` file. + 1. Navigate to the [Actions secrets and variables](https://github.com/you-n-g/wan/settings/secrets/actions) settings. + 1. Set **App ID** of the GitHub App as **variable** `BOT_APP_ID`. + 1. Set the content of the private key as **secret** `BOT_PRIVATE_KEY`. + +::: + +:::{tab-item} personal access token (classic) + +1. [Create a personal access token (classic)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) with **workflow** scope. +1. Navigate to the [Actions secrets and variables](https://github.com/you-n-g/wan/settings/secrets/actions) settings and set the token as a **secret** `PAT`. + +::: +:::: + +```{note} +You can set the scope of the variables and secrets to **Repository** or **Organization** according to actual requirements. +``` + +::::: + +:::::{tab-item} GitLab +:sync: gitlab + +Either [Group access tokens](https://docs.gitlab.com/ee/user/group/settings/group_access_tokens.html), [Project access tokens](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html) or [Personal access tokens](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) can be used. The group or project access tokens are more recommended to avoid the issues and merge requests tied to particular user. + +1. Create a [group access token](https://gitlab.com/groups/you-n-g/-/settings/access_tokens), [project access token](https://gitlab.com/you-n-g/wan/-/settings/access_tokens) or [personal access token](https://gitlab.com/-/user_settings/personal_access_tokens) with `Maintainer` role and `api, write_repository` scope. +1. Navigate to the [CI/CD](https://gitlab.com/you-n-g/wan/-/settings/ci_cd) settings and the **Variables** section. Set the token as variable `PAT` with the **Mask variable** option for security. +1. Navigate to the [Pipeline schedules](https://gitlab.com/you-n-g/wan/-/pipeline_schedules). Create a new schedule with `*/15 0-3 * * 1` as **Interval Pattern** and mark it as **Activated**. + +```{note} +Although optional, [creating a personal access token (classic)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) on **GitHub** is strongly recommended. This token only needs `read-only` access and will increase the rate limit for Renovate to fetch dependencies and changelogs from github.com. It can be from any account and should be set as the variable `GITHUB_COM_TOKEN` with the **Mask variable** option for security. For more information on setting this up, see [Renovate's documentation](https://docs.renovatebot.com/getting-started/running/#githubcom-token-for-changelogs). +``` + +::::: +:::::: diff --git a/docs/management/update.md b/docs/management/update.md new file mode 100644 index 0000000..b9f3b9a --- /dev/null +++ b/docs/management/update.md @@ -0,0 +1,53 @@ +# Template and Dependency Update + +## Template update + +To update the project template, thanks to the [update feature](https://copier.readthedocs.io/en/stable/updating/) provided by [Copier](https://github.com/copier-org/copier) and the [regex manager](https://docs.renovatebot.com/modules/manager/regex/) provided by Renovate, a pull request will be automatically created when a new version of the template is released. In most cases, Copier will update the project seamlessly. If conflicts arise, they can be resolved manually since everything is version-controlled by Git. + +### Tips to minimize potential conflicts + +To minimize potential conflicts, consider the following suggestions: + +1. Avoid modifying the auto-generated files unless necessary. +1. For template-related changes, consider proposing an issue or a pull request to the [project template repository](http://github.com/serious-scaffold/ss-python) directly. +1. For project-specific changes, adopt an inheritance or extension approach to minimize modifications to auto-generated content. + +## Dependency update + +With the integration of [Renovate](https://github.com/renovatebot/renovate), all dependencies, including those used for development and CI/CD, will be automatically updated via pull requests whenever a new version is released. This allows us to focus solely on testing to ensure the new versions do not break anything. Moreover, an issue titled "Dependency Dashboard" will be created, so that you can have an overview of the state of all dependencies. + +### Managed dependency types + +The project template tracks the following dependencies: + +1. Supported managers other than `regex`: + 1. [pep621](https://docs.renovatebot.com/modules/manager/pep621/): The lock file generated by PDM for both dependencies and development dependencies in `pyproject.toml`. + 1. [github-actions](https://docs.renovatebot.com/modules/manager/github-actions/): Actions, runners and containers in GitHub Actions. + 1. [gitlabci](https://docs.renovatebot.com/modules/manager/gitlabci/): Containers in GitLab CI/CD. + 1. [pre-commit](https://docs.renovatebot.com/modules/manager/pre-commit/): Pre-commit hooks. +1. Regex manager: + 1. Python packages installed with pip/pipx, listed in the README, DevContainer Dockerfile, GitHub Actions, GitLab CI/CD, ReadTheDocs configuration, Renovate configuration and documentation. + 1. Debian packages installed in the DevContainer Dockerfile. + 1. PDM version specified in the `pdm-project/setup-pdm` GitHub action. + 1. PDM version specified in the renovate constraints. + 1. NPM packages used with npx. + 1. The project template itself. + +### Add new dependencies + +When adding new dependencies that belong to the managed dependency type mentioned above, it is recommended to pin or lock their versions to ensure they are smoothly managed by Renovate. + +When adding new types of dependencies, it is also recommended to manage them with Renovate. + +- If this follows a common pattern, consider creating an issue or even sending a pull request to project template directly. +- If it is project-specific, you can extend the renovate configuration: + - For supported managers other than `regex`, add them in the Renovate configuration using environment variable `RENOVATE_ENABLED_MANAGERS` in GitHub Actions or GitLab CI/CD and configure them in the `renovaterc.json` under the root directory if needed. + - For `regex` managers, add new entries in the `customManagers` and configure `packageRules` if needed in the `.renovaterc.json`. + + ```{note} + This also adheres to the . + ``` + +```{note} +For the complete list of supported managers and their corresponding configurations, please refer to the [Managers - Renovate Docs](https://docs.renovatebot.com/modules/manager/). +``` diff --git a/docs/reports/coverage/index.md b/docs/reports/coverage/index.md new file mode 100644 index 0000000..d362f0a --- /dev/null +++ b/docs/reports/coverage/index.md @@ -0,0 +1,3 @@ +# Coverage Reports + + diff --git a/docs/reports/index.md b/docs/reports/index.md new file mode 100644 index 0000000..fd72301 --- /dev/null +++ b/docs/reports/index.md @@ -0,0 +1,7 @@ +# Code Quality Reports + +```{toctree} +:maxdepth: 2 +mypy/index +coverage/index +``` diff --git a/docs/reports/mypy/index.md b/docs/reports/mypy/index.md new file mode 100644 index 0000000..10d61d0 --- /dev/null +++ b/docs/reports/mypy/index.md @@ -0,0 +1,3 @@ +# MyPy Reports + + diff --git a/pdm.lock b/pdm.lock new file mode 100644 index 0000000..afdf9d7 --- /dev/null +++ b/pdm.lock @@ -0,0 +1,1276 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "doc", "lint", "test"] +strategy = ["cross_platform", "inherit_metadata"] +lock_version = "4.4.2" +content_hash = "sha256:15321cfdb508fccffc1e86ae96141b05b5941404b065576fe758f06f5b123d82" + +[[package]] +name = "alabaster" +version = "0.7.13" +requires_python = ">=3.6" +summary = "A configurable sidebar-enabled Sphinx theme" +groups = ["doc"] +files = [ + {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, + {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +requires_python = ">=3.8" +summary = "Reusable constraint types to use with typing.Annotated" +groups = ["default", "doc"] +dependencies = [ + "typing-extensions>=4.0.0; python_version < \"3.9\"", +] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "autodoc-pydantic" +version = "2.1.0" +requires_python = ">=3.8,<4.0.0" +summary = "Seamlessly integrate pydantic models in your Sphinx documentation." +groups = ["doc"] +dependencies = [ + "Sphinx>=4.0", + "importlib-metadata>1; python_version <= \"3.8\"", + "pydantic-settings<3.0.0,>=2.0", + "pydantic<3.0.0,>=2.0", +] +files = [ + {file = "autodoc_pydantic-2.1.0-py3-none-any.whl", hash = "sha256:9f1f82ee3667589dfa08b21697be8bbd80b15110e838cd765bb1bf3ce1b0ea8f"}, + {file = "autodoc_pydantic-2.1.0.tar.gz", hash = "sha256:3cf1b973e2f5ff0fbbe9b951c11827b5e32d3409e238f7f5782359426ab8d360"}, +] + +[[package]] +name = "babel" +version = "2.16.0" +requires_python = ">=3.8" +summary = "Internationalization utilities" +groups = ["doc"] +dependencies = [ + "pytz>=2015.7; python_version < \"3.9\"", +] +files = [ + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, +] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +requires_python = ">=3.6.0" +summary = "Screen-scraping library" +groups = ["doc"] +dependencies = [ + "soupsieve>1.2", +] +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[[package]] +name = "certifi" +version = "2024.7.4" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." +groups = ["doc"] +files = [ + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +requires_python = ">=3.7.0" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["doc"] +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +groups = ["default", "doc"] +dependencies = [ + "colorama; platform_system == \"Windows\"", +] +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["default", "doc", "test"] +marker = "sys_platform == \"win32\" or platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.6.1" +requires_python = ">=3.8" +summary = "Code coverage measurement for Python" +groups = ["doc", "test"] +files = [ + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, +] + +[[package]] +name = "docutils" +version = "0.20.1" +requires_python = ">=3.7" +summary = "Docutils -- Python Documentation Utilities" +groups = ["doc"] +files = [ + {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, + {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" +groups = ["doc", "test"] +marker = "python_version < \"3.11\"" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[[package]] +name = "furo" +version = "2024.8.6" +requires_python = ">=3.8" +summary = "A clean customisable Sphinx documentation theme." +groups = ["doc"] +dependencies = [ + "beautifulsoup4", + "pygments>=2.7", + "sphinx-basic-ng>=1.0.0.beta2", + "sphinx<9.0,>=6.0", +] +files = [ + {file = "furo-2024.8.6-py3-none-any.whl", hash = "sha256:6cd97c58b47813d3619e63e9081169880fbe331f0ca883c871ff1f3f11814f5c"}, + {file = "furo-2024.8.6.tar.gz", hash = "sha256:b63e4cee8abfc3136d3bc03a3d45a76a850bada4d6374d24c1716b0e01394a01"}, +] + +[[package]] +name = "idna" +version = "3.7" +requires_python = ">=3.5" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["doc"] +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "Getting image size from png/jpeg/jpeg2000/gif file" +groups = ["doc"] +files = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, +] + +[[package]] +name = "importlib-metadata" +version = "8.2.0" +requires_python = ">=3.8" +summary = "Read metadata from Python packages" +groups = ["doc"] +marker = "python_version < \"3.10\"" +dependencies = [ + "zipp>=0.5", +] +files = [ + {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, + {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" +groups = ["doc", "test"] +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +groups = ["doc"] +dependencies = [ + "MarkupSafe>=2.0", +] +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[[package]] +name = "lxml" +version = "5.3.0" +requires_python = ">=3.6" +summary = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +groups = ["doc"] +files = [ + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, + {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, + {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, + {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, + {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, + {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, + {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, + {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, + {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, + {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, + {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, + {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, + {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, + {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, + {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +requires_python = ">=3.8" +summary = "Python port of markdown-it. Markdown parsing, done right!" +groups = ["default", "doc"] +dependencies = [ + "mdurl~=0.1", +] +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[[package]] +name = "markupsafe" +version = "2.1.5" +requires_python = ">=3.7" +summary = "Safely add untrusted strings to HTML/XML markup." +groups = ["doc"] +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.4.1" +requires_python = ">=3.8" +summary = "Collection of plugins for markdown-it-py" +groups = ["doc"] +dependencies = [ + "markdown-it-py<4.0.0,>=1.0.0", +] +files = [ + {file = "mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a"}, + {file = "mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +requires_python = ">=3.7" +summary = "Markdown URL utilities" +groups = ["default", "doc"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mypy" +version = "1.11.1" +requires_python = ">=3.8" +summary = "Optional static typing for Python" +groups = ["doc", "lint"] +dependencies = [ + "mypy-extensions>=1.0.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=4.6.0", +] +files = [ + {file = "mypy-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c"}, + {file = "mypy-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411"}, + {file = "mypy-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1e30dc3bfa4e157e53c1d17a0dad20f89dc433393e7702b813c10e200843b03"}, + {file = "mypy-1.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2c63350af88f43a66d3dfeeeb8d77af34a4f07d760b9eb3a8697f0386c7590b4"}, + {file = "mypy-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:a831671bad47186603872a3abc19634f3011d7f83b083762c942442d51c58d58"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, + {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, + {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, + {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, + {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, + {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, + {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, + {file = "mypy-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:749fd3213916f1751fff995fccf20c6195cae941dc968f3aaadf9bb4e430e5a2"}, + {file = "mypy-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b639dce63a0b19085213ec5fdd8cffd1d81988f47a2dec7100e93564f3e8fb3b"}, + {file = "mypy-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c956b49c5d865394d62941b109728c5c596a415e9c5b2be663dd26a1ff07bc0"}, + {file = "mypy-1.11.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45df906e8b6804ef4b666af29a87ad9f5921aad091c79cc38e12198e220beabd"}, + {file = "mypy-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:d44be7551689d9d47b7abc27c71257adfdb53f03880841a5db15ddb22dc63edb"}, + {file = "mypy-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2684d3f693073ab89d76da8e3921883019ea8a3ec20fa5d8ecca6a2db4c54bbe"}, + {file = "mypy-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79c07eb282cb457473add5052b63925e5cc97dfab9812ee65a7c7ab5e3cb551c"}, + {file = "mypy-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11965c2f571ded6239977b14deebd3f4c3abd9a92398712d6da3a772974fad69"}, + {file = "mypy-1.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a2b43895a0f8154df6519706d9bca8280cda52d3d9d1514b2d9c3e26792a0b74"}, + {file = "mypy-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:1a81cf05975fd61aec5ae16501a091cfb9f605dc3e3c878c0da32f250b74760b"}, + {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, + {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["doc", "lint"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "mypy" +version = "1.11.1" +extras = ["reports"] +requires_python = ">=3.8" +summary = "Optional static typing for Python" +groups = ["doc"] +dependencies = [ + "lxml", + "mypy==1.11.1", +] +files = [ + {file = "mypy-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c"}, + {file = "mypy-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411"}, + {file = "mypy-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1e30dc3bfa4e157e53c1d17a0dad20f89dc433393e7702b813c10e200843b03"}, + {file = "mypy-1.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2c63350af88f43a66d3dfeeeb8d77af34a4f07d760b9eb3a8697f0386c7590b4"}, + {file = "mypy-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:a831671bad47186603872a3abc19634f3011d7f83b083762c942442d51c58d58"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, + {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, + {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, + {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, + {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, + {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, + {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, + {file = "mypy-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:749fd3213916f1751fff995fccf20c6195cae941dc968f3aaadf9bb4e430e5a2"}, + {file = "mypy-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b639dce63a0b19085213ec5fdd8cffd1d81988f47a2dec7100e93564f3e8fb3b"}, + {file = "mypy-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c956b49c5d865394d62941b109728c5c596a415e9c5b2be663dd26a1ff07bc0"}, + {file = "mypy-1.11.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45df906e8b6804ef4b666af29a87ad9f5921aad091c79cc38e12198e220beabd"}, + {file = "mypy-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:d44be7551689d9d47b7abc27c71257adfdb53f03880841a5db15ddb22dc63edb"}, + {file = "mypy-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2684d3f693073ab89d76da8e3921883019ea8a3ec20fa5d8ecca6a2db4c54bbe"}, + {file = "mypy-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79c07eb282cb457473add5052b63925e5cc97dfab9812ee65a7c7ab5e3cb551c"}, + {file = "mypy-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11965c2f571ded6239977b14deebd3f4c3abd9a92398712d6da3a772974fad69"}, + {file = "mypy-1.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a2b43895a0f8154df6519706d9bca8280cda52d3d9d1514b2d9c3e26792a0b74"}, + {file = "mypy-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:1a81cf05975fd61aec5ae16501a091cfb9f605dc3e3c878c0da32f250b74760b"}, + {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, + {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, +] + +[[package]] +name = "myst-parser" +version = "3.0.1" +requires_python = ">=3.8" +summary = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," +groups = ["doc"] +dependencies = [ + "docutils<0.22,>=0.18", + "jinja2", + "markdown-it-py~=3.0", + "mdit-py-plugins~=0.4", + "pyyaml", + "sphinx<8,>=6", +] +files = [ + {file = "myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1"}, + {file = "myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87"}, +] + +[[package]] +name = "packaging" +version = "24.1" +requires_python = ">=3.8" +summary = "Core utilities for Python packages" +groups = ["doc", "test"] +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +requires_python = ">=3.8" +summary = "plugin and hook calling mechanisms for python" +groups = ["doc", "test"] +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[[package]] +name = "pydantic" +version = "2.8.2" +requires_python = ">=3.8" +summary = "Data validation using Python type hints" +groups = ["default", "doc"] +dependencies = [ + "annotated-types>=0.4.0", + "pydantic-core==2.20.1", + "typing-extensions>=4.12.2; python_version >= \"3.13\"", + "typing-extensions>=4.6.1; python_version < \"3.13\"", +] +files = [ + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, +] + +[[package]] +name = "pydantic-core" +version = "2.20.1" +requires_python = ">=3.8" +summary = "Core functionality for Pydantic validation and serialization" +groups = ["default", "doc"] +dependencies = [ + "typing-extensions!=4.7.0,>=4.6.0", +] +files = [ + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, +] + +[[package]] +name = "pydantic-settings" +version = "2.4.0" +requires_python = ">=3.8" +summary = "Settings management using Pydantic" +groups = ["default", "doc"] +dependencies = [ + "pydantic>=2.7.0", + "python-dotenv>=0.21.0", +] +files = [ + {file = "pydantic_settings-2.4.0-py3-none-any.whl", hash = "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315"}, + {file = "pydantic_settings-2.4.0.tar.gz", hash = "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88"}, +] + +[[package]] +name = "pygments" +version = "2.18.0" +requires_python = ">=3.8" +summary = "Pygments is a syntax highlighting package written in Python." +groups = ["default", "doc"] +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[[package]] +name = "pytest" +version = "8.3.2" +requires_python = ">=3.8" +summary = "pytest: simple powerful testing with Python" +groups = ["doc", "test"] +dependencies = [ + "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", + "iniconfig", + "packaging", + "pluggy<2,>=1.5", + "tomli>=1; python_version < \"3.11\"", +] +files = [ + {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, + {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, +] + +[[package]] +name = "python-dotenv" +version = "1.0.1" +requires_python = ">=3.8" +summary = "Read key-value pairs from a .env file and set them as environment variables" +groups = ["default", "doc"] +files = [ + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, +] + +[[package]] +name = "pytz" +version = "2024.1" +summary = "World timezone definitions, modern and historical" +groups = ["doc"] +marker = "python_version < \"3.9\"" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +requires_python = ">=3.8" +summary = "YAML parser and emitter for Python" +groups = ["doc"] +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +requires_python = ">=3.8" +summary = "Python HTTP for Humans." +groups = ["doc"] +dependencies = [ + "certifi>=2017.4.17", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.21.1", +] +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[[package]] +name = "rich" +version = "13.7.1" +requires_python = ">=3.7.0" +summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +groups = ["default"] +dependencies = [ + "markdown-it-py>=2.2.0", + "pygments<3.0.0,>=2.13.0", + "typing-extensions<5.0,>=4.0.0; python_version < \"3.9\"", +] +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +requires_python = ">=3.7" +summary = "Tool to Detect Surrounding Shell" +groups = ["default"] +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +summary = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +groups = ["doc"] +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + +[[package]] +name = "soupsieve" +version = "2.6" +requires_python = ">=3.8" +summary = "A modern CSS selector implementation for Beautiful Soup." +groups = ["doc"] +files = [ + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, +] + +[[package]] +name = "sphinx" +version = "7.1.2" +requires_python = ">=3.8" +summary = "Python documentation generator" +groups = ["doc"] +dependencies = [ + "Jinja2>=3.0", + "Pygments>=2.13", + "alabaster<0.8,>=0.7", + "babel>=2.9", + "colorama>=0.4.5; sys_platform == \"win32\"", + "docutils<0.21,>=0.18.1", + "imagesize>=1.3", + "importlib-metadata>=4.8; python_version < \"3.10\"", + "packaging>=21.0", + "requests>=2.25.0", + "snowballstemmer>=2.0", + "sphinxcontrib-applehelp", + "sphinxcontrib-devhelp", + "sphinxcontrib-htmlhelp>=2.0.0", + "sphinxcontrib-jsmath", + "sphinxcontrib-qthelp", + "sphinxcontrib-serializinghtml>=1.1.5", +] +files = [ + {file = "sphinx-7.1.2-py3-none-any.whl", hash = "sha256:d170a81825b2fcacb6dfd5a0d7f578a053e45d3f2b153fecc948c37344eb4cbe"}, + {file = "sphinx-7.1.2.tar.gz", hash = "sha256:780f4d32f1d7d1126576e0e5ecc19dc32ab76cd24e950228dcf7b1f6d3d9e22f"}, +] + +[[package]] +name = "sphinx-basic-ng" +version = "1.0.0b2" +requires_python = ">=3.7" +summary = "A modern skeleton for Sphinx themes." +groups = ["doc"] +dependencies = [ + "sphinx>=4.0", +] +files = [ + {file = "sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b"}, + {file = "sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9"}, +] + +[[package]] +name = "sphinx-click" +version = "6.0.0" +requires_python = ">=3.8" +summary = "Sphinx extension that automatically documents click applications" +groups = ["doc"] +dependencies = [ + "click>=8.0", + "docutils", + "sphinx>=4.0", +] +files = [ + {file = "sphinx_click-6.0.0-py3-none-any.whl", hash = "sha256:1e0a3c83bcb7c55497751b19d07ebe56b5d7b85eb76dd399cf9061b497adc317"}, + {file = "sphinx_click-6.0.0.tar.gz", hash = "sha256:f5d664321dc0c6622ff019f1e1c84e58ce0cecfddeb510e004cf60c2a3ab465b"}, +] + +[[package]] +name = "sphinx-design" +version = "0.5.0" +requires_python = ">=3.8" +summary = "A sphinx extension for designing beautiful, view size responsive web components." +groups = ["doc"] +dependencies = [ + "sphinx<8,>=5", +] +files = [ + {file = "sphinx_design-0.5.0-py3-none-any.whl", hash = "sha256:1af1267b4cea2eedd6724614f19dcc88fe2e15aff65d06b2f6252cee9c4f4c1e"}, + {file = "sphinx_design-0.5.0.tar.gz", hash = "sha256:e8e513acea6f92d15c6de3b34e954458f245b8e761b45b63950f65373352ab00"}, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.4" +requires_python = ">=3.8" +summary = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +groups = ["doc"] +files = [ + {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, + {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.2" +requires_python = ">=3.5" +summary = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +groups = ["doc"] +files = [ + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.0.1" +requires_python = ">=3.8" +summary = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +groups = ["doc"] +files = [ + {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, + {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +requires_python = ">=3.5" +summary = "A sphinx extension which renders display math in HTML via JavaScript" +groups = ["doc"] +files = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +requires_python = ">=3.5" +summary = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +groups = ["doc"] +files = [ + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +requires_python = ">=3.5" +summary = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +groups = ["doc"] +files = [ + {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, + {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +requires_python = ">=3.7" +summary = "A lil' TOML parser" +groups = ["doc", "lint", "test"] +marker = "python_version < \"3.11\"" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typer" +version = "0.12.3" +requires_python = ">=3.7" +summary = "Typer, build great CLIs. Easy to code. Based on Python type hints." +groups = ["default"] +dependencies = [ + "click>=8.0.0", + "rich>=10.11.0", + "shellingham>=1.3.0", + "typing-extensions>=3.7.4.3", +] +files = [ + {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, + {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, +] + +[[package]] +name = "typer" +version = "0.12.3" +extras = ["all"] +requires_python = ">=3.7" +summary = "Typer, build great CLIs. Easy to code. Based on Python type hints." +groups = ["default"] +dependencies = [ + "typer==0.12.3", +] +files = [ + {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, + {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["default", "doc", "lint"] +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "urllib3" +version = "2.2.2" +requires_python = ">=3.8" +summary = "HTTP library with thread-safe connection pooling, file post, and more." +groups = ["doc"] +files = [ + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, +] + +[[package]] +name = "zipp" +version = "3.20.0" +requires_python = ">=3.8" +summary = "Backport of pathlib-compatible object wrapper for zip files" +groups = ["doc"] +marker = "python_version < \"3.10\"" +files = [ + {file = "zipp-3.20.0-py3-none-any.whl", hash = "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d"}, + {file = "zipp-3.20.0.tar.gz", hash = "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..45ef773 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,134 @@ +[build-system] +build-backend = "setuptools.build_meta" +requires = [ + "setuptools==71.1.0", + "setuptools-scm==8.1.0", +] + +[project] +name = "wan" +description = "Wait and notify conveniently" +readme = "README.md" +keywords = [ + "copier-template", + "full-development-lifecycle", + "project-template", + "serious-scaffold", +] +license = { text = "MIT" } +authors = [ + { email = "afe.young@gmail.com", name = "Xiao Yang" }, +] +requires-python = ">=3.8" +classifiers = [ + "Development Status :: 4 - Beta", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dynamic = [ + "version", +] +dependencies = [ + "pydantic-settings", + "typer[all]", +] +urls.documentation = "https://you-n-g.github.io/wan" +urls.issue = "https://github.com/you-n-g/wan/issues" +urls.repository = "https://github.com/you-n-g/wan" +scripts.wan-cli = "wan.cli:app" + +[tool.pdm] +distribution = true + +[tool.pdm.dev-dependencies] +doc = [ + "Sphinx", + "autodoc-pydantic", + "coverage", + "furo", + "mypy[reports]", + "myst-parser", + "pytest", + "sphinx-click", + "sphinx-design", +] +lint = [ + "mypy", +] +test = [ + "coverage", + "pytest", +] + +[tool.setuptools_scm] +fallback_version = "0.0.0" + +[tool.ruff] +src = [ + "src", +] + +fix = true +lint.select = [ + "B", # flake8-bugbear + "D", # pydocstyle + "E", # pycodestyle error + "F", # Pyflakes + "I", # isort + "RUF100", # Unused noqa directive + "S", # flake8-bandit + "SIM", # flake8-simplify + "UP", # pyupgrade + "W", # pycodestyle warning +] +lint.per-file-ignores."tests/*" = [ + "S101", +] +lint.pydocstyle.convention = "google" + +[tool.codespell] +write-changes = true +check-filenames = true + +[tool.pyproject-fmt] +indent = 4 +keep_full_version = true +max_supported_python = "3.12" + +[tool.pytest.ini_options] +addopts = "-l -s --durations=0" +log_cli = true +log_cli_level = "info" +log_date_format = "%Y-%m-%d %H:%M:%S" +log_format = "%(asctime)s %(levelname)s %(message)s" +minversion = "6.0" + +[tool.coverage.report] +fail_under = 100 + +[tool.coverage.run] +source = [ + "wan", +] + +[tool.mypy] +check_untyped_defs = true +disallow_any_unimported = true +disallow_untyped_defs = true +enable_error_code = [ + "ignore-without-code", +] +exclude = [ + "build", + "doc", +] +no_implicit_optional = true +show_error_codes = true +warn_return_any = true +warn_unused_ignores = true diff --git a/scripts/generate-coverage-badge.sh b/scripts/generate-coverage-badge.sh new file mode 100644 index 0000000..7b24daa --- /dev/null +++ b/scripts/generate-coverage-badge.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +TOTAL_COVERAGE=$(coverage report --format=total) +COLOR="#9f9f9f" + +if [ "$TOTAL_COVERAGE" -gt 95 ]; then + COLOR="#4c1" +elif [ "$TOTAL_COVERAGE" -gt 90 ]; then + COLOR="#a3c51c" +elif [ "$TOTAL_COVERAGE" -gt 75 ]; then + COLOR="#dfb317" +elif [ "$TOTAL_COVERAGE" -gt 0 ]; then + COLOR="#e05d44" +fi + +COVERAGE_JSON_DIR=${1:-.} +mkdir -p "$COVERAGE_JSON_DIR" + +cat << EOF > "${COVERAGE_JSON_DIR}/coverage.json" +{ + "schemaVersion": 1, + "label": "coverage", + "message": "${TOTAL_COVERAGE}%", + "color": "${COLOR}" +} +EOF diff --git a/src/wan/__init__.py b/src/wan/__init__.py new file mode 100644 index 0000000..8a8721b --- /dev/null +++ b/src/wan/__init__.py @@ -0,0 +1 @@ +"""Init for the project.""" diff --git a/src/wan/cli.py b/src/wan/cli.py new file mode 100644 index 0000000..b423d02 --- /dev/null +++ b/src/wan/cli.py @@ -0,0 +1,23 @@ +"""Command Line Interface.""" + +import typer + +app = typer.Typer() + + +@app.command() +def run() -> None: + """Run command.""" + + +# NOTE(huxuan): callback is required for single command as a subcommand in typer. +# And it is a convenient way to document the cli here. +# Reference: https://typer.tiangolo.com/tutorial/commands/one-or-multiple/#one-command-and-one-callback +@app.callback(no_args_is_help=True) +def main() -> None: + """CLI for WAN.""" + + +# NOTE(huxuan): click object is used for document generation. +# Reference: https://github.com/tiangolo/typer/issues/200#issuecomment-796485787 +typer_click_object = typer.main.get_command(app) diff --git a/src/wan/py.typed b/src/wan/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/src/wan/settings.py b/src/wan/settings.py new file mode 100644 index 0000000..8e921b5 --- /dev/null +++ b/src/wan/settings.py @@ -0,0 +1,37 @@ +"""Settings Module.""" + +import logging +from logging import getLevelName +from typing import Optional + +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class GlobalSettings(BaseSettings): + """System level settings.""" + + ci: bool = False + """Indicator for whether or not in CI/CD environment.""" + + +class Settings(BaseSettings): + """Project specific settings.""" + + logging_level: Optional[str] = getLevelName(logging.INFO) + """Default logging level for the project.""" + + model_config = SettingsConfigDict( + env_prefix="WAN_", + ) + + +# NOTE(huxuan): `#:` style docstring is required for module attributes to satisfy both +# autodoc [1] and `check-docstring-first` in `pre-commit` [2]. +# [1] https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#directive-autoattribute +# [2] https://github.com/pre-commit/pre-commit-hooks/issues/159#issuecomment-559886109 + +#: Instance for system level settings. +global_settings = GlobalSettings() + +#: Instance for project specific settings. +settings = Settings() diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..6f62d03 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Init for the test.""" diff --git a/tests/cli_test.py b/tests/cli_test.py new file mode 100644 index 0000000..8ed3aca --- /dev/null +++ b/tests/cli_test.py @@ -0,0 +1,21 @@ +"""Test for cli.""" + +from typer.testing import CliRunner + +from wan.cli import app + +runner = CliRunner() + + +def test_cli() -> None: + """Test for cli.""" + result = runner.invoke(app) + assert result.exit_code == 0 + assert "Usage" in result.output + + +def test_cli_run() -> None: + """Test for run subcommand of the cli.""" + result = runner.invoke(app, "run") + assert result.exit_code == 0 + assert not result.output diff --git a/tests/pkg_test.py b/tests/pkg_test.py new file mode 100644 index 0000000..ded5cc4 --- /dev/null +++ b/tests/pkg_test.py @@ -0,0 +1,8 @@ +"""Test for pkg.""" + +import wan + + +def test_pkg() -> None: + """Test for pkg.""" + assert wan.__package__ == "wan" diff --git a/tests/settings_test.py b/tests/settings_test.py new file mode 100644 index 0000000..3e97f04 --- /dev/null +++ b/tests/settings_test.py @@ -0,0 +1,14 @@ +"""Test for settings.""" + +import os + +from wan.settings import global_settings, settings + + +def test_settings() -> None: + """Test for settings.""" + assert settings.logging_level == os.getenv( + "WAN_LOGGING_LEVEL", + "INFO", + ) + assert str(global_settings.ci).lower() == os.getenv("CI", "False").lower()