diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..81d8cf00 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file records the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 7840730ae93629100fb838b4beef7ee2 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/README.doctree b/.doctrees/README.doctree new file mode 100644 index 00000000..34ba9c8c Binary files /dev/null and b/.doctrees/README.doctree differ diff --git a/.doctrees/changelog.doctree b/.doctrees/changelog.doctree new file mode 100644 index 00000000..fe36de82 Binary files /dev/null and b/.doctrees/changelog.doctree differ diff --git a/.doctrees/cli_args.doctree b/.doctrees/cli_args.doctree new file mode 100644 index 00000000..5e3a6466 Binary files /dev/null and b/.doctrees/cli_args.doctree differ diff --git a/.doctrees/configuration.doctree b/.doctrees/configuration.doctree new file mode 100644 index 00000000..9d97ec20 Binary files /dev/null and b/.doctrees/configuration.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 00000000..2870aec5 Binary files /dev/null and b/.doctrees/environment.pickle differ diff --git a/.doctrees/example.doctree b/.doctrees/example.doctree new file mode 100644 index 00000000..c982e9cd Binary files /dev/null and b/.doctrees/example.doctree differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree new file mode 100644 index 00000000..d91c4d08 Binary files /dev/null and b/.doctrees/index.doctree differ diff --git a/.doctrees/migration.doctree b/.doctrees/migration.doctree new file mode 100644 index 00000000..d53e3d78 Binary files /dev/null and b/.doctrees/migration.doctree differ diff --git a/.doctrees/troubleshoot.doctree b/.doctrees/troubleshoot.doctree new file mode 100644 index 00000000..78046e96 Binary files /dev/null and b/.doctrees/troubleshoot.doctree differ diff --git a/.doctrees/what-is-new.doctree b/.doctrees/what-is-new.doctree new file mode 100644 index 00000000..0d53a883 Binary files /dev/null and b/.doctrees/what-is-new.doctree differ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 37cffb11..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @commit-check/developers diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml deleted file mode 100644 index 372f47c8..00000000 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Bug report -description: something went wrong -labels: ["bug"] -body: - - type: markdown - attributes: - value: this is for issues for `commit-check` - - type: textarea - id: freeform - attributes: - label: describe your issue - placeholder: 'I was doing ... I ran ... I expected ... I got ...' - validations: - required: true - - type: input - id: version - attributes: - label: commit-check version - placeholder: commit-check x.x.x - validations: - required: false - - type: textarea - id: configuration - attributes: - label: commit-check.toml or cchk.toml - description: (auto-rendered as toml, no need for backticks) - render: toml - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml deleted file mode 100644 index ee8099e1..00000000 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Feature request -description: Suggest an idea for this project -labels: ["enhancement"] - -body: - - type: markdown - attributes: - value: >- - Hi there! - - We'd appreciate it if you could search on commit-check's existing issues before filing - a feature request. - - - type: textarea - attributes: - label: What's the problem this feature will solve? - description: >- - What are you trying to do, that you are unable to achieve with commit-check as it currently stands? - validations: - required: true - - - type: textarea - attributes: - label: Describe the solution you'd like - description: >- - A clear and concise description of what you want to happen. Please use examples - of real-world use cases that this would help with, and how it solves the - the problem described above. - validations: - required: true - - - type: textarea - attributes: - label: Additional context - description: >- - Add any other context, links, etc. relevant to the feature request. - validations: - required: false diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index 8325a0ce..00000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,219 +0,0 @@ -# Commit Check Development Instructions - -Commit Check is a Python CLI tool and pre-commit hook that validates commit messages, branch naming, author information, and more according to Conventional Commits and Conventional Branch conventions. - -Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here. - -## Working Effectively - -### Prerequisites and Setup -```bash -# Install Python dependencies (required) -python3 -m pip install --upgrade pip -python3 -m pip install nox - -# Install package in development mode with PYTHONPATH (network timeout workaround) -export PYTHONPATH=/home/runner/work/commit-check/commit-check -python3 -m pip install pyyaml # Core dependency -``` - -### Build and Package -```bash -# Build wheel package -- NETWORK ISSUES: Often fails due to PyPI timeouts in CI environments -# Takes ~10 seconds when working, ~20+ seconds when timing out -nox -s build - -# Manual build workaround when nox fails: -python3 -m pip wheel --no-deps -w dist . # NETWORK ISSUES: Also fails due to build dependencies - -# Install wheel (depends on build) -nox -s install # NETWORK ISSUES: Often fails due to PyPI timeouts in CI environments -``` - -### Testing -```bash -# Run tests directly (fastest, most reliable) -- takes ~1 second. Set timeout to 30+ seconds. -PYTHONPATH=/home/runner/work/commit-check/commit-check python3 -m pytest tests/ -v - -# Alternative: Run tests via nox (may timeout due to network) -nox -s coverage # NETWORK ISSUES: Often fails due to PyPI timeouts, takes 5+ minutes when working -``` - -### Linting and Code Quality -```bash -# NETWORK ISSUES: nox -s lint often fails due to pre-commit installation timeouts -# Manual workaround for linting: -python3 -m pip install pre-commit # May timeout, retry if needed -pre-commit install --hook-type pre-commit -pre-commit run --all-files --show-diff-on-failure # Takes 2-5 minutes for full run -``` - -### Documentation -```bash -# NETWORK ISSUES: Documentation builds fail due to external dependencies (fonts.google.com) -# Install docs dependencies (may timeout) -python3 -m pip install sphinx-immaterial sphinx-autobuild - -# Build docs -- FAILS due to network restrictions in CI environments -PYTHONPATH=/home/runner/work/commit-check/commit-check sphinx-build -E -W -b html docs _build/html -``` - -## Validation Scenarios - -### Manual Testing (Essential after changes) -Always manually validate functionality with these scenarios: - -```bash -# Set PYTHONPATH for direct module execution -export PYTHONPATH=/home/runner/work/commit-check/commit-check - -# Test 1: Valid conventional commit message -echo "fix: correct issue with validation" > test_commit.txt -python3 -m commit_check.main --message test_commit.txt -# Expected: Exit code 0 (success) - -# Test 2: Invalid commit message format -echo "invalid commit message" > test_commit_invalid.txt -python3 -m commit_check.main --message test_commit_invalid.txt -# Expected: Exit code 1, shows ASCII art rejection and error details - -# Test 3: Complex conventional commit with scope and body -echo "feat(api): add new user endpoint - -This adds support for creating new users via the REST API. - -Breaking Change: API version updated to v2" > test_complex_commit.txt -python3 -m commit_check.main --message test_complex_commit.txt -# Expected: Exit code 0 (success) - -# Test 4: Branch name validation -python3 -m commit_check.main --branch -# Expected: Depends on current branch name, should show validation result - -# Test 5: Help and version -python3 -m commit_check.main --help -python3 -m commit_check.main --version - -# Test 6: Configuration validation -python3 -m commit_check.main --config .commit-check.yml --dry-run - -# Test 7: Multiple checks at once -python3 -m commit_check.main --message test_commit.txt --branch --dry-run - -# Clean up test files -rm -f test_commit.txt test_commit_invalid.txt test_complex_commit.txt -``` - -### Integration Testing -```bash -# Test as pre-commit hook -pre-commit try-repo . --verbose --hook-stage commit-msg - -# Test wheel installation -python3 -m pip install dist/*.whl # After running nox -s build -commit-check --help # Verify CLI works -cchk --help # Verify alias works -``` - -## Known Issues and Workarounds - -### Network Connectivity -- **Issue**: PyPI timeouts during pip install in CI environments -- **Workaround**: Use `--timeout=10` flag, install dependencies individually, or use PYTHONPATH for development - -### Build System -- **Issue**: nox sessions fail due to dependency installation timeouts -- **Workaround**: Run commands directly with PYTHONPATH instead of nox sessions - -### Documentation -- **Issue**: Sphinx build fails due to external font loading (fonts.google.com) -- **Status**: Cannot be fixed in restricted CI environments - -## Configuration and Important Files - -### Repository Structure -``` -. -├── commit_check/ # Main Python package -│ ├── __init__.py # Package configuration and defaults -│ ├── main.py # CLI entry point -│ ├── commit.py # Commit message validation -│ ├── branch.py # Branch name validation -│ ├── author.py # Author validation -│ └── util.py # Utility functions -├── tests/ # Test suite (108 tests) -├── docs/ # Sphinx documentation -├── .commit-check.yml # Default configuration -├── pyproject.toml # Package metadata and build config -├── noxfile.py # Build automation -└── .pre-commit-config.yaml # Pre-commit configuration -``` - -### Key Files -- **pyproject.toml**: Package configuration, dependencies, entry points -- **noxfile.py**: Automated build tasks (lint, test, build, docs) -- **.commit-check.yml**: Default validation rules for the tool itself -- **commit_check/__init__.py**: Default configuration templates and constants - -## Common Commands Summary - -| Command | Purpose | Timing | Notes | -|---------|---------|---------|-------| -| `nox -s build` | Build wheel | ~10s | Reliable | -| `pytest tests/` | Run tests | ~1s | Fastest, most reliable | -| `nox -s coverage` | Tests + coverage | 5+ min | Often times out | -| `nox -s lint` | Code quality | 2-5 min | Often times out | -| `python3 -m commit_check.main --help` | CLI help | Instant | Always works | - -## Tool Behavior and Features - -### Commit Message Validation -- **Conventional Commits**: Enforces standard format: `type(scope): description` -- **Supported types**: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test -- **Scope**: Optional, e.g., `feat(api): add endpoint` -- **Breaking changes**: Supports `!` notation: `feat!: breaking change` -- **Merge commits**: Special handling for merge commit messages - -### Branch Name Validation -- **Conventional Branches**: Enforces patterns like `feature/`, `bugfix/`, etc. -- **Allowed prefixes**: bugfix/, feature/, release/, hotfix/, task/, chore/ -- **Special branches**: master, main, HEAD, PR-* are allowed - -### Author Validation -- **Author name**: Checks for valid name format -- **Author email**: Validates email format -- **Commit signoff**: Checks for "Signed-off-by:" trailer - -### Exit Codes -- **0**: All checks passed -- **1**: One or more checks failed -- **Error output**: Colorized ASCII art rejection message with specific error details - -## When to Use What - -### For Quick Development and Testing -- **Use**: Direct Python module execution with PYTHONPATH -- **Commands**: `PYTHONPATH=/home/runner/work/commit-check/commit-check python3 -m commit_check.main` -- **Best for**: Testing changes, debugging, manual validation - -### For Production Builds (when network works) -- **Use**: nox sessions for full build pipeline -- **Commands**: `nox -s build`, `nox -s coverage`, `nox -s lint` -- **Best for**: CI/CD, release preparation, comprehensive testing - -### For Isolated Testing -- **Use**: Direct pytest execution -- **Commands**: `PYTHONPATH=/home/runner/work/commit-check/commit-check python3 -m pytest tests/` -- **Best for**: Unit testing, TDD, debugging test failures - -### For Pre-commit Integration -- **Use**: pre-commit commands -- **Commands**: `pre-commit try-repo .`, `pre-commit run --all-files` -- **Best for**: Validating hook behavior, testing integration - -## Development Workflow -1. **Always** set `export PYTHONPATH=/home/runner/work/commit-check/commit-check` -2. **Always** test CLI functionality manually after changes using validation scenarios above -3. **Always** run `pytest tests/` before committing changes -4. **Always** verify build works with `nox -s build` -5. Avoid relying on nox for dependency installation in CI environments diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 755e981a..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,15 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: github-actions - directory: / - schedule: - interval: "weekly" - - package-ecosystem: pip - directory: / - schedule: - interval: "weekly" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml deleted file mode 100644 index 0d0b1c99..00000000 --- a/.github/release-drafter.yml +++ /dev/null @@ -1 +0,0 @@ -_extends: .github diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 0d0b1c99..00000000 --- a/.github/stale.yml +++ /dev/null @@ -1 +0,0 @@ -_extends: .github diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml deleted file mode 100644 index 02a97fa9..00000000 --- a/.github/workflows/codspeed.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: CodSpeed - -permissions: - contents: read - -on: - push: - branches: - - "main" - paths: - - "commit_check/**" - - "tests/**" - - ".github/workflows/codspeed.yml" - - "pyproject.toml" - pull_request: - branches: - - "main" - paths: - - "commit_check/**" - - "tests/**" - - ".github/workflows/codspeed.yml" - - "pyproject.toml" - # `workflow_dispatch` allows CodSpeed to trigger backtest - # performance analysis in order to generate initial data. - workflow_dispatch: - -jobs: - benchmarks: - name: Run benchmarks - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: "3.13" - - - name: Install dependencies - run: pip install -e .[test] - - - name: Run benchmarks - uses: CodSpeedHQ/action@346a2d8a8d9d38909abd0bc3d23f773110f076ad # v4.4.1 - with: - token: ${{ secrets.CODSPEED_TOKEN }} - run: pytest tests/ --codspeed - mode: instrumentation # https://codspeed.io/docs/instruments diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml deleted file mode 100644 index 13e989a1..00000000 --- a/.github/workflows/labeler.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: PR Autolabeler - -permissions: - contents: write - pull-requests: write - -on: - # pull_request event is required for autolabeler - pull_request: - types: [opened, reopened, synchronize] - -jobs: - draft-release: - uses: commit-check/.github/.github/workflows/release-drafter.yml@main diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index efced516..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,114 +0,0 @@ -name: main - -permissions: - contents: write - -on: - push: - branches: - - main - pull_request: - paths: - - "**.py" - - pyproject.toml - - ".github/workflows/main.yml" - - ".pre-commit-config.yaml" - - "!docs/**" - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: '3.x' - - - name: Install nox - run: | - python -m pip install --upgrade pip - python -m pip install nox - - - name: Run pre-commit - run: | - nox -s lint - nox -s test-hook - - - name: Build wheel - run: nox -s build - - name: Upload wheel as artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: commit-check_wheel - path: ${{ github.workspace }}/dist/*.whl - - name: Run commit-check - run: nox -s commit-check - - - name: Collect Coverage - run: nox -s coverage - - - uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5.0.2 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./coverage.xml - fail_ci_if_error: true # optional (default = false) - verbose: true # optional (default = false) - - install: - needs: [build] - strategy: - fail-fast: false - matrix: - py: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] - os: ['windows-latest', 'ubuntu-24.04', 'macos-latest'] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6.0.1 - - uses: actions/setup-python@v6.1.0 - with: - python-version: ${{ matrix.py }} - - run: | - pip install --upgrade pip - pip install .[dev] - - - name: Download wheel artifact - uses: actions/download-artifact@v7 - with: - name: commit-check_wheel - path: dist - - - name: Install test - # using a wildcard as filename on Windows requires a bash shell - shell: bash - run: nox -s install - - docs: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v6.0.1 - - uses: actions/setup-python@v6.1.0 - with: - python-version: "3.10" - - - name: Install nox - run: | - python -m pip install --upgrade pip - python -m pip install nox - - - name: Build docs - run: nox -s docs - - - name: Save built docs as artifact - uses: actions/upload-artifact@v6 - with: - name: "commit-check_docs" - path: ${{ github.workspace }}/_build/html - - - name: Upload docs to github pages - # only publish doc changes from main branch - if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' - uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./_build/html diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml deleted file mode 100644 index cda81320..00000000 --- a/.github/workflows/publish-package.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: publish package - -on: - release: - branches: [main] - types: [published] - workflow_dispatch: - -permissions: - id-token: write - attestations: write - -jobs: - publish: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - # use fetch --all for setuptools_scm to work - with: - fetch-depth: 0 - - name: Set up Python - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: '3.x' - - - name: Build wheel - run: | - # Install dependencies - python -m pip install --upgrade pip twine - # Build wheel - python -m pip wheel -w dist . - # Check distribution - twine check dist/commit_check* - - - name: Create attestations - uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 - with: - subject-path: "dist/commit_check*" - - - name: Publish package to TestPyPI - if: github.event_name == 'workflow_dispatch' && github.repository == 'commit-check/commit-check' - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.TEST_PYPI_TOKEN }} - run: twine upload --repository testpypi dist/commit_check* - continue-on-error: true - - - name: Publish package to PyPI - if: github.event_name != 'workflow_dispatch' && github.repository == 'commit-check/commit-check' - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} - run: twine upload dist/commit_check* diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml deleted file mode 100644 index 182ecec1..00000000 --- a/.github/workflows/release-drafter.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Release Drafter - -on: - push: - branches: - - "main" - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - draft-release: - uses: commit-check/.github/.github/workflows/release-drafter.yml@main diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6e9ea54f..00000000 --- a/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -commit_check/__pycache__/ -commit_check.egg-info -__pycache__ -.mypy_cache -.vscode -venv -.venv -UNKNOWN.egg-info -dist -build -tests/__pycache__ -.coverage -coverage.xml -.nox -_build/ - -# docs -docs/_build -docs/cli_args.rst -docs/__pycache__ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 46d7da4b..00000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# https://pre-commit.ci/ -ci: - autofix_commit_msg: 'ci: auto fixes from pre-commit.com hooks' - autoupdate_commit_msg: 'ci: pre-commit autoupdate' - autoupdate_schedule: quarterly - -# https://pre-commit.com/ -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v6.0.0 - hooks: - - id: check-yaml - - id: check-toml - - id: end-of-file-fixer - - id: trailing-whitespace - - id: name-tests-test -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.1 - hooks: - - id: ruff-check - args: [ --fix ] - - id: ruff-format -- repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.18.2 - hooks: - - id: mypy - additional_dependencies: [types-PyYAML] - exclude: ^testing/resources/ -- repo: https://github.com/codespell-project/codespell - rev: v2.4.1 - hooks: - - id: codespell -- repo: https://github.com/commit-check/commit-check - rev: v2.0.0 - hooks: - - id: check-message - stages: [commit-msg] - - id: check-branch # uncomment if you need. - - id: check-author-name # uncomment if you need. - - id: check-author-email # uncomment if you need. diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml deleted file mode 100644 index 15456a62..00000000 --- a/.pre-commit-hooks.yaml +++ /dev/null @@ -1,29 +0,0 @@ -- id: check-message - name: check commit message - description: ensures commit message to match regex - entry: commit-check - args: [--message] - stages: [commit-msg] - pass_filenames: true - language: python -- id: check-branch - name: check branch name - description: ensures branch name to match regex - entry: commit-check - args: [--branch] - pass_filenames: false - language: python -- id: check-author-name - name: check committer name - description: ensures committer name to match regex - entry: commit-check - args: [--author-name] - pass_filenames: false - language: python -- id: check-author-email - name: check committer email - description: ensures committer email to match regex - entry: commit-check - args: [--author-email] - pass_filenames: false - language: python diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 045335c2..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,44 +0,0 @@ -# Contributing - -Thank you for investing your time in contributing to our project! We welcome feedback, bug reports, and pull requests! - -## New contributor guide - -Our development branch is `main`. When submitting pull requests, please adhere to the following guidelines: - -* Add tests for any new features and bug fixes. -* Put a reasonable amount of comments into the code. -* Fork [commit-check](https://github.com/commit-check/commit-check) on your GitHub user account. -* Create a branch from `main`, make your changes on the new branch, and then create a PR against the `main` branch of the commit-check repository. -* Separate unrelated changes into multiple pull requests for better review and management. - -By contributing any code or documentation to this repository (by raising pull requests or otherwise), you explicitly agree to the [License Agreement](https://github.com/commit-check/commit-check/blob/main/LICENSE). - -We appreciate your contributions to make Commit Check even better! - -## Development - -### Debug commit-check pre-commit hook - -```bash -pre-commit try-repo ./../commit-check/ check-message --verbose --hook-stage commit-msg --commit-msg-filename .git/COMMIT_EDITMSG -``` - -### Debug commit-check wheel package - -```bash -python3 -m pip install --upgrade pip -pip install -e ./../commit-check/ -commit-check -m -``` - -### Test commit-check pre-commit hook on GitHub - -```yaml -- repo: https://github.com/commit-check/commit-check - rev: the tag or revision # update it to test commit hash - hooks: - - id: check-message - - id: check-branch - - id: check-author-email -``` diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 3b0c3663..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 shenxianpeng (xianpeng.shen@gmail.com) - -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/README.html b/README.html new file mode 100644 index 00000000..9b4f93f1 --- /dev/null +++ b/README.html @@ -0,0 +1,712 @@ + + + + + + + + + + + + + + + + + + + + How to build the docs - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

How to build the docs

+

From the root directory of the repository, do the following to steps

+
    +
  1. Install docs’ dependencies

    +
    pip install nox
    +
    +
    +
  2. +
  3. Build the docs

    +
    nox -s docs
    +
    +
    +

    Browse the files in /_build/html with your internet browser to see the rendered +output.

    +
  4. +
+ + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/README.rst b/README.rst deleted file mode 100644 index 2ec1c52d..00000000 --- a/README.rst +++ /dev/null @@ -1,177 +0,0 @@ -Commit Check -============ - -.. |pypi-version| image:: https://img.shields.io/pypi/v/commit-check?logo=python&logoColor=white&color=%232c9ccd - :target: https://pypi.org/project/commit-check/ - :alt: PyPI - -.. |ci-badge| image:: https://github.com/commit-check/commit-check/actions/workflows/main.yml/badge.svg - :target: https://github.com/commit-check/commit-check/actions/workflows/main.yml - :alt: CI - -.. |sonar-badge| image:: https://sonarcloud.io/api/project_badges/measure?project=commit-check_commit-check&metric=alert_status - :target: https://sonarcloud.io/summary/new_code?id=commit-check_commit-check - :alt: Quality Gate Status - -.. |codecov-badge| image:: https://codecov.io/gh/commit-check/commit-check/branch/main/graph/badge.svg?token=GC2U5V5ZRT - :target: https://codecov.io/gh/commit-check/commit-check - :alt: CodeCov - -.. |commit-check-badge| image:: https://img.shields.io/badge/commit--check-enabled-brightgreen?logo=Git&logoColor=white&color=%232c9ccd - :target: https://github.com/commit-check/commit-check - :alt: commit-check - -.. |slsa-badge| image:: https://slsa.dev/images/gh-badge-level3.svg - :target: https://slsa.dev - :alt: SLSA - -|ci-badge| |sonar-badge| |pypi-version| |commit-check-badge| |codecov-badge| |slsa-badge| - -Overview --------- - -**Commit Check** (aka **cchk**) is an open-source tool that enforces commit metadata standards — including commit messages, branch naming, committer name/email, commit signoff, and more — helping teams maintain consistency and compliance. - -As a lightweight alternative to GitHub Enterprise `Metadata restrictions `_ -and Bitbucket's paid plugin `Yet Another Commit Checker `_, Commit Check integrates DevOps principles and Infrastructure as Code (IaC) practices for a modern workflow. - -What’s New in v2.0.0 --------------------- - -Version 2.0.0 is a major release featuring a new configuration format, a modernized architecture, and an improved user experience. - -**✨ Highlights** - -* **TOML Configuration** — Replaces ``.commit-check.yml`` with ``cchk.toml`` or ``commit-check.toml`` for clearer, more consistent syntax. -* **Simplified CLI & Hooks** — Legacy pre-commit hooks and options removed to deliver a cleaner, more streamlined interface. -* **New Validation Engine** — Fully redesigned for greater flexibility, performance, and maintainability. - -For the full list of updates and improvements, visit the `What's New `_ page. - -Installation ------------- - -To install Commit Check, you can use pip: - -.. code-block:: bash - - pip install commit-check - -Or install directly from the GitHub repository: - -.. code-block:: bash - - pip install git+https://github.com/commit-check/commit-check.git@main - -Then, run ``commit-check --help`` or ``cchk --help`` (alias for ``commit-check``) from the command line. -For more information, see the `docs `_. - - -Configuration -------------- - -Use Default Configuration -~~~~~~~~~~~~~~~~~~~~~~~~~ - -- **Commit Check** uses a `default configuration `_ if you do not provide a ``cchk.toml`` or ``commit-check.toml`` file. - -- The default configuration is lenient — it only checks whether commit messages follow the `Conventional Commits `_ specification and branch names follow the `Conventional Branch `_ convention. - -Use Custom Configuration -~~~~~~~~~~~~~~~~~~~~~~~~ - -To customize the behavior, create a configuration file named ``cchk.toml`` or ``commit-check.toml`` in your repository's root directory, e.g., `cchk.toml `_ - -Usage ------ - -For detailed usage instructions including pre-commit hooks, CLI commands, and STDIN examples, see the `Usage Examples documentation `_. - -Examples --------- - -Check Commit Message Failed - -.. code-block:: text - - Commit rejected by Commit-Check. - - (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) - / ._. \ / ._. \ / ._. \ / ._. \ / ._. \ - __\( C )/__ __\( H )/__ __\( E )/__ __\( C )/__ __\( K )/__ - (_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._) - || E || || R || || R || || O || || R || - _.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._ - (.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.) - `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ - - Commit rejected. - - Type message check failed ==> test commit message check - It doesn't match regex: ^(chore|ci|docs|feat|fix|refactor|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)|(Merge).*|(fixup!.*) - The commit message should follow Conventional Commits. See https://www.conventionalcommits.org - Suggest: Use (): with allowed types - - -Check Branch Naming Failed - -.. code-block:: text - - Commit rejected by Commit-Check. - - (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) - / ._. \ / ._. \ / ._. \ / ._. \ / ._. \ - __\( C )/__ __\( H )/__ __\( E )/__ __\( C )/__ __\( K )/__ - (_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._) - || E || || R || || R || || O || || R || - _.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._ - (.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.) - `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ - - Commit rejected. - - Type branch check failed ==> test-branch - It doesn't match regex: ^(feature|bugfix|hotfix|release|chore|feat|fix)\/.+|(master)|(main)|(HEAD)|(PR-.+) - The branch should follow Conventional Branch. See https://conventional-branch.github.io/ - Suggest: Use / with allowed types or ignore_authors in config branch section to bypass - -More examples see `example documentation `_. - -Badging your repository ------------------------ - -You can add a badge to your repository to show that you use commit-check! - -.. image:: https://img.shields.io/badge/commit--check-enabled-brightgreen?logo=Git&logoColor=white&color=%232c9ccd - :target: https://github.com/commit-check/commit-check - :alt: commit-check - -Markdown - -.. code-block:: text - - [![commit-check](https://img.shields.io/badge/commit--check-enabled-brightgreen?logo=Git&logoColor=white&color=%232c9ccd)](https://github.com/commit-check/commit-check) - -reStructuredText - -.. code-block:: text - - .. image:: https://img.shields.io/badge/commit--check-enabled-brightgreen?logo=Git&logoColor=white&color=%232c9ccd - :target: https://github.com/commit-check/commit-check - :alt: commit-check - - -Versioning ----------- - -Versioning follows `Semantic Versioning `_. - -Have question or feedback? --------------------------- - -Please post to `issues `_ for feedback, feature requests, or bug reports. - -License -------- - -This project is released under the `MIT License `_ diff --git a/docs/README.rst b/_sources/README.rst.txt similarity index 100% rename from docs/README.rst rename to _sources/README.rst.txt diff --git a/docs/changelog.rst b/_sources/changelog.rst.txt similarity index 100% rename from docs/changelog.rst rename to _sources/changelog.rst.txt diff --git a/_sources/cli_args.rst.txt b/_sources/cli_args.rst.txt new file mode 100644 index 00000000..f04ec977 --- /dev/null +++ b/_sources/cli_args.rst.txt @@ -0,0 +1,45 @@ +commit-check --help +============================== + +usage: commit-check [-h] [-v] [-c CONFIG] [-m [MESSAGE]] [-b] [-n] [-e] [-d] + +Check commit message, branch name, author name, email, and more. + +options: + +.. std:option:: -h, --help + + -h, --help show this help message and exit + +.. std:option:: -v, --version + + -v, --version show program's version number and exit + +.. std:option:: -c, --config + + -c CONFIG, --config CONFIG + path to config file (cchk.toml or commit-check.toml). + If not specified, searches for cchk.toml in current + directory + +.. std:option:: -m, --message + + -m [MESSAGE], --message [MESSAGE] + validate commit message. Optionally specify file path, + otherwise reads from stdin if available + +.. std:option:: -b, --branch + + -b, --branch check current git branch name + +.. std:option:: -n, --author-name + + -n, --author-name check git author name + +.. std:option:: -e, --author-email + + -e, --author-email check git author email + +.. std:option:: -d, --dry-run + + -d, --dry-run perform a dry run without failing (always returns 0) diff --git a/docs/configuration.rst b/_sources/configuration.rst.txt similarity index 100% rename from docs/configuration.rst rename to _sources/configuration.rst.txt diff --git a/docs/example.rst b/_sources/example.rst.txt similarity index 100% rename from docs/example.rst rename to _sources/example.rst.txt diff --git a/docs/index.rst b/_sources/index.rst.txt similarity index 100% rename from docs/index.rst rename to _sources/index.rst.txt diff --git a/docs/migration.rst b/_sources/migration.rst.txt similarity index 100% rename from docs/migration.rst rename to _sources/migration.rst.txt diff --git a/docs/troubleshoot.rst b/_sources/troubleshoot.rst.txt similarity index 100% rename from docs/troubleshoot.rst rename to _sources/troubleshoot.rst.txt diff --git a/docs/what-is-new.rst b/_sources/what-is-new.rst.txt similarity index 100% rename from docs/what-is-new.rst rename to _sources/what-is-new.rst.txt diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..7ebbd6d0 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,914 @@ +/* + * Sphinx stylesheet -- basic theme. + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin-top: 10px; +} + +ul.search li { + padding: 5px 0; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..7e4c114f --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/docs/_static/extra_css.css b/_static/extra_css.css similarity index 100% rename from docs/_static/extra_css.css rename to _static/extra_css.css diff --git a/_static/fonts/00254b3347f6117a719cec84ec0a8d0b.woff2 b/_static/fonts/00254b3347f6117a719cec84ec0a8d0b.woff2 new file mode 100644 index 00000000..189ec1fc Binary files /dev/null and b/_static/fonts/00254b3347f6117a719cec84ec0a8d0b.woff2 differ diff --git a/_static/fonts/0204e961adca27dd4947c6df130dd96f.woff2 b/_static/fonts/0204e961adca27dd4947c6df130dd96f.woff2 new file mode 100644 index 00000000..1df1d0fc Binary files /dev/null and b/_static/fonts/0204e961adca27dd4947c6df130dd96f.woff2 differ diff --git a/_static/fonts/026a36b060c2ef6c88ac125a50e8b4c9.woff2 b/_static/fonts/026a36b060c2ef6c88ac125a50e8b4c9.woff2 new file mode 100644 index 00000000..8fdc9ca0 Binary files /dev/null and b/_static/fonts/026a36b060c2ef6c88ac125a50e8b4c9.woff2 differ diff --git a/_static/fonts/027cb81785975d282bd176dd05d6cd51.woff2 b/_static/fonts/027cb81785975d282bd176dd05d6cd51.woff2 new file mode 100644 index 00000000..988246ac Binary files /dev/null and b/_static/fonts/027cb81785975d282bd176dd05d6cd51.woff2 differ diff --git a/_static/fonts/04a4e747fa3f0133c028bd4d76ffcb4f.woff2 b/_static/fonts/04a4e747fa3f0133c028bd4d76ffcb4f.woff2 new file mode 100644 index 00000000..8bb531d8 Binary files /dev/null and b/_static/fonts/04a4e747fa3f0133c028bd4d76ffcb4f.woff2 differ diff --git a/_static/fonts/04ae2fa764d886b85410579faccf3e3e.woff2 b/_static/fonts/04ae2fa764d886b85410579faccf3e3e.woff2 new file mode 100644 index 00000000..6f74187f Binary files /dev/null and b/_static/fonts/04ae2fa764d886b85410579faccf3e3e.woff2 differ diff --git a/_static/fonts/05ada379c350a1406544195bc7289117.woff2 b/_static/fonts/05ada379c350a1406544195bc7289117.woff2 new file mode 100644 index 00000000..0f99658d Binary files /dev/null and b/_static/fonts/05ada379c350a1406544195bc7289117.woff2 differ diff --git a/_static/fonts/079db204eccfd1129698a5247c2e088b.woff2 b/_static/fonts/079db204eccfd1129698a5247c2e088b.woff2 new file mode 100644 index 00000000..db3d7a87 Binary files /dev/null and b/_static/fonts/079db204eccfd1129698a5247c2e088b.woff2 differ diff --git a/_static/fonts/079efa5d2641f256a97c9c802c168ef3.woff2 b/_static/fonts/079efa5d2641f256a97c9c802c168ef3.woff2 new file mode 100644 index 00000000..68c8946d Binary files /dev/null and b/_static/fonts/079efa5d2641f256a97c9c802c168ef3.woff2 differ diff --git a/_static/fonts/0bf080b4cbce22785a90a3b464e34dc4.woff2 b/_static/fonts/0bf080b4cbce22785a90a3b464e34dc4.woff2 new file mode 100644 index 00000000..8c60e390 Binary files /dev/null and b/_static/fonts/0bf080b4cbce22785a90a3b464e34dc4.woff2 differ diff --git a/_static/fonts/0ee2e6f8f9dcd2af7bc0c6b519c28395.woff2 b/_static/fonts/0ee2e6f8f9dcd2af7bc0c6b519c28395.woff2 new file mode 100644 index 00000000..b35bba2d Binary files /dev/null and b/_static/fonts/0ee2e6f8f9dcd2af7bc0c6b519c28395.woff2 differ diff --git a/_static/fonts/0ef8a8fa25c458bcf4ac50a6dd593225.woff2 b/_static/fonts/0ef8a8fa25c458bcf4ac50a6dd593225.woff2 new file mode 100644 index 00000000..5ee456d8 Binary files /dev/null and b/_static/fonts/0ef8a8fa25c458bcf4ac50a6dd593225.woff2 differ diff --git a/_static/fonts/0f65443c2941435f9a90afb8921573f4.woff2 b/_static/fonts/0f65443c2941435f9a90afb8921573f4.woff2 new file mode 100644 index 00000000..33614b92 Binary files /dev/null and b/_static/fonts/0f65443c2941435f9a90afb8921573f4.woff2 differ diff --git a/_static/fonts/0fe4d8168abe6e917ef92b63a22ebccb.woff2 b/_static/fonts/0fe4d8168abe6e917ef92b63a22ebccb.woff2 new file mode 100644 index 00000000..a2c5e628 Binary files /dev/null and b/_static/fonts/0fe4d8168abe6e917ef92b63a22ebccb.woff2 differ diff --git a/_static/fonts/0feda7435983533516a4869176c31719.ttf b/_static/fonts/0feda7435983533516a4869176c31719.ttf new file mode 100644 index 00000000..1fb82d1f Binary files /dev/null and b/_static/fonts/0feda7435983533516a4869176c31719.ttf differ diff --git a/_static/fonts/117c76def7e509f636b6992214a3e006.woff2 b/_static/fonts/117c76def7e509f636b6992214a3e006.woff2 new file mode 100644 index 00000000..9d55880b Binary files /dev/null and b/_static/fonts/117c76def7e509f636b6992214a3e006.woff2 differ diff --git a/_static/fonts/117fa76afb2f349d9d3e898f24eb5263.woff2 b/_static/fonts/117fa76afb2f349d9d3e898f24eb5263.woff2 new file mode 100644 index 00000000..cd98dbb9 Binary files /dev/null and b/_static/fonts/117fa76afb2f349d9d3e898f24eb5263.woff2 differ diff --git a/_static/fonts/11decf95fec8f66b914587f5c114f9c4.ttf b/_static/fonts/11decf95fec8f66b914587f5c114f9c4.ttf new file mode 100644 index 00000000..09d59138 Binary files /dev/null and b/_static/fonts/11decf95fec8f66b914587f5c114f9c4.ttf differ diff --git a/_static/fonts/11ed281341a6dd16e758cb1e38e59f78.woff2 b/_static/fonts/11ed281341a6dd16e758cb1e38e59f78.woff2 new file mode 100644 index 00000000..85a32c28 Binary files /dev/null and b/_static/fonts/11ed281341a6dd16e758cb1e38e59f78.woff2 differ diff --git a/_static/fonts/13a019687fdb60cb1ff759f2aa5a09c9.woff2 b/_static/fonts/13a019687fdb60cb1ff759f2aa5a09c9.woff2 new file mode 100644 index 00000000..45fd58e8 Binary files /dev/null and b/_static/fonts/13a019687fdb60cb1ff759f2aa5a09c9.woff2 differ diff --git a/_static/fonts/13a92d073c751034247a6d47e8134fdd.woff2 b/_static/fonts/13a92d073c751034247a6d47e8134fdd.woff2 new file mode 100644 index 00000000..18d17329 Binary files /dev/null and b/_static/fonts/13a92d073c751034247a6d47e8134fdd.woff2 differ diff --git a/_static/fonts/16ef93a23793ea9defec5f01265a3fdc.woff2 b/_static/fonts/16ef93a23793ea9defec5f01265a3fdc.woff2 new file mode 100644 index 00000000..86107735 Binary files /dev/null and b/_static/fonts/16ef93a23793ea9defec5f01265a3fdc.woff2 differ diff --git a/_static/fonts/17111913977f7ec5077bbdbc046fbc6a.woff2 b/_static/fonts/17111913977f7ec5077bbdbc046fbc6a.woff2 new file mode 100644 index 00000000..993f18bb Binary files /dev/null and b/_static/fonts/17111913977f7ec5077bbdbc046fbc6a.woff2 differ diff --git a/_static/fonts/1a35ae0d4ce7da20107242fdfcfbff81.woff2 b/_static/fonts/1a35ae0d4ce7da20107242fdfcfbff81.woff2 new file mode 100644 index 00000000..500778d4 Binary files /dev/null and b/_static/fonts/1a35ae0d4ce7da20107242fdfcfbff81.woff2 differ diff --git a/_static/fonts/1b1a774a3e0e9b725eaa711a2afb7392.woff2 b/_static/fonts/1b1a774a3e0e9b725eaa711a2afb7392.woff2 new file mode 100644 index 00000000..c8fc859e Binary files /dev/null and b/_static/fonts/1b1a774a3e0e9b725eaa711a2afb7392.woff2 differ diff --git a/_static/fonts/1f149703dd15543c6b006e681cdc6760.woff2 b/_static/fonts/1f149703dd15543c6b006e681cdc6760.woff2 new file mode 100644 index 00000000..01105edf Binary files /dev/null and b/_static/fonts/1f149703dd15543c6b006e681cdc6760.woff2 differ diff --git a/_static/fonts/1f39a390e50a9034847927b40b8fd1a1.woff2 b/_static/fonts/1f39a390e50a9034847927b40b8fd1a1.woff2 new file mode 100644 index 00000000..f740bc93 Binary files /dev/null and b/_static/fonts/1f39a390e50a9034847927b40b8fd1a1.woff2 differ diff --git a/_static/fonts/219dddc355ee1f0ae550a97bae8a2531.woff2 b/_static/fonts/219dddc355ee1f0ae550a97bae8a2531.woff2 new file mode 100644 index 00000000..35645669 Binary files /dev/null and b/_static/fonts/219dddc355ee1f0ae550a97bae8a2531.woff2 differ diff --git a/_static/fonts/21a4306e449be7b5403a98b97f9dd0f9.woff2 b/_static/fonts/21a4306e449be7b5403a98b97f9dd0f9.woff2 new file mode 100644 index 00000000..013a49f6 Binary files /dev/null and b/_static/fonts/21a4306e449be7b5403a98b97f9dd0f9.woff2 differ diff --git a/_static/fonts/21eb25612d5c76e78c41bacf87adf6db.woff2 b/_static/fonts/21eb25612d5c76e78c41bacf87adf6db.woff2 new file mode 100644 index 00000000..aee97f9f Binary files /dev/null and b/_static/fonts/21eb25612d5c76e78c41bacf87adf6db.woff2 differ diff --git a/_static/fonts/237c47406e9e4a75786c423ab40d1a98.woff2 b/_static/fonts/237c47406e9e4a75786c423ab40d1a98.woff2 new file mode 100644 index 00000000..a1113ae2 Binary files /dev/null and b/_static/fonts/237c47406e9e4a75786c423ab40d1a98.woff2 differ diff --git a/_static/fonts/258446abf19534d57203b8e4b8a37c99.ttf b/_static/fonts/258446abf19534d57203b8e4b8a37c99.ttf new file mode 100644 index 00000000..761a43d0 Binary files /dev/null and b/_static/fonts/258446abf19534d57203b8e4b8a37c99.ttf differ diff --git a/_static/fonts/264c5b476ab42c43d6af4c257bb04477.woff2 b/_static/fonts/264c5b476ab42c43d6af4c257bb04477.woff2 new file mode 100644 index 00000000..52da8957 Binary files /dev/null and b/_static/fonts/264c5b476ab42c43d6af4c257bb04477.woff2 differ diff --git a/_static/fonts/26646b9d877d16236aa3267f8231ca4c.woff2 b/_static/fonts/26646b9d877d16236aa3267f8231ca4c.woff2 new file mode 100644 index 00000000..db6956c6 Binary files /dev/null and b/_static/fonts/26646b9d877d16236aa3267f8231ca4c.woff2 differ diff --git a/_static/fonts/26d45c6882b664dbea7b47896d0c2bc8.woff2 b/_static/fonts/26d45c6882b664dbea7b47896d0c2bc8.woff2 new file mode 100644 index 00000000..699f0220 Binary files /dev/null and b/_static/fonts/26d45c6882b664dbea7b47896d0c2bc8.woff2 differ diff --git a/_static/fonts/283fbef73f42c21722c5a3efc7a44b0c.woff2 b/_static/fonts/283fbef73f42c21722c5a3efc7a44b0c.woff2 new file mode 100644 index 00000000..10e1335a Binary files /dev/null and b/_static/fonts/283fbef73f42c21722c5a3efc7a44b0c.woff2 differ diff --git a/_static/fonts/28d2d42c2dc05f74362e21c4810e20cf.woff2 b/_static/fonts/28d2d42c2dc05f74362e21c4810e20cf.woff2 new file mode 100644 index 00000000..fb33b3bb Binary files /dev/null and b/_static/fonts/28d2d42c2dc05f74362e21c4810e20cf.woff2 differ diff --git a/_static/fonts/2a9ccbf9e2fc7ffc329cabcb326cac11.woff2 b/_static/fonts/2a9ccbf9e2fc7ffc329cabcb326cac11.woff2 new file mode 100644 index 00000000..c4822da7 Binary files /dev/null and b/_static/fonts/2a9ccbf9e2fc7ffc329cabcb326cac11.woff2 differ diff --git a/_static/fonts/2ae735028a2bdd6e73c6aec996cf9ad9.woff2 b/_static/fonts/2ae735028a2bdd6e73c6aec996cf9ad9.woff2 new file mode 100644 index 00000000..5a6fbff8 Binary files /dev/null and b/_static/fonts/2ae735028a2bdd6e73c6aec996cf9ad9.woff2 differ diff --git a/_static/fonts/2b413a610bc96fdc0d550d28ff5c575e.woff2 b/_static/fonts/2b413a610bc96fdc0d550d28ff5c575e.woff2 new file mode 100644 index 00000000..895e1edb Binary files /dev/null and b/_static/fonts/2b413a610bc96fdc0d550d28ff5c575e.woff2 differ diff --git a/_static/fonts/2bef6bc763635f137e6b49fc7d01d0d1.woff2 b/_static/fonts/2bef6bc763635f137e6b49fc7d01d0d1.woff2 new file mode 100644 index 00000000..665cf6aa Binary files /dev/null and b/_static/fonts/2bef6bc763635f137e6b49fc7d01d0d1.woff2 differ diff --git a/_static/fonts/2dc356092de7c114b1259e518a7f539a.woff2 b/_static/fonts/2dc356092de7c114b1259e518a7f539a.woff2 new file mode 100644 index 00000000..ab009390 Binary files /dev/null and b/_static/fonts/2dc356092de7c114b1259e518a7f539a.woff2 differ diff --git a/_static/fonts/2e43802a9d1556dbe360c22e2b85a597.woff2 b/_static/fonts/2e43802a9d1556dbe360c22e2b85a597.woff2 new file mode 100644 index 00000000..b3834ad7 Binary files /dev/null and b/_static/fonts/2e43802a9d1556dbe360c22e2b85a597.woff2 differ diff --git a/_static/fonts/2e991b4c7e5e35481357bf270b4d10e3.woff2 b/_static/fonts/2e991b4c7e5e35481357bf270b4d10e3.woff2 new file mode 100644 index 00000000..851f5fb9 Binary files /dev/null and b/_static/fonts/2e991b4c7e5e35481357bf270b4d10e3.woff2 differ diff --git a/_static/fonts/2eccf6c0d5b3656754d3d21cf62213ce.woff2 b/_static/fonts/2eccf6c0d5b3656754d3d21cf62213ce.woff2 new file mode 100644 index 00000000..066efbc2 Binary files /dev/null and b/_static/fonts/2eccf6c0d5b3656754d3d21cf62213ce.woff2 differ diff --git a/_static/fonts/2f39871937f1093b0ff8429081c6ec7b.woff2 b/_static/fonts/2f39871937f1093b0ff8429081c6ec7b.woff2 new file mode 100644 index 00000000..b01f17a9 Binary files /dev/null and b/_static/fonts/2f39871937f1093b0ff8429081c6ec7b.woff2 differ diff --git a/_static/fonts/2f45b23744b48cb8432ebce3a7785b15.woff2 b/_static/fonts/2f45b23744b48cb8432ebce3a7785b15.woff2 new file mode 100644 index 00000000..ad801122 Binary files /dev/null and b/_static/fonts/2f45b23744b48cb8432ebce3a7785b15.woff2 differ diff --git a/_static/fonts/2fdf026badd63aad0ca82a950790c3ad.woff2 b/_static/fonts/2fdf026badd63aad0ca82a950790c3ad.woff2 new file mode 100644 index 00000000..ca28246d Binary files /dev/null and b/_static/fonts/2fdf026badd63aad0ca82a950790c3ad.woff2 differ diff --git a/_static/fonts/3128f62492065ac0b20b397b3c2eb517.woff2 b/_static/fonts/3128f62492065ac0b20b397b3c2eb517.woff2 new file mode 100644 index 00000000..88d5eccd Binary files /dev/null and b/_static/fonts/3128f62492065ac0b20b397b3c2eb517.woff2 differ diff --git a/_static/fonts/31ce4972e0eedf25b993cb820d192cdf.woff2 b/_static/fonts/31ce4972e0eedf25b993cb820d192cdf.woff2 new file mode 100644 index 00000000..16f04366 Binary files /dev/null and b/_static/fonts/31ce4972e0eedf25b993cb820d192cdf.woff2 differ diff --git a/_static/fonts/362193de66077cdecea259d864fb6a32.woff2 b/_static/fonts/362193de66077cdecea259d864fb6a32.woff2 new file mode 100644 index 00000000..dc3ebe4c Binary files /dev/null and b/_static/fonts/362193de66077cdecea259d864fb6a32.woff2 differ diff --git a/_static/fonts/36ad3d233422da0692b766d17b2cf840.woff2 b/_static/fonts/36ad3d233422da0692b766d17b2cf840.woff2 new file mode 100644 index 00000000..8affdd07 Binary files /dev/null and b/_static/fonts/36ad3d233422da0692b766d17b2cf840.woff2 differ diff --git a/_static/fonts/3774b4ecc75b5d7dbf2ec07da7fb53e4.woff2 b/_static/fonts/3774b4ecc75b5d7dbf2ec07da7fb53e4.woff2 new file mode 100644 index 00000000..f56e3562 Binary files /dev/null and b/_static/fonts/3774b4ecc75b5d7dbf2ec07da7fb53e4.woff2 differ diff --git a/_static/fonts/3937a4c765110f2cc43d71e4daccfc13.woff2 b/_static/fonts/3937a4c765110f2cc43d71e4daccfc13.woff2 new file mode 100644 index 00000000..1826fb64 Binary files /dev/null and b/_static/fonts/3937a4c765110f2cc43d71e4daccfc13.woff2 differ diff --git a/_static/fonts/396a86833bb247070b487483b2ffee96.woff2 b/_static/fonts/396a86833bb247070b487483b2ffee96.woff2 new file mode 100644 index 00000000..48c41e1d Binary files /dev/null and b/_static/fonts/396a86833bb247070b487483b2ffee96.woff2 differ diff --git a/_static/fonts/3b6666c0da3a7fc7977e7ad30d57a213.woff2 b/_static/fonts/3b6666c0da3a7fc7977e7ad30d57a213.woff2 new file mode 100644 index 00000000..4b6d9aa2 Binary files /dev/null and b/_static/fonts/3b6666c0da3a7fc7977e7ad30d57a213.woff2 differ diff --git a/_static/fonts/3bb26e5fa6a6c594d2e343a95693893b.woff2 b/_static/fonts/3bb26e5fa6a6c594d2e343a95693893b.woff2 new file mode 100644 index 00000000..5c2a8578 Binary files /dev/null and b/_static/fonts/3bb26e5fa6a6c594d2e343a95693893b.woff2 differ diff --git a/_static/fonts/3d1e72bf2f7f579e5680e87a492bf14f.woff2 b/_static/fonts/3d1e72bf2f7f579e5680e87a492bf14f.woff2 new file mode 100644 index 00000000..08e21faf Binary files /dev/null and b/_static/fonts/3d1e72bf2f7f579e5680e87a492bf14f.woff2 differ diff --git a/_static/fonts/3da92e22ed8b5a86d3cba6011ac25860.woff2 b/_static/fonts/3da92e22ed8b5a86d3cba6011ac25860.woff2 new file mode 100644 index 00000000..53793698 Binary files /dev/null and b/_static/fonts/3da92e22ed8b5a86d3cba6011ac25860.woff2 differ diff --git a/_static/fonts/3e253f072fd8cb460de5e9daadfcc565.woff2 b/_static/fonts/3e253f072fd8cb460de5e9daadfcc565.woff2 new file mode 100644 index 00000000..6dba9706 Binary files /dev/null and b/_static/fonts/3e253f072fd8cb460de5e9daadfcc565.woff2 differ diff --git a/_static/fonts/3eb393e3a3d57bfe84e0705f86a042da.woff2 b/_static/fonts/3eb393e3a3d57bfe84e0705f86a042da.woff2 new file mode 100644 index 00000000..922fd05b Binary files /dev/null and b/_static/fonts/3eb393e3a3d57bfe84e0705f86a042da.woff2 differ diff --git a/_static/fonts/4050a23ec5cf36be5af409d6af66246b.woff2 b/_static/fonts/4050a23ec5cf36be5af409d6af66246b.woff2 new file mode 100644 index 00000000..65ca0605 Binary files /dev/null and b/_static/fonts/4050a23ec5cf36be5af409d6af66246b.woff2 differ diff --git a/_static/fonts/40d9a7ba120fbde112edc76a0e9f27fc.woff2 b/_static/fonts/40d9a7ba120fbde112edc76a0e9f27fc.woff2 new file mode 100644 index 00000000..bbd8c932 Binary files /dev/null and b/_static/fonts/40d9a7ba120fbde112edc76a0e9f27fc.woff2 differ diff --git a/_static/fonts/420106fda3528ff19100ff961bf017a5.woff2 b/_static/fonts/420106fda3528ff19100ff961bf017a5.woff2 new file mode 100644 index 00000000..ec37a6dc Binary files /dev/null and b/_static/fonts/420106fda3528ff19100ff961bf017a5.woff2 differ diff --git a/_static/fonts/422db4f94eb2639310cc49eb0c5232f7.woff2 b/_static/fonts/422db4f94eb2639310cc49eb0c5232f7.woff2 new file mode 100644 index 00000000..3a09829d Binary files /dev/null and b/_static/fonts/422db4f94eb2639310cc49eb0c5232f7.woff2 differ diff --git a/_static/fonts/426ea34d21839226fe870b5d07da1c1c.woff2 b/_static/fonts/426ea34d21839226fe870b5d07da1c1c.woff2 new file mode 100644 index 00000000..6117fd83 Binary files /dev/null and b/_static/fonts/426ea34d21839226fe870b5d07da1c1c.woff2 differ diff --git a/_static/fonts/43d3927918baa5dafbbf682c2ab6cd51.woff2 b/_static/fonts/43d3927918baa5dafbbf682c2ab6cd51.woff2 new file mode 100644 index 00000000..c28d2659 Binary files /dev/null and b/_static/fonts/43d3927918baa5dafbbf682c2ab6cd51.woff2 differ diff --git a/_static/fonts/442508ca6b49e1c39559e6e3cc7e2815.woff2 b/_static/fonts/442508ca6b49e1c39559e6e3cc7e2815.woff2 new file mode 100644 index 00000000..a09288a9 Binary files /dev/null and b/_static/fonts/442508ca6b49e1c39559e6e3cc7e2815.woff2 differ diff --git a/_static/fonts/46097cf128244dfb1bd2419e3479dea0.woff2 b/_static/fonts/46097cf128244dfb1bd2419e3479dea0.woff2 new file mode 100644 index 00000000..1cf75de7 Binary files /dev/null and b/_static/fonts/46097cf128244dfb1bd2419e3479dea0.woff2 differ diff --git a/_static/fonts/465f2ba0417b6b16ef8718992301efd8.woff2 b/_static/fonts/465f2ba0417b6b16ef8718992301efd8.woff2 new file mode 100644 index 00000000..5e3c8918 Binary files /dev/null and b/_static/fonts/465f2ba0417b6b16ef8718992301efd8.woff2 differ diff --git a/_static/fonts/47a2eb0e55070af53746643240dace61.woff2 b/_static/fonts/47a2eb0e55070af53746643240dace61.woff2 new file mode 100644 index 00000000..a026cd65 Binary files /dev/null and b/_static/fonts/47a2eb0e55070af53746643240dace61.woff2 differ diff --git a/_static/fonts/4984943fb416d86430e08c11c95ea560.woff2 b/_static/fonts/4984943fb416d86430e08c11c95ea560.woff2 new file mode 100644 index 00000000..851f45dc Binary files /dev/null and b/_static/fonts/4984943fb416d86430e08c11c95ea560.woff2 differ diff --git a/_static/fonts/4a91a3f5b5892a43e491b614d30e3132.ttf b/_static/fonts/4a91a3f5b5892a43e491b614d30e3132.ttf new file mode 100644 index 00000000..6532973b Binary files /dev/null and b/_static/fonts/4a91a3f5b5892a43e491b614d30e3132.ttf differ diff --git a/_static/fonts/4ac413e37db56eeeb4bb5cc1015ef5cb.ttf b/_static/fonts/4ac413e37db56eeeb4bb5cc1015ef5cb.ttf new file mode 100644 index 00000000..36baf58c Binary files /dev/null and b/_static/fonts/4ac413e37db56eeeb4bb5cc1015ef5cb.ttf differ diff --git a/_static/fonts/4b1c9b0ba29c3f32c0a04915792aeab9.woff2 b/_static/fonts/4b1c9b0ba29c3f32c0a04915792aeab9.woff2 new file mode 100644 index 00000000..f71b5086 Binary files /dev/null and b/_static/fonts/4b1c9b0ba29c3f32c0a04915792aeab9.woff2 differ diff --git a/_static/fonts/4b92658fb886583bb0500a5e2fa672d1.woff2 b/_static/fonts/4b92658fb886583bb0500a5e2fa672d1.woff2 new file mode 100644 index 00000000..a3e10b25 Binary files /dev/null and b/_static/fonts/4b92658fb886583bb0500a5e2fa672d1.woff2 differ diff --git a/_static/fonts/4caa7d82d0e5f6f127292f4f4c9af27a.woff2 b/_static/fonts/4caa7d82d0e5f6f127292f4f4c9af27a.woff2 new file mode 100644 index 00000000..820d4b4b Binary files /dev/null and b/_static/fonts/4caa7d82d0e5f6f127292f4f4c9af27a.woff2 differ diff --git a/_static/fonts/4d2765a0e0008da1d571566a55631207.ttf b/_static/fonts/4d2765a0e0008da1d571566a55631207.ttf new file mode 100644 index 00000000..4b8e06cc Binary files /dev/null and b/_static/fonts/4d2765a0e0008da1d571566a55631207.ttf differ diff --git a/_static/fonts/4e6d69d748044d096e9487d38ffb071c.woff2 b/_static/fonts/4e6d69d748044d096e9487d38ffb071c.woff2 new file mode 100644 index 00000000..6dee9764 Binary files /dev/null and b/_static/fonts/4e6d69d748044d096e9487d38ffb071c.woff2 differ diff --git a/_static/fonts/512757a4e09f30e718530112a3be087c.woff2 b/_static/fonts/512757a4e09f30e718530112a3be087c.woff2 new file mode 100644 index 00000000..57c923ea Binary files /dev/null and b/_static/fonts/512757a4e09f30e718530112a3be087c.woff2 differ diff --git a/_static/fonts/5193a8c91a003cfe41866c6844be22d0.woff2 b/_static/fonts/5193a8c91a003cfe41866c6844be22d0.woff2 new file mode 100644 index 00000000..0d897007 Binary files /dev/null and b/_static/fonts/5193a8c91a003cfe41866c6844be22d0.woff2 differ diff --git a/_static/fonts/51d978655b85a660b5ec352ab9eff784.woff2 b/_static/fonts/51d978655b85a660b5ec352ab9eff784.woff2 new file mode 100644 index 00000000..803a6367 Binary files /dev/null and b/_static/fonts/51d978655b85a660b5ec352ab9eff784.woff2 differ diff --git a/_static/fonts/52672870c9b3b0e5d8e74c9fdd522491.woff2 b/_static/fonts/52672870c9b3b0e5d8e74c9fdd522491.woff2 new file mode 100644 index 00000000..29161581 Binary files /dev/null and b/_static/fonts/52672870c9b3b0e5d8e74c9fdd522491.woff2 differ diff --git a/_static/fonts/529667aea70b09ba8845845f8b791127.woff2 b/_static/fonts/529667aea70b09ba8845845f8b791127.woff2 new file mode 100644 index 00000000..766c09d4 Binary files /dev/null and b/_static/fonts/529667aea70b09ba8845845f8b791127.woff2 differ diff --git a/_static/fonts/52d548b023a99019b1540895b1eeec9c.woff2 b/_static/fonts/52d548b023a99019b1540895b1eeec9c.woff2 new file mode 100644 index 00000000..9c4e1751 Binary files /dev/null and b/_static/fonts/52d548b023a99019b1540895b1eeec9c.woff2 differ diff --git a/_static/fonts/5317ff42c10ad2360d9f9c7f4da5b439.woff2 b/_static/fonts/5317ff42c10ad2360d9f9c7f4da5b439.woff2 new file mode 100644 index 00000000..0e050f8f Binary files /dev/null and b/_static/fonts/5317ff42c10ad2360d9f9c7f4da5b439.woff2 differ diff --git a/_static/fonts/542e2fd31336075667f486dbb0e086fd.woff2 b/_static/fonts/542e2fd31336075667f486dbb0e086fd.woff2 new file mode 100644 index 00000000..4a484c37 Binary files /dev/null and b/_static/fonts/542e2fd31336075667f486dbb0e086fd.woff2 differ diff --git a/_static/fonts/54dae5e8ef1a5aad1b61d8fd6d9cb6d0.woff2 b/_static/fonts/54dae5e8ef1a5aad1b61d8fd6d9cb6d0.woff2 new file mode 100644 index 00000000..f9247c3d Binary files /dev/null and b/_static/fonts/54dae5e8ef1a5aad1b61d8fd6d9cb6d0.woff2 differ diff --git a/_static/fonts/550faacd31f18c0b9cfa0ab0825b94ed.woff2 b/_static/fonts/550faacd31f18c0b9cfa0ab0825b94ed.woff2 new file mode 100644 index 00000000..79bc03e6 Binary files /dev/null and b/_static/fonts/550faacd31f18c0b9cfa0ab0825b94ed.woff2 differ diff --git a/_static/fonts/59310440fd3e41969b9f1511a08d7cc5.ttf b/_static/fonts/59310440fd3e41969b9f1511a08d7cc5.ttf new file mode 100644 index 00000000..65e3d579 Binary files /dev/null and b/_static/fonts/59310440fd3e41969b9f1511a08d7cc5.ttf differ diff --git a/_static/fonts/5ae9b4b2ee6c8b3ded2d4008ccf058b7.woff2 b/_static/fonts/5ae9b4b2ee6c8b3ded2d4008ccf058b7.woff2 new file mode 100644 index 00000000..376efcca Binary files /dev/null and b/_static/fonts/5ae9b4b2ee6c8b3ded2d4008ccf058b7.woff2 differ diff --git a/_static/fonts/5c032390bf8eb86dc4e7cbe575174e63.woff2 b/_static/fonts/5c032390bf8eb86dc4e7cbe575174e63.woff2 new file mode 100644 index 00000000..c0516fde Binary files /dev/null and b/_static/fonts/5c032390bf8eb86dc4e7cbe575174e63.woff2 differ diff --git a/_static/fonts/5c20fe772ae00739c191fcf5fc92d383.woff2 b/_static/fonts/5c20fe772ae00739c191fcf5fc92d383.woff2 new file mode 100644 index 00000000..c12e9336 Binary files /dev/null and b/_static/fonts/5c20fe772ae00739c191fcf5fc92d383.woff2 differ diff --git a/_static/fonts/5deb0b03027599395fa49424334c383b.woff2 b/_static/fonts/5deb0b03027599395fa49424334c383b.woff2 new file mode 100644 index 00000000..dddef273 Binary files /dev/null and b/_static/fonts/5deb0b03027599395fa49424334c383b.woff2 differ diff --git a/_static/fonts/5eb5872bb169d41a79e46876e0441311.woff2 b/_static/fonts/5eb5872bb169d41a79e46876e0441311.woff2 new file mode 100644 index 00000000..06f33538 Binary files /dev/null and b/_static/fonts/5eb5872bb169d41a79e46876e0441311.woff2 differ diff --git a/_static/fonts/5f72bfaf9e281f741c41abe46dff3e1d.woff2 b/_static/fonts/5f72bfaf9e281f741c41abe46dff3e1d.woff2 new file mode 100644 index 00000000..c14e2d0a Binary files /dev/null and b/_static/fonts/5f72bfaf9e281f741c41abe46dff3e1d.woff2 differ diff --git a/_static/fonts/601e118215ded34377e51a2e84d014c9.ttf b/_static/fonts/601e118215ded34377e51a2e84d014c9.ttf new file mode 100644 index 00000000..6034058c Binary files /dev/null and b/_static/fonts/601e118215ded34377e51a2e84d014c9.ttf differ diff --git a/_static/fonts/61ade56110af07e1fb875b7b045dfad3.ttf b/_static/fonts/61ade56110af07e1fb875b7b045dfad3.ttf new file mode 100644 index 00000000..f13718cc Binary files /dev/null and b/_static/fonts/61ade56110af07e1fb875b7b045dfad3.ttf differ diff --git a/_static/fonts/61f9fec22049e0ca94afdbf42e754714.woff2 b/_static/fonts/61f9fec22049e0ca94afdbf42e754714.woff2 new file mode 100644 index 00000000..61e31578 Binary files /dev/null and b/_static/fonts/61f9fec22049e0ca94afdbf42e754714.woff2 differ diff --git a/_static/fonts/66b26b3c84c6a918a3c1d323b81184cf.woff2 b/_static/fonts/66b26b3c84c6a918a3c1d323b81184cf.woff2 new file mode 100644 index 00000000..7ded06b0 Binary files /dev/null and b/_static/fonts/66b26b3c84c6a918a3c1d323b81184cf.woff2 differ diff --git a/_static/fonts/66cd4926f8b79b3df6d888564d4bddcc.woff2 b/_static/fonts/66cd4926f8b79b3df6d888564d4bddcc.woff2 new file mode 100644 index 00000000..f343e0cb Binary files /dev/null and b/_static/fonts/66cd4926f8b79b3df6d888564d4bddcc.woff2 differ diff --git a/_static/fonts/682534463397d85ffd5965a4f70a947d.ttf b/_static/fonts/682534463397d85ffd5965a4f70a947d.ttf new file mode 100644 index 00000000..4514b651 Binary files /dev/null and b/_static/fonts/682534463397d85ffd5965a4f70a947d.ttf differ diff --git a/_static/fonts/6ae318fb48664db81936182f961e5c32.woff2 b/_static/fonts/6ae318fb48664db81936182f961e5c32.woff2 new file mode 100644 index 00000000..116f4c3f Binary files /dev/null and b/_static/fonts/6ae318fb48664db81936182f961e5c32.woff2 differ diff --git a/_static/fonts/6ae8f8b730d4bfe372997d78612486ac.woff2 b/_static/fonts/6ae8f8b730d4bfe372997d78612486ac.woff2 new file mode 100644 index 00000000..a332ef80 Binary files /dev/null and b/_static/fonts/6ae8f8b730d4bfe372997d78612486ac.woff2 differ diff --git a/_static/fonts/6b4464ee024fff1bd7a9f622659eaaea.woff2 b/_static/fonts/6b4464ee024fff1bd7a9f622659eaaea.woff2 new file mode 100644 index 00000000..8d120423 Binary files /dev/null and b/_static/fonts/6b4464ee024fff1bd7a9f622659eaaea.woff2 differ diff --git a/_static/fonts/6b76c51e06a497bee64b065b08ad96b8.woff2 b/_static/fonts/6b76c51e06a497bee64b065b08ad96b8.woff2 new file mode 100644 index 00000000..e7916714 Binary files /dev/null and b/_static/fonts/6b76c51e06a497bee64b065b08ad96b8.woff2 differ diff --git a/_static/fonts/6bf499f36f403374a272b5adb80aefc3.woff2 b/_static/fonts/6bf499f36f403374a272b5adb80aefc3.woff2 new file mode 100644 index 00000000..c2dedafb Binary files /dev/null and b/_static/fonts/6bf499f36f403374a272b5adb80aefc3.woff2 differ diff --git a/_static/fonts/6c29edce0214f7ce5c29596630dda4df.woff2 b/_static/fonts/6c29edce0214f7ce5c29596630dda4df.woff2 new file mode 100644 index 00000000..a7719d5e Binary files /dev/null and b/_static/fonts/6c29edce0214f7ce5c29596630dda4df.woff2 differ diff --git a/_static/fonts/6c6a1c0a595735b92096a64feba801ab.woff2 b/_static/fonts/6c6a1c0a595735b92096a64feba801ab.woff2 new file mode 100644 index 00000000..ddfb7b4b Binary files /dev/null and b/_static/fonts/6c6a1c0a595735b92096a64feba801ab.woff2 differ diff --git a/_static/fonts/6d26fc8ce47383c3acc58ba2e9058844.ttf b/_static/fonts/6d26fc8ce47383c3acc58ba2e9058844.ttf new file mode 100644 index 00000000..65d3901f Binary files /dev/null and b/_static/fonts/6d26fc8ce47383c3acc58ba2e9058844.ttf differ diff --git a/_static/fonts/6ea4bf3cac225e29318cd2a18a4f9ffa.woff2 b/_static/fonts/6ea4bf3cac225e29318cd2a18a4f9ffa.woff2 new file mode 100644 index 00000000..e708c519 Binary files /dev/null and b/_static/fonts/6ea4bf3cac225e29318cd2a18a4f9ffa.woff2 differ diff --git a/_static/fonts/6f93a718640e4084dd22b48e4c81d95a.ttf b/_static/fonts/6f93a718640e4084dd22b48e4c81d95a.ttf new file mode 100644 index 00000000..34addfb7 Binary files /dev/null and b/_static/fonts/6f93a718640e4084dd22b48e4c81d95a.ttf differ diff --git a/_static/fonts/6fea4c96d85aafe12ccfa3a7403b3fd4.woff2 b/_static/fonts/6fea4c96d85aafe12ccfa3a7403b3fd4.woff2 new file mode 100644 index 00000000..3de0eb54 Binary files /dev/null and b/_static/fonts/6fea4c96d85aafe12ccfa3a7403b3fd4.woff2 differ diff --git a/_static/fonts/7031e540f4a2dc07a28e6e9a9ee85359.woff2 b/_static/fonts/7031e540f4a2dc07a28e6e9a9ee85359.woff2 new file mode 100644 index 00000000..180447f3 Binary files /dev/null and b/_static/fonts/7031e540f4a2dc07a28e6e9a9ee85359.woff2 differ diff --git a/_static/fonts/70df311f920b9db2b2647692b885aed8.woff2 b/_static/fonts/70df311f920b9db2b2647692b885aed8.woff2 new file mode 100644 index 00000000..0848da42 Binary files /dev/null and b/_static/fonts/70df311f920b9db2b2647692b885aed8.woff2 differ diff --git a/_static/fonts/72205716fd182d68ae7159fc3cbc22f8.ttf b/_static/fonts/72205716fd182d68ae7159fc3cbc22f8.ttf new file mode 100644 index 00000000..a4ec2be5 Binary files /dev/null and b/_static/fonts/72205716fd182d68ae7159fc3cbc22f8.ttf differ diff --git a/_static/fonts/723cbd6f8aa09d478166cf4b328ec440.woff2 b/_static/fonts/723cbd6f8aa09d478166cf4b328ec440.woff2 new file mode 100644 index 00000000..4f0c8378 Binary files /dev/null and b/_static/fonts/723cbd6f8aa09d478166cf4b328ec440.woff2 differ diff --git a/_static/fonts/73569e58a695276963fb8c3c1026376d.ttf b/_static/fonts/73569e58a695276963fb8c3c1026376d.ttf new file mode 100644 index 00000000..b0390865 Binary files /dev/null and b/_static/fonts/73569e58a695276963fb8c3c1026376d.ttf differ diff --git a/_static/fonts/7426b8382b0c7ce632df53261dce20be.woff2 b/_static/fonts/7426b8382b0c7ce632df53261dce20be.woff2 new file mode 100644 index 00000000..b73829d7 Binary files /dev/null and b/_static/fonts/7426b8382b0c7ce632df53261dce20be.woff2 differ diff --git a/_static/fonts/742a490470ad5add81a8614602f59609.woff2 b/_static/fonts/742a490470ad5add81a8614602f59609.woff2 new file mode 100644 index 00000000..de646f8d Binary files /dev/null and b/_static/fonts/742a490470ad5add81a8614602f59609.woff2 differ diff --git a/_static/fonts/752686e9f1580c8dc3eef03805ffd49e.woff2 b/_static/fonts/752686e9f1580c8dc3eef03805ffd49e.woff2 new file mode 100644 index 00000000..6416d7ff Binary files /dev/null and b/_static/fonts/752686e9f1580c8dc3eef03805ffd49e.woff2 differ diff --git a/_static/fonts/75d351ba4b7ae0ba4a2287ef48ae282b.woff2 b/_static/fonts/75d351ba4b7ae0ba4a2287ef48ae282b.woff2 new file mode 100644 index 00000000..1daeb76b Binary files /dev/null and b/_static/fonts/75d351ba4b7ae0ba4a2287ef48ae282b.woff2 differ diff --git a/_static/fonts/7608821ae7a01e76cb42e6fda12421e5.woff2 b/_static/fonts/7608821ae7a01e76cb42e6fda12421e5.woff2 new file mode 100644 index 00000000..02c19edd Binary files /dev/null and b/_static/fonts/7608821ae7a01e76cb42e6fda12421e5.woff2 differ diff --git a/_static/fonts/7635b26cac7923a2a94ad867d41afe4c.woff2 b/_static/fonts/7635b26cac7923a2a94ad867d41afe4c.woff2 new file mode 100644 index 00000000..6a6fb7aa Binary files /dev/null and b/_static/fonts/7635b26cac7923a2a94ad867d41afe4c.woff2 differ diff --git a/_static/fonts/77882429b96adeaa683dd0bcddff6e57.ttf b/_static/fonts/77882429b96adeaa683dd0bcddff6e57.ttf new file mode 100644 index 00000000..943b64fa Binary files /dev/null and b/_static/fonts/77882429b96adeaa683dd0bcddff6e57.ttf differ diff --git a/_static/fonts/79003e6320341ae4b3dc73aafa30e2a6.woff2 b/_static/fonts/79003e6320341ae4b3dc73aafa30e2a6.woff2 new file mode 100644 index 00000000..24f7240b Binary files /dev/null and b/_static/fonts/79003e6320341ae4b3dc73aafa30e2a6.woff2 differ diff --git a/_static/fonts/79e33408703a4c71c3b985b963a5d516.woff2 b/_static/fonts/79e33408703a4c71c3b985b963a5d516.woff2 new file mode 100644 index 00000000..3a4a1c8b Binary files /dev/null and b/_static/fonts/79e33408703a4c71c3b985b963a5d516.woff2 differ diff --git a/_static/fonts/7a5681247aa6fc3418022342557bf3e3.woff2 b/_static/fonts/7a5681247aa6fc3418022342557bf3e3.woff2 new file mode 100644 index 00000000..61326908 Binary files /dev/null and b/_static/fonts/7a5681247aa6fc3418022342557bf3e3.woff2 differ diff --git a/_static/fonts/7a8bcfe0a68bb4832124e2e022554fa3.woff2 b/_static/fonts/7a8bcfe0a68bb4832124e2e022554fa3.woff2 new file mode 100644 index 00000000..c9c3e214 Binary files /dev/null and b/_static/fonts/7a8bcfe0a68bb4832124e2e022554fa3.woff2 differ diff --git a/_static/fonts/7c632ba05b03720375e7caf795836efb.woff2 b/_static/fonts/7c632ba05b03720375e7caf795836efb.woff2 new file mode 100644 index 00000000..58d7cd69 Binary files /dev/null and b/_static/fonts/7c632ba05b03720375e7caf795836efb.woff2 differ diff --git a/_static/fonts/7e0b492e21cac0154068c32b5c353d34.woff2 b/_static/fonts/7e0b492e21cac0154068c32b5c353d34.woff2 new file mode 100644 index 00000000..da2e498a Binary files /dev/null and b/_static/fonts/7e0b492e21cac0154068c32b5c353d34.woff2 differ diff --git a/_static/fonts/7ef81fadcc090047e1c258f05066207d.woff2 b/_static/fonts/7ef81fadcc090047e1c258f05066207d.woff2 new file mode 100644 index 00000000..8eb689d0 Binary files /dev/null and b/_static/fonts/7ef81fadcc090047e1c258f05066207d.woff2 differ diff --git a/_static/fonts/8084f78186f127f1d12ba99276efe997.woff2 b/_static/fonts/8084f78186f127f1d12ba99276efe997.woff2 new file mode 100644 index 00000000..9f01067c Binary files /dev/null and b/_static/fonts/8084f78186f127f1d12ba99276efe997.woff2 differ diff --git a/_static/fonts/80b21d8db6045c871d36ad4a2c985722.woff2 b/_static/fonts/80b21d8db6045c871d36ad4a2c985722.woff2 new file mode 100644 index 00000000..38b29287 Binary files /dev/null and b/_static/fonts/80b21d8db6045c871d36ad4a2c985722.woff2 differ diff --git a/_static/fonts/826d42af215f1727ea4ef9055df04fc7.ttf b/_static/fonts/826d42af215f1727ea4ef9055df04fc7.ttf new file mode 100644 index 00000000..8148af08 Binary files /dev/null and b/_static/fonts/826d42af215f1727ea4ef9055df04fc7.ttf differ diff --git a/_static/fonts/83323e13092c5323935518bb1ed3654b.ttf b/_static/fonts/83323e13092c5323935518bb1ed3654b.ttf new file mode 100644 index 00000000..2a46deaf Binary files /dev/null and b/_static/fonts/83323e13092c5323935518bb1ed3654b.ttf differ diff --git a/_static/fonts/8458ffb1652db9f2f466c228153373bd.woff2 b/_static/fonts/8458ffb1652db9f2f466c228153373bd.woff2 new file mode 100644 index 00000000..a3468104 Binary files /dev/null and b/_static/fonts/8458ffb1652db9f2f466c228153373bd.woff2 differ diff --git a/_static/fonts/84b502edbdb3fb25714c78ad3e33827c.woff2 b/_static/fonts/84b502edbdb3fb25714c78ad3e33827c.woff2 new file mode 100644 index 00000000..1281ef46 Binary files /dev/null and b/_static/fonts/84b502edbdb3fb25714c78ad3e33827c.woff2 differ diff --git a/_static/fonts/858fdc48287ed646b82bfdf31ce60e5b.ttf b/_static/fonts/858fdc48287ed646b82bfdf31ce60e5b.ttf new file mode 100644 index 00000000..82a9e06f Binary files /dev/null and b/_static/fonts/858fdc48287ed646b82bfdf31ce60e5b.ttf differ diff --git a/_static/fonts/85b7e87c4d7247aaf8824e30b4144465.woff2 b/_static/fonts/85b7e87c4d7247aaf8824e30b4144465.woff2 new file mode 100644 index 00000000..46db6ae1 Binary files /dev/null and b/_static/fonts/85b7e87c4d7247aaf8824e30b4144465.woff2 differ diff --git a/_static/fonts/8638bf59a1e3ceb5b51df17bcf7bd7fc.woff2 b/_static/fonts/8638bf59a1e3ceb5b51df17bcf7bd7fc.woff2 new file mode 100644 index 00000000..915487b3 Binary files /dev/null and b/_static/fonts/8638bf59a1e3ceb5b51df17bcf7bd7fc.woff2 differ diff --git a/_static/fonts/868a11959e0c21a053df779c3cdeaad1.woff2 b/_static/fonts/868a11959e0c21a053df779c3cdeaad1.woff2 new file mode 100644 index 00000000..7efaca39 Binary files /dev/null and b/_static/fonts/868a11959e0c21a053df779c3cdeaad1.woff2 differ diff --git a/_static/fonts/871d2e9fd0b24c64bb3bfba59560196a.ttf b/_static/fonts/871d2e9fd0b24c64bb3bfba59560196a.ttf new file mode 100644 index 00000000..54c31d65 Binary files /dev/null and b/_static/fonts/871d2e9fd0b24c64bb3bfba59560196a.ttf differ diff --git a/_static/fonts/88b7c5e61902ab86691356a44517e57e.woff2 b/_static/fonts/88b7c5e61902ab86691356a44517e57e.woff2 new file mode 100644 index 00000000..f9d6c61a Binary files /dev/null and b/_static/fonts/88b7c5e61902ab86691356a44517e57e.woff2 differ diff --git a/_static/fonts/89bd2cbbc4b133be434990f66ea692cb.woff2 b/_static/fonts/89bd2cbbc4b133be434990f66ea692cb.woff2 new file mode 100644 index 00000000..81ac4082 Binary files /dev/null and b/_static/fonts/89bd2cbbc4b133be434990f66ea692cb.woff2 differ diff --git a/_static/fonts/8a08f5c435eed0f2414b3eeb3ce8c217.woff2 b/_static/fonts/8a08f5c435eed0f2414b3eeb3ce8c217.woff2 new file mode 100644 index 00000000..8200dc39 Binary files /dev/null and b/_static/fonts/8a08f5c435eed0f2414b3eeb3ce8c217.woff2 differ diff --git a/_static/fonts/8c65ea83f430ace76d95c746dcc7d8dc.ttf b/_static/fonts/8c65ea83f430ace76d95c746dcc7d8dc.ttf new file mode 100644 index 00000000..16949064 Binary files /dev/null and b/_static/fonts/8c65ea83f430ace76d95c746dcc7d8dc.ttf differ diff --git a/_static/fonts/8e67a526354c56c027c959a53b68147e.woff2 b/_static/fonts/8e67a526354c56c027c959a53b68147e.woff2 new file mode 100644 index 00000000..f005019b Binary files /dev/null and b/_static/fonts/8e67a526354c56c027c959a53b68147e.woff2 differ diff --git a/_static/fonts/8f0b23da93d60488a6162d1ebe93431b.woff2 b/_static/fonts/8f0b23da93d60488a6162d1ebe93431b.woff2 new file mode 100644 index 00000000..8756a14b Binary files /dev/null and b/_static/fonts/8f0b23da93d60488a6162d1ebe93431b.woff2 differ diff --git a/_static/fonts/8f1a4367b3d00ca55ea9b650136e690b.woff2 b/_static/fonts/8f1a4367b3d00ca55ea9b650136e690b.woff2 new file mode 100644 index 00000000..164501b5 Binary files /dev/null and b/_static/fonts/8f1a4367b3d00ca55ea9b650136e690b.woff2 differ diff --git a/_static/fonts/8f3dd654717149daea27dad82c649a7a.woff2 b/_static/fonts/8f3dd654717149daea27dad82c649a7a.woff2 new file mode 100644 index 00000000..0194d7b6 Binary files /dev/null and b/_static/fonts/8f3dd654717149daea27dad82c649a7a.woff2 differ diff --git a/_static/fonts/90237ead9085efcdb757ba498a2d4646.woff2 b/_static/fonts/90237ead9085efcdb757ba498a2d4646.woff2 new file mode 100644 index 00000000..a7b593fd Binary files /dev/null and b/_static/fonts/90237ead9085efcdb757ba498a2d4646.woff2 differ diff --git a/_static/fonts/917fc800a4cfb7ea65dac264d5a38eb6.ttf b/_static/fonts/917fc800a4cfb7ea65dac264d5a38eb6.ttf new file mode 100644 index 00000000..53225436 Binary files /dev/null and b/_static/fonts/917fc800a4cfb7ea65dac264d5a38eb6.ttf differ diff --git a/_static/fonts/92e018250353983874a958541296cfa6.woff2 b/_static/fonts/92e018250353983874a958541296cfa6.woff2 new file mode 100644 index 00000000..40f533d0 Binary files /dev/null and b/_static/fonts/92e018250353983874a958541296cfa6.woff2 differ diff --git a/_static/fonts/94333af3cbb89d3b83773d25618f1706.woff2 b/_static/fonts/94333af3cbb89d3b83773d25618f1706.woff2 new file mode 100644 index 00000000..4f2751e2 Binary files /dev/null and b/_static/fonts/94333af3cbb89d3b83773d25618f1706.woff2 differ diff --git a/_static/fonts/94edfe2c34615cf4291ff718187862ea.ttf b/_static/fonts/94edfe2c34615cf4291ff718187862ea.ttf new file mode 100644 index 00000000..6062c26c Binary files /dev/null and b/_static/fonts/94edfe2c34615cf4291ff718187862ea.ttf differ diff --git a/_static/fonts/96246862b6453fb62d5ba6dcfa043c02.woff2 b/_static/fonts/96246862b6453fb62d5ba6dcfa043c02.woff2 new file mode 100644 index 00000000..2b74a277 Binary files /dev/null and b/_static/fonts/96246862b6453fb62d5ba6dcfa043c02.woff2 differ diff --git a/_static/fonts/96a6a4e9dd5d1505226c82c13d410deb.woff2 b/_static/fonts/96a6a4e9dd5d1505226c82c13d410deb.woff2 new file mode 100644 index 00000000..bef9af43 Binary files /dev/null and b/_static/fonts/96a6a4e9dd5d1505226c82c13d410deb.woff2 differ diff --git a/_static/fonts/96dbb7d9188b2e0703f002e68077f967.woff2 b/_static/fonts/96dbb7d9188b2e0703f002e68077f967.woff2 new file mode 100644 index 00000000..303d3cd4 Binary files /dev/null and b/_static/fonts/96dbb7d9188b2e0703f002e68077f967.woff2 differ diff --git a/_static/fonts/96ff010e106cae30b33bbc2f4b6c3f60.woff2 b/_static/fonts/96ff010e106cae30b33bbc2f4b6c3f60.woff2 new file mode 100644 index 00000000..87ff0f12 Binary files /dev/null and b/_static/fonts/96ff010e106cae30b33bbc2f4b6c3f60.woff2 differ diff --git a/_static/fonts/97bc75da499078ba9c8f0cee4ad2920a.woff2 b/_static/fonts/97bc75da499078ba9c8f0cee4ad2920a.woff2 new file mode 100644 index 00000000..eb27f6d8 Binary files /dev/null and b/_static/fonts/97bc75da499078ba9c8f0cee4ad2920a.woff2 differ diff --git a/_static/fonts/98901a616b22ef6dbca6abebf3560b6b.woff2 b/_static/fonts/98901a616b22ef6dbca6abebf3560b6b.woff2 new file mode 100644 index 00000000..da5caf01 Binary files /dev/null and b/_static/fonts/98901a616b22ef6dbca6abebf3560b6b.woff2 differ diff --git a/_static/fonts/98ad4f585b76c4e883b39c991192a77c.woff2 b/_static/fonts/98ad4f585b76c4e883b39c991192a77c.woff2 new file mode 100644 index 00000000..84a80b09 Binary files /dev/null and b/_static/fonts/98ad4f585b76c4e883b39c991192a77c.woff2 differ diff --git a/_static/fonts/99214e5d9bc3ce84af84175a45f4ba0b.ttf b/_static/fonts/99214e5d9bc3ce84af84175a45f4ba0b.ttf new file mode 100644 index 00000000..d3fa4275 Binary files /dev/null and b/_static/fonts/99214e5d9bc3ce84af84175a45f4ba0b.ttf differ diff --git a/_static/fonts/99f6d8a464743ae3c388b32ab525bf87.woff2 b/_static/fonts/99f6d8a464743ae3c388b32ab525bf87.woff2 new file mode 100644 index 00000000..e4ca040a Binary files /dev/null and b/_static/fonts/99f6d8a464743ae3c388b32ab525bf87.woff2 differ diff --git a/_static/fonts/9a70a7678eae9689a2e903377e3c259e.woff2 b/_static/fonts/9a70a7678eae9689a2e903377e3c259e.woff2 new file mode 100644 index 00000000..8625132d Binary files /dev/null and b/_static/fonts/9a70a7678eae9689a2e903377e3c259e.woff2 differ diff --git a/_static/fonts/9f8dec9e15435e26b10359950ee22fed.woff2 b/_static/fonts/9f8dec9e15435e26b10359950ee22fed.woff2 new file mode 100644 index 00000000..4f7c5af3 Binary files /dev/null and b/_static/fonts/9f8dec9e15435e26b10359950ee22fed.woff2 differ diff --git a/_static/fonts/9faa7062eb32d692b0b5f69f0e42fe62.woff2 b/_static/fonts/9faa7062eb32d692b0b5f69f0e42fe62.woff2 new file mode 100644 index 00000000..f211f2cd Binary files /dev/null and b/_static/fonts/9faa7062eb32d692b0b5f69f0e42fe62.woff2 differ diff --git a/_static/fonts/a08aab97ea21fc5299645d12e3ef57bf.woff2 b/_static/fonts/a08aab97ea21fc5299645d12e3ef57bf.woff2 new file mode 100644 index 00000000..15e1583a Binary files /dev/null and b/_static/fonts/a08aab97ea21fc5299645d12e3ef57bf.woff2 differ diff --git a/_static/fonts/a147e4366336588aae172d59e25deef1.woff2 b/_static/fonts/a147e4366336588aae172d59e25deef1.woff2 new file mode 100644 index 00000000..aa296b5a Binary files /dev/null and b/_static/fonts/a147e4366336588aae172d59e25deef1.woff2 differ diff --git a/_static/fonts/a1fa19f89170d7580d17c2b8b8970ec4.woff2 b/_static/fonts/a1fa19f89170d7580d17c2b8b8970ec4.woff2 new file mode 100644 index 00000000..0f2f4fbc Binary files /dev/null and b/_static/fonts/a1fa19f89170d7580d17c2b8b8970ec4.woff2 differ diff --git a/_static/fonts/a2d2c60ad40172211ff4782075414565.woff2 b/_static/fonts/a2d2c60ad40172211ff4782075414565.woff2 new file mode 100644 index 00000000..998a77a6 Binary files /dev/null and b/_static/fonts/a2d2c60ad40172211ff4782075414565.woff2 differ diff --git a/_static/fonts/a346eb01892d90d3150a27bcc3490add.woff2 b/_static/fonts/a346eb01892d90d3150a27bcc3490add.woff2 new file mode 100644 index 00000000..04ccf35e Binary files /dev/null and b/_static/fonts/a346eb01892d90d3150a27bcc3490add.woff2 differ diff --git a/_static/fonts/a3efd151d530b9353dbb771102f217a9.woff2 b/_static/fonts/a3efd151d530b9353dbb771102f217a9.woff2 new file mode 100644 index 00000000..9bdc4b18 Binary files /dev/null and b/_static/fonts/a3efd151d530b9353dbb771102f217a9.woff2 differ diff --git a/_static/fonts/a4afb0badd14ab3594ee2ef01392b285.woff2 b/_static/fonts/a4afb0badd14ab3594ee2ef01392b285.woff2 new file mode 100644 index 00000000..ba40efe6 Binary files /dev/null and b/_static/fonts/a4afb0badd14ab3594ee2ef01392b285.woff2 differ diff --git a/_static/fonts/a620860b63de9c40dac9a59b0094c61a.woff2 b/_static/fonts/a620860b63de9c40dac9a59b0094c61a.woff2 new file mode 100644 index 00000000..97ce3826 Binary files /dev/null and b/_static/fonts/a620860b63de9c40dac9a59b0094c61a.woff2 differ diff --git a/_static/fonts/a6883e4c27bb2b4d33116a6228bbc9ff.ttf b/_static/fonts/a6883e4c27bb2b4d33116a6228bbc9ff.ttf new file mode 100644 index 00000000..24d10e80 Binary files /dev/null and b/_static/fonts/a6883e4c27bb2b4d33116a6228bbc9ff.ttf differ diff --git a/_static/fonts/a712dd5fa12c7c09e52d44cfce499e33.woff2 b/_static/fonts/a712dd5fa12c7c09e52d44cfce499e33.woff2 new file mode 100644 index 00000000..4a0c4273 Binary files /dev/null and b/_static/fonts/a712dd5fa12c7c09e52d44cfce499e33.woff2 differ diff --git a/_static/fonts/a77dc0ac7d95f0f4254cc1a78f3c07db.woff2 b/_static/fonts/a77dc0ac7d95f0f4254cc1a78f3c07db.woff2 new file mode 100644 index 00000000..0c685a6f Binary files /dev/null and b/_static/fonts/a77dc0ac7d95f0f4254cc1a78f3c07db.woff2 differ diff --git a/_static/fonts/a84df1f533205686b83a3232b24efa87.woff2 b/_static/fonts/a84df1f533205686b83a3232b24efa87.woff2 new file mode 100644 index 00000000..19990a1d Binary files /dev/null and b/_static/fonts/a84df1f533205686b83a3232b24efa87.woff2 differ diff --git a/_static/fonts/a875ce2faf827acf96c74d348b861a09.woff2 b/_static/fonts/a875ce2faf827acf96c74d348b861a09.woff2 new file mode 100644 index 00000000..e325dbe2 Binary files /dev/null and b/_static/fonts/a875ce2faf827acf96c74d348b861a09.woff2 differ diff --git a/_static/fonts/a94c81d0b3f6bb97fd97cfcfbfa5dcaf.woff2 b/_static/fonts/a94c81d0b3f6bb97fd97cfcfbfa5dcaf.woff2 new file mode 100644 index 00000000..c4f017a2 Binary files /dev/null and b/_static/fonts/a94c81d0b3f6bb97fd97cfcfbfa5dcaf.woff2 differ diff --git a/_static/fonts/a966ed9a844cd60b56d4e1b31b0051fe.woff2 b/_static/fonts/a966ed9a844cd60b56d4e1b31b0051fe.woff2 new file mode 100644 index 00000000..c5360a27 Binary files /dev/null and b/_static/fonts/a966ed9a844cd60b56d4e1b31b0051fe.woff2 differ diff --git a/_static/fonts/aae577798ff3f4e9e1d9640a97dea39a.woff2 b/_static/fonts/aae577798ff3f4e9e1d9640a97dea39a.woff2 new file mode 100644 index 00000000..1a1ed7c2 Binary files /dev/null and b/_static/fonts/aae577798ff3f4e9e1d9640a97dea39a.woff2 differ diff --git a/_static/fonts/ab0a020935184477d441bd13b3b9e642.woff2 b/_static/fonts/ab0a020935184477d441bd13b3b9e642.woff2 new file mode 100644 index 00000000..d2f6aa9e Binary files /dev/null and b/_static/fonts/ab0a020935184477d441bd13b3b9e642.woff2 differ diff --git a/_static/fonts/add79d702aef2d1f1cf4865df00911e0.woff2 b/_static/fonts/add79d702aef2d1f1cf4865df00911e0.woff2 new file mode 100644 index 00000000..f9c26fa2 Binary files /dev/null and b/_static/fonts/add79d702aef2d1f1cf4865df00911e0.woff2 differ diff --git a/_static/fonts/ae4c0081383f95289e776a828f29831c.woff2 b/_static/fonts/ae4c0081383f95289e776a828f29831c.woff2 new file mode 100644 index 00000000..da96555d Binary files /dev/null and b/_static/fonts/ae4c0081383f95289e776a828f29831c.woff2 differ diff --git a/_static/fonts/af09b935bb3d7e0f6541002b82baf166.woff2 b/_static/fonts/af09b935bb3d7e0f6541002b82baf166.woff2 new file mode 100644 index 00000000..d202426c Binary files /dev/null and b/_static/fonts/af09b935bb3d7e0f6541002b82baf166.woff2 differ diff --git a/_static/fonts/af8b9493960aacd72b94c7567ab45c9e.ttf b/_static/fonts/af8b9493960aacd72b94c7567ab45c9e.ttf new file mode 100644 index 00000000..7b83e8a3 Binary files /dev/null and b/_static/fonts/af8b9493960aacd72b94c7567ab45c9e.ttf differ diff --git a/_static/fonts/b078d17cfea0b0c47b499eeb79153746.ttf b/_static/fonts/b078d17cfea0b0c47b499eeb79153746.ttf new file mode 100644 index 00000000..a28b5468 Binary files /dev/null and b/_static/fonts/b078d17cfea0b0c47b499eeb79153746.ttf differ diff --git a/_static/fonts/b11130c54c74efd6daafe68f038f84db.woff2 b/_static/fonts/b11130c54c74efd6daafe68f038f84db.woff2 new file mode 100644 index 00000000..9ef7f598 Binary files /dev/null and b/_static/fonts/b11130c54c74efd6daafe68f038f84db.woff2 differ diff --git a/_static/fonts/b17158b92ca6f9303712a3378bfb5636.woff2 b/_static/fonts/b17158b92ca6f9303712a3378bfb5636.woff2 new file mode 100644 index 00000000..70b4e050 Binary files /dev/null and b/_static/fonts/b17158b92ca6f9303712a3378bfb5636.woff2 differ diff --git a/_static/fonts/b39a3761f41f9476dfd827446487cb79.woff2 b/_static/fonts/b39a3761f41f9476dfd827446487cb79.woff2 new file mode 100644 index 00000000..69815fba Binary files /dev/null and b/_static/fonts/b39a3761f41f9476dfd827446487cb79.woff2 differ diff --git a/_static/fonts/b5b98bb4e5069d0f063d919167ba6653.woff2 b/_static/fonts/b5b98bb4e5069d0f063d919167ba6653.woff2 new file mode 100644 index 00000000..8483f510 Binary files /dev/null and b/_static/fonts/b5b98bb4e5069d0f063d919167ba6653.woff2 differ diff --git a/_static/fonts/b5c6e34d471a72326c3151f6f89b70b3.woff2 b/_static/fonts/b5c6e34d471a72326c3151f6f89b70b3.woff2 new file mode 100644 index 00000000..bdfaff3b Binary files /dev/null and b/_static/fonts/b5c6e34d471a72326c3151f6f89b70b3.woff2 differ diff --git a/_static/fonts/b7c212f5d900890107f648d1f28310a8.woff2 b/_static/fonts/b7c212f5d900890107f648d1f28310a8.woff2 new file mode 100644 index 00000000..d40b06e3 Binary files /dev/null and b/_static/fonts/b7c212f5d900890107f648d1f28310a8.woff2 differ diff --git a/_static/fonts/b7cae3f403e6f573f0a7fed865887af4.woff2 b/_static/fonts/b7cae3f403e6f573f0a7fed865887af4.woff2 new file mode 100644 index 00000000..09cf4e50 Binary files /dev/null and b/_static/fonts/b7cae3f403e6f573f0a7fed865887af4.woff2 differ diff --git a/_static/fonts/b7f1713b565f769b0605291cc28102c0.woff2 b/_static/fonts/b7f1713b565f769b0605291cc28102c0.woff2 new file mode 100644 index 00000000..d213395e Binary files /dev/null and b/_static/fonts/b7f1713b565f769b0605291cc28102c0.woff2 differ diff --git a/_static/fonts/b89ebf50f35195132ecff30f6fcf4b66.woff2 b/_static/fonts/b89ebf50f35195132ecff30f6fcf4b66.woff2 new file mode 100644 index 00000000..6c929662 Binary files /dev/null and b/_static/fonts/b89ebf50f35195132ecff30f6fcf4b66.woff2 differ diff --git a/_static/fonts/b8b678e335cca488ceeab549e0ee7c43.woff2 b/_static/fonts/b8b678e335cca488ceeab549e0ee7c43.woff2 new file mode 100644 index 00000000..b0e87089 Binary files /dev/null and b/_static/fonts/b8b678e335cca488ceeab549e0ee7c43.woff2 differ diff --git a/_static/fonts/b965f477e38a00cafdcfba8553d17d35.woff2 b/_static/fonts/b965f477e38a00cafdcfba8553d17d35.woff2 new file mode 100644 index 00000000..235c5bfe Binary files /dev/null and b/_static/fonts/b965f477e38a00cafdcfba8553d17d35.woff2 differ diff --git a/_static/fonts/ba534299c2b72e3b905f313cc81dd4fa.woff2 b/_static/fonts/ba534299c2b72e3b905f313cc81dd4fa.woff2 new file mode 100644 index 00000000..59caba42 Binary files /dev/null and b/_static/fonts/ba534299c2b72e3b905f313cc81dd4fa.woff2 differ diff --git a/_static/fonts/bbd1d1a14cde3b29e24f67475f7c0569.woff2 b/_static/fonts/bbd1d1a14cde3b29e24f67475f7c0569.woff2 new file mode 100644 index 00000000..488021de Binary files /dev/null and b/_static/fonts/bbd1d1a14cde3b29e24f67475f7c0569.woff2 differ diff --git a/_static/fonts/bc65abe41b621168458f550dd21f3e85.woff2 b/_static/fonts/bc65abe41b621168458f550dd21f3e85.woff2 new file mode 100644 index 00000000..8e41171e Binary files /dev/null and b/_static/fonts/bc65abe41b621168458f550dd21f3e85.woff2 differ diff --git a/_static/fonts/bd6bbdda9ebfa829f1b1314a929f1197.woff2 b/_static/fonts/bd6bbdda9ebfa829f1b1314a929f1197.woff2 new file mode 100644 index 00000000..8fc56b2d Binary files /dev/null and b/_static/fonts/bd6bbdda9ebfa829f1b1314a929f1197.woff2 differ diff --git a/_static/fonts/beabfea8c7ef7693427c37f99ece071f.woff2 b/_static/fonts/beabfea8c7ef7693427c37f99ece071f.woff2 new file mode 100644 index 00000000..bc95855c Binary files /dev/null and b/_static/fonts/beabfea8c7ef7693427c37f99ece071f.woff2 differ diff --git a/_static/fonts/bef5ef5511a39f5f2a5ec4d20ad5bbf7.woff2 b/_static/fonts/bef5ef5511a39f5f2a5ec4d20ad5bbf7.woff2 new file mode 100644 index 00000000..ed3274ec Binary files /dev/null and b/_static/fonts/bef5ef5511a39f5f2a5ec4d20ad5bbf7.woff2 differ diff --git a/_static/fonts/c0b55e2fa00cb3538e82dbb7d2f8dc66.ttf b/_static/fonts/c0b55e2fa00cb3538e82dbb7d2f8dc66.ttf new file mode 100644 index 00000000..c4b622c6 Binary files /dev/null and b/_static/fonts/c0b55e2fa00cb3538e82dbb7d2f8dc66.ttf differ diff --git a/_static/fonts/c2018a1ed955d97c427d0f06f40d6050.woff2 b/_static/fonts/c2018a1ed955d97c427d0f06f40d6050.woff2 new file mode 100644 index 00000000..d2959af3 Binary files /dev/null and b/_static/fonts/c2018a1ed955d97c427d0f06f40d6050.woff2 differ diff --git a/_static/fonts/c28df7ae5ed0937c97304fcbc60e61d2.ttf b/_static/fonts/c28df7ae5ed0937c97304fcbc60e61d2.ttf new file mode 100644 index 00000000..6fbbfb34 Binary files /dev/null and b/_static/fonts/c28df7ae5ed0937c97304fcbc60e61d2.ttf differ diff --git a/_static/fonts/c29bd9cd79bb0a8a71ce2962919e8b0d.woff2 b/_static/fonts/c29bd9cd79bb0a8a71ce2962919e8b0d.woff2 new file mode 100644 index 00000000..d2e02245 Binary files /dev/null and b/_static/fonts/c29bd9cd79bb0a8a71ce2962919e8b0d.woff2 differ diff --git a/_static/fonts/c32d88b77c94ccea3e7a03e87fcbbad8.woff2 b/_static/fonts/c32d88b77c94ccea3e7a03e87fcbbad8.woff2 new file mode 100644 index 00000000..a41cd0ae Binary files /dev/null and b/_static/fonts/c32d88b77c94ccea3e7a03e87fcbbad8.woff2 differ diff --git a/_static/fonts/c3afdd3c83b6de20c3d9e87740770c9e.woff2 b/_static/fonts/c3afdd3c83b6de20c3d9e87740770c9e.woff2 new file mode 100644 index 00000000..645479a7 Binary files /dev/null and b/_static/fonts/c3afdd3c83b6de20c3d9e87740770c9e.woff2 differ diff --git a/_static/fonts/c4705b13de24588bbf5ac6c4d29db389.woff2 b/_static/fonts/c4705b13de24588bbf5ac6c4d29db389.woff2 new file mode 100644 index 00000000..bcf868bd Binary files /dev/null and b/_static/fonts/c4705b13de24588bbf5ac6c4d29db389.woff2 differ diff --git a/_static/fonts/c5d0a8d5e21d71fe4aed01ef6c6e904a.ttf b/_static/fonts/c5d0a8d5e21d71fe4aed01ef6c6e904a.ttf new file mode 100644 index 00000000..102b4c8a Binary files /dev/null and b/_static/fonts/c5d0a8d5e21d71fe4aed01ef6c6e904a.ttf differ diff --git a/_static/fonts/c71e1ed02ffd053fbc7f851cd79198f0.ttf b/_static/fonts/c71e1ed02ffd053fbc7f851cd79198f0.ttf new file mode 100644 index 00000000..bbe85f8e Binary files /dev/null and b/_static/fonts/c71e1ed02ffd053fbc7f851cd79198f0.ttf differ diff --git a/_static/fonts/c780beba9d1521f4930e8612ffb1535c.woff2 b/_static/fonts/c780beba9d1521f4930e8612ffb1535c.woff2 new file mode 100644 index 00000000..11042d6d Binary files /dev/null and b/_static/fonts/c780beba9d1521f4930e8612ffb1535c.woff2 differ diff --git a/_static/fonts/c99a92c471d6f433b19fde75b2552e38.woff2 b/_static/fonts/c99a92c471d6f433b19fde75b2552e38.woff2 new file mode 100644 index 00000000..96be1e08 Binary files /dev/null and b/_static/fonts/c99a92c471d6f433b19fde75b2552e38.woff2 differ diff --git a/_static/fonts/ca7f31435e0446821dcd43fc0e766e31.woff2 b/_static/fonts/ca7f31435e0446821dcd43fc0e766e31.woff2 new file mode 100644 index 00000000..d5fa93fd Binary files /dev/null and b/_static/fonts/ca7f31435e0446821dcd43fc0e766e31.woff2 differ diff --git a/_static/fonts/cc7318e183292c701800a2c61d807c98.woff2 b/_static/fonts/cc7318e183292c701800a2c61d807c98.woff2 new file mode 100644 index 00000000..34c09e3c Binary files /dev/null and b/_static/fonts/cc7318e183292c701800a2c61d807c98.woff2 differ diff --git a/_static/fonts/cdc3adef34f3d5d51ccbd1e93cee04e9.woff2 b/_static/fonts/cdc3adef34f3d5d51ccbd1e93cee04e9.woff2 new file mode 100644 index 00000000..55f38fcd Binary files /dev/null and b/_static/fonts/cdc3adef34f3d5d51ccbd1e93cee04e9.woff2 differ diff --git a/_static/fonts/cdec81ab55fb735870442a76524651c7.woff2 b/_static/fonts/cdec81ab55fb735870442a76524651c7.woff2 new file mode 100644 index 00000000..e761883d Binary files /dev/null and b/_static/fonts/cdec81ab55fb735870442a76524651c7.woff2 differ diff --git a/_static/fonts/ce31a3d939f25087b2b8b08f6b386523.woff2 b/_static/fonts/ce31a3d939f25087b2b8b08f6b386523.woff2 new file mode 100644 index 00000000..d07072ab Binary files /dev/null and b/_static/fonts/ce31a3d939f25087b2b8b08f6b386523.woff2 differ diff --git a/_static/fonts/ce4650b74cac95f6c9484a808c046790.woff2 b/_static/fonts/ce4650b74cac95f6c9484a808c046790.woff2 new file mode 100644 index 00000000..367c13ac Binary files /dev/null and b/_static/fonts/ce4650b74cac95f6c9484a808c046790.woff2 differ diff --git a/_static/fonts/ce7027efa5c894e8b244b0ca05ec121b.woff2 b/_static/fonts/ce7027efa5c894e8b244b0ca05ec121b.woff2 new file mode 100644 index 00000000..5392e037 Binary files /dev/null and b/_static/fonts/ce7027efa5c894e8b244b0ca05ec121b.woff2 differ diff --git a/_static/fonts/d06d842a080c12b21bf6521a5d9dc79d.woff2 b/_static/fonts/d06d842a080c12b21bf6521a5d9dc79d.woff2 new file mode 100644 index 00000000..98616a52 Binary files /dev/null and b/_static/fonts/d06d842a080c12b21bf6521a5d9dc79d.woff2 differ diff --git a/_static/fonts/d22c7353a102a9be9c67988ab7a16188.woff2 b/_static/fonts/d22c7353a102a9be9c67988ab7a16188.woff2 new file mode 100644 index 00000000..2213e7ec Binary files /dev/null and b/_static/fonts/d22c7353a102a9be9c67988ab7a16188.woff2 differ diff --git a/_static/fonts/d4577260f133e8b3d89369ab48596774.woff2 b/_static/fonts/d4577260f133e8b3d89369ab48596774.woff2 new file mode 100644 index 00000000..94aaf646 Binary files /dev/null and b/_static/fonts/d4577260f133e8b3d89369ab48596774.woff2 differ diff --git a/_static/fonts/d7c7c06d1be056d03709ceae2b003606.woff2 b/_static/fonts/d7c7c06d1be056d03709ceae2b003606.woff2 new file mode 100644 index 00000000..6b97ba2a Binary files /dev/null and b/_static/fonts/d7c7c06d1be056d03709ceae2b003606.woff2 differ diff --git a/_static/fonts/d7ed3965fb236543ca714c28aa93846d.woff2 b/_static/fonts/d7ed3965fb236543ca714c28aa93846d.woff2 new file mode 100644 index 00000000..e7ff05e5 Binary files /dev/null and b/_static/fonts/d7ed3965fb236543ca714c28aa93846d.woff2 differ diff --git a/_static/fonts/dbcb7acd17899c70335fc7724aefcec8.woff2 b/_static/fonts/dbcb7acd17899c70335fc7724aefcec8.woff2 new file mode 100644 index 00000000..1aa9aa77 Binary files /dev/null and b/_static/fonts/dbcb7acd17899c70335fc7724aefcec8.woff2 differ diff --git a/_static/fonts/dcac443a527040572c077cb2b28ac8ca.woff2 b/_static/fonts/dcac443a527040572c077cb2b28ac8ca.woff2 new file mode 100644 index 00000000..a3cabd4a Binary files /dev/null and b/_static/fonts/dcac443a527040572c077cb2b28ac8ca.woff2 differ diff --git a/_static/fonts/dcfb096c0a3b3089bfce4753d16eda3b.woff2 b/_static/fonts/dcfb096c0a3b3089bfce4753d16eda3b.woff2 new file mode 100644 index 00000000..3f43bf85 Binary files /dev/null and b/_static/fonts/dcfb096c0a3b3089bfce4753d16eda3b.woff2 differ diff --git a/_static/fonts/de9d9d69c7140eb0ba951986b1181ff1.woff2 b/_static/fonts/de9d9d69c7140eb0ba951986b1181ff1.woff2 new file mode 100644 index 00000000..5eca4abc Binary files /dev/null and b/_static/fonts/de9d9d69c7140eb0ba951986b1181ff1.woff2 differ diff --git a/_static/fonts/df3312dfbf327224b9f2f9632c7ccd8c.woff2 b/_static/fonts/df3312dfbf327224b9f2f9632c7ccd8c.woff2 new file mode 100644 index 00000000..b3ff1819 Binary files /dev/null and b/_static/fonts/df3312dfbf327224b9f2f9632c7ccd8c.woff2 differ diff --git a/_static/fonts/e03013e0baa5690a803c188da2214d92.woff2 b/_static/fonts/e03013e0baa5690a803c188da2214d92.woff2 new file mode 100644 index 00000000..6008f024 Binary files /dev/null and b/_static/fonts/e03013e0baa5690a803c188da2214d92.woff2 differ diff --git a/_static/fonts/e1a38cc8ff546d3df1459c89df87b8ea.woff2 b/_static/fonts/e1a38cc8ff546d3df1459c89df87b8ea.woff2 new file mode 100644 index 00000000..9e25a3e5 Binary files /dev/null and b/_static/fonts/e1a38cc8ff546d3df1459c89df87b8ea.woff2 differ diff --git a/_static/fonts/e1c796916b3538c0a441a60a90f5520a.woff2 b/_static/fonts/e1c796916b3538c0a441a60a90f5520a.woff2 new file mode 100644 index 00000000..57f1b8fb Binary files /dev/null and b/_static/fonts/e1c796916b3538c0a441a60a90f5520a.woff2 differ diff --git a/_static/fonts/e25d7629424c8d89c39bddb9b6a99b6f.woff2 b/_static/fonts/e25d7629424c8d89c39bddb9b6a99b6f.woff2 new file mode 100644 index 00000000..b1e0e31d Binary files /dev/null and b/_static/fonts/e25d7629424c8d89c39bddb9b6a99b6f.woff2 differ diff --git a/_static/fonts/e29a95b21321270ffb79543ee0cba17d.woff2 b/_static/fonts/e29a95b21321270ffb79543ee0cba17d.woff2 new file mode 100644 index 00000000..47cfc4d0 Binary files /dev/null and b/_static/fonts/e29a95b21321270ffb79543ee0cba17d.woff2 differ diff --git a/_static/fonts/e340d891a3edd4db23f95f759fe85e53.woff2 b/_static/fonts/e340d891a3edd4db23f95f759fe85e53.woff2 new file mode 100644 index 00000000..52edf12f Binary files /dev/null and b/_static/fonts/e340d891a3edd4db23f95f759fe85e53.woff2 differ diff --git a/_static/fonts/e3476a3f9c6b9343a3398c7b1d5c84eb.woff2 b/_static/fonts/e3476a3f9c6b9343a3398c7b1d5c84eb.woff2 new file mode 100644 index 00000000..659bfaf1 Binary files /dev/null and b/_static/fonts/e3476a3f9c6b9343a3398c7b1d5c84eb.woff2 differ diff --git a/_static/fonts/e38070f61c248c215a19fee66f151635.woff2 b/_static/fonts/e38070f61c248c215a19fee66f151635.woff2 new file mode 100644 index 00000000..3b4f01a4 Binary files /dev/null and b/_static/fonts/e38070f61c248c215a19fee66f151635.woff2 differ diff --git a/_static/fonts/e38d3465f2c8bf67cc531b6a68484b01.woff2 b/_static/fonts/e38d3465f2c8bf67cc531b6a68484b01.woff2 new file mode 100644 index 00000000..b33115d6 Binary files /dev/null and b/_static/fonts/e38d3465f2c8bf67cc531b6a68484b01.woff2 differ diff --git a/_static/fonts/e3e9abf60b61dbf89160e8ad6cbc60ba.woff2 b/_static/fonts/e3e9abf60b61dbf89160e8ad6cbc60ba.woff2 new file mode 100644 index 00000000..db3b7314 Binary files /dev/null and b/_static/fonts/e3e9abf60b61dbf89160e8ad6cbc60ba.woff2 differ diff --git a/_static/fonts/e43155115077f8ce42db882a6bed76a7.woff2 b/_static/fonts/e43155115077f8ce42db882a6bed76a7.woff2 new file mode 100644 index 00000000..fbee621e Binary files /dev/null and b/_static/fonts/e43155115077f8ce42db882a6bed76a7.woff2 differ diff --git a/_static/fonts/e44c11f4834bdd4d6b6da7b8ee5eaebc.woff2 b/_static/fonts/e44c11f4834bdd4d6b6da7b8ee5eaebc.woff2 new file mode 100644 index 00000000..5a5fad1a Binary files /dev/null and b/_static/fonts/e44c11f4834bdd4d6b6da7b8ee5eaebc.woff2 differ diff --git a/_static/fonts/e4a744be99f104ecbd224af9a91da2a7.woff2 b/_static/fonts/e4a744be99f104ecbd224af9a91da2a7.woff2 new file mode 100644 index 00000000..50c55be7 Binary files /dev/null and b/_static/fonts/e4a744be99f104ecbd224af9a91da2a7.woff2 differ diff --git a/_static/fonts/e4f3be7a1ed443693c97b52476b67b58.ttf b/_static/fonts/e4f3be7a1ed443693c97b52476b67b58.ttf new file mode 100644 index 00000000..cf5e3a98 Binary files /dev/null and b/_static/fonts/e4f3be7a1ed443693c97b52476b67b58.ttf differ diff --git a/_static/fonts/e5b29c36b2e7a2f4db58307359fa5740.woff2 b/_static/fonts/e5b29c36b2e7a2f4db58307359fa5740.woff2 new file mode 100644 index 00000000..d8a648a0 Binary files /dev/null and b/_static/fonts/e5b29c36b2e7a2f4db58307359fa5740.woff2 differ diff --git a/_static/fonts/e6bae3f6087387a22a5897fef44189b7.woff2 b/_static/fonts/e6bae3f6087387a22a5897fef44189b7.woff2 new file mode 100644 index 00000000..045829c6 Binary files /dev/null and b/_static/fonts/e6bae3f6087387a22a5897fef44189b7.woff2 differ diff --git a/_static/fonts/e6f072bccf56c7a5885cad43b269048e.woff2 b/_static/fonts/e6f072bccf56c7a5885cad43b269048e.woff2 new file mode 100644 index 00000000..b367959a Binary files /dev/null and b/_static/fonts/e6f072bccf56c7a5885cad43b269048e.woff2 differ diff --git a/_static/fonts/e86101cc8a902668923f9cabfd607fdb.woff2 b/_static/fonts/e86101cc8a902668923f9cabfd607fdb.woff2 new file mode 100644 index 00000000..4e708e8b Binary files /dev/null and b/_static/fonts/e86101cc8a902668923f9cabfd607fdb.woff2 differ diff --git a/_static/fonts/e972943c8c50df41fca0fab199af6055.woff2 b/_static/fonts/e972943c8c50df41fca0fab199af6055.woff2 new file mode 100644 index 00000000..5af907da Binary files /dev/null and b/_static/fonts/e972943c8c50df41fca0fab199af6055.woff2 differ diff --git a/_static/fonts/e9a3e9f5f5250477366117d455632fb8.woff2 b/_static/fonts/e9a3e9f5f5250477366117d455632fb8.woff2 new file mode 100644 index 00000000..b11d2e3c Binary files /dev/null and b/_static/fonts/e9a3e9f5f5250477366117d455632fb8.woff2 differ diff --git a/_static/fonts/ebfaffa0ce7a84bf2216d03982a7a79b.woff2 b/_static/fonts/ebfaffa0ce7a84bf2216d03982a7a79b.woff2 new file mode 100644 index 00000000..dead4205 Binary files /dev/null and b/_static/fonts/ebfaffa0ce7a84bf2216d03982a7a79b.woff2 differ diff --git a/_static/fonts/ec52baba03c31dfa5c0d0bc6906ba425.woff2 b/_static/fonts/ec52baba03c31dfa5c0d0bc6906ba425.woff2 new file mode 100644 index 00000000..2cb3c78e Binary files /dev/null and b/_static/fonts/ec52baba03c31dfa5c0d0bc6906ba425.woff2 differ diff --git a/_static/fonts/ecb54ce0193aacd9bc7dbdb75eb9c824.woff2 b/_static/fonts/ecb54ce0193aacd9bc7dbdb75eb9c824.woff2 new file mode 100644 index 00000000..f22dd365 Binary files /dev/null and b/_static/fonts/ecb54ce0193aacd9bc7dbdb75eb9c824.woff2 differ diff --git a/_static/fonts/ed5bf02d648da84d8d68e5e7a9261c19.woff2 b/_static/fonts/ed5bf02d648da84d8d68e5e7a9261c19.woff2 new file mode 100644 index 00000000..887feeca Binary files /dev/null and b/_static/fonts/ed5bf02d648da84d8d68e5e7a9261c19.woff2 differ diff --git a/_static/fonts/ee85eaf88a859d80dedaa048b0e142f7.woff2 b/_static/fonts/ee85eaf88a859d80dedaa048b0e142f7.woff2 new file mode 100644 index 00000000..7557ee1d Binary files /dev/null and b/_static/fonts/ee85eaf88a859d80dedaa048b0e142f7.woff2 differ diff --git a/_static/fonts/eee5f43c92cb9030d97f216bbb2ba34e.woff2 b/_static/fonts/eee5f43c92cb9030d97f216bbb2ba34e.woff2 new file mode 100644 index 00000000..fd8fb365 Binary files /dev/null and b/_static/fonts/eee5f43c92cb9030d97f216bbb2ba34e.woff2 differ diff --git a/_static/fonts/ef1fccbc8e3265cc39de4e7bab29fc77.woff2 b/_static/fonts/ef1fccbc8e3265cc39de4e7bab29fc77.woff2 new file mode 100644 index 00000000..0eb50210 Binary files /dev/null and b/_static/fonts/ef1fccbc8e3265cc39de4e7bab29fc77.woff2 differ diff --git a/_static/fonts/f04ac67be64e2ad4a8e0900f60287d6c.woff2 b/_static/fonts/f04ac67be64e2ad4a8e0900f60287d6c.woff2 new file mode 100644 index 00000000..9c69cfeb Binary files /dev/null and b/_static/fonts/f04ac67be64e2ad4a8e0900f60287d6c.woff2 differ diff --git a/_static/fonts/f07d0c93a3147897fad7ae0f6d52fba1.woff2 b/_static/fonts/f07d0c93a3147897fad7ae0f6d52fba1.woff2 new file mode 100644 index 00000000..94b43008 Binary files /dev/null and b/_static/fonts/f07d0c93a3147897fad7ae0f6d52fba1.woff2 differ diff --git a/_static/fonts/f200b88b158918b03884c3529a49f6c3.woff2 b/_static/fonts/f200b88b158918b03884c3529a49f6c3.woff2 new file mode 100644 index 00000000..a7317672 Binary files /dev/null and b/_static/fonts/f200b88b158918b03884c3529a49f6c3.woff2 differ diff --git a/_static/fonts/f2b9287e870e65639bc34af8a226575b.woff2 b/_static/fonts/f2b9287e870e65639bc34af8a226575b.woff2 new file mode 100644 index 00000000..40f04fa0 Binary files /dev/null and b/_static/fonts/f2b9287e870e65639bc34af8a226575b.woff2 differ diff --git a/_static/fonts/f38f5947317e57e3c4cc20b55cf53710.woff2 b/_static/fonts/f38f5947317e57e3c4cc20b55cf53710.woff2 new file mode 100644 index 00000000..669ea34d Binary files /dev/null and b/_static/fonts/f38f5947317e57e3c4cc20b55cf53710.woff2 differ diff --git a/_static/fonts/f491d519ae3928214f725a9b27936bf9.woff2 b/_static/fonts/f491d519ae3928214f725a9b27936bf9.woff2 new file mode 100644 index 00000000..6d3c43d0 Binary files /dev/null and b/_static/fonts/f491d519ae3928214f725a9b27936bf9.woff2 differ diff --git a/_static/fonts/f5eae6b0ac5ed02f8d5a9a35a51f7c74.ttf b/_static/fonts/f5eae6b0ac5ed02f8d5a9a35a51f7c74.ttf new file mode 100644 index 00000000..24a1af94 Binary files /dev/null and b/_static/fonts/f5eae6b0ac5ed02f8d5a9a35a51f7c74.ttf differ diff --git a/_static/fonts/f67cbe19918d1ea33e927a2b83dfc964.woff2 b/_static/fonts/f67cbe19918d1ea33e927a2b83dfc964.woff2 new file mode 100644 index 00000000..0dc0dc42 Binary files /dev/null and b/_static/fonts/f67cbe19918d1ea33e927a2b83dfc964.woff2 differ diff --git a/_static/fonts/f6ae49575b5a269d35d25f3c774bcc7f.woff2 b/_static/fonts/f6ae49575b5a269d35d25f3c774bcc7f.woff2 new file mode 100644 index 00000000..2a6e5eb1 Binary files /dev/null and b/_static/fonts/f6ae49575b5a269d35d25f3c774bcc7f.woff2 differ diff --git a/_static/fonts/f6c56d7a605e19cba07493bde4326ca0.woff2 b/_static/fonts/f6c56d7a605e19cba07493bde4326ca0.woff2 new file mode 100644 index 00000000..3e9f41a8 Binary files /dev/null and b/_static/fonts/f6c56d7a605e19cba07493bde4326ca0.woff2 differ diff --git a/_static/fonts/f8dc85e7e10f9eafb62db41ba60e19a3.woff2 b/_static/fonts/f8dc85e7e10f9eafb62db41ba60e19a3.woff2 new file mode 100644 index 00000000..dca1d8fe Binary files /dev/null and b/_static/fonts/f8dc85e7e10f9eafb62db41ba60e19a3.woff2 differ diff --git a/_static/fonts/f9943037d734ce0a3dca872da278a77c.woff2 b/_static/fonts/f9943037d734ce0a3dca872da278a77c.woff2 new file mode 100644 index 00000000..c56f1344 Binary files /dev/null and b/_static/fonts/f9943037d734ce0a3dca872da278a77c.woff2 differ diff --git a/_static/fonts/fd2133ab2aba43ef040fad88322b695b.woff2 b/_static/fonts/fd2133ab2aba43ef040fad88322b695b.woff2 new file mode 100644 index 00000000..bf1390ea Binary files /dev/null and b/_static/fonts/fd2133ab2aba43ef040fad88322b695b.woff2 differ diff --git a/_static/fonts/fdd953c288159a1f149911720d8a19fa.woff2 b/_static/fonts/fdd953c288159a1f149911720d8a19fa.woff2 new file mode 100644 index 00000000..47e69cf8 Binary files /dev/null and b/_static/fonts/fdd953c288159a1f149911720d8a19fa.woff2 differ diff --git a/_static/fonts/fe56d0d137acb0f9b17754d3670f5eca.woff2 b/_static/fonts/fe56d0d137acb0f9b17754d3670f5eca.woff2 new file mode 100644 index 00000000..b0ed6d69 Binary files /dev/null and b/_static/fonts/fe56d0d137acb0f9b17754d3670f5eca.woff2 differ diff --git a/_static/fonts/fe89051f65780458ad298ceb78c1812a.woff2 b/_static/fonts/fe89051f65780458ad298ceb78c1812a.woff2 new file mode 100644 index 00000000..62dbaa8e Binary files /dev/null and b/_static/fonts/fe89051f65780458ad298ceb78c1812a.woff2 differ diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 00000000..c7fe6c6f --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,192 @@ +/* + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/docs/_static/logo.jpg b/_static/logo.jpg similarity index 100% rename from docs/_static/logo.jpg rename to _static/logo.jpg diff --git a/_static/sphinx_immaterial_theme.0555d7d8f9fd34954.min.css b/_static/sphinx_immaterial_theme.0555d7d8f9fd34954.min.css new file mode 100644 index 00000000..8dea4c6d --- /dev/null +++ b/_static/sphinx_immaterial_theme.0555d7d8f9fd34954.min.css @@ -0,0 +1,4 @@ +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:content-box;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:separate;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:transparent;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:rgba(0,0,0,.87);--md-default-fg-color--light:rgba(0,0,0,.54);--md-default-fg-color--lighter:rgba(0,0,0,.32);--md-default-fg-color--lightest:rgba(0,0,0,.07);--md-default-bg-color:#fff;--md-default-bg-color--light:hsla(0,0%,100%,.7);--md-default-bg-color--lighter:hsla(0,0%,100%,.3);--md-default-bg-color--lightest:hsla(0,0%,100%,.12);--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-hl-color:#4287ff;--md-code-hl-color--light:rgba(66,135,255,.1);--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:rgba(245,80,61,.15);--md-typeset-ins-color:rgba(11,213,112,.15);--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:rgba(255,255,0,.5);--md-typeset-table-color:rgba(0,0,0,.12);--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:rgba(0,0,0,.87);--md-warning-bg-color:#ff9;--md-footer-fg-color:#fff;--md-footer-fg-color--light:hsla(0,0%,100%,.7);--md-footer-fg-color--lighter:hsla(0,0%,100%,.45);--md-footer-bg-color:rgba(0,0,0,.87);--md-footer-bg-color--dark:rgba(0,0,0,.32);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.05),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.1),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.35)}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}.si-icon-inline:before{background-color:var(--md-default-fg-color);content:"";display:inline-flex;height:1.125em;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;vertical-align:text-top;width:1.125em}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6;overflow-wrap:break-word}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset h5 code{text-transform:none}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent)}.md-typeset a code{color:currentcolor;transition:background-color 125ms}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset .code-block-caption+.notranslate .highlighttable,.md-typeset .code-block-caption+.notranslate pre{margin-top:0}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol ol ol ol,.md-typeset ul ol ol ol{list-style-type:upper-alpha}.md-typeset ol ol ol ol ol,.md-typeset ul ol ol ol ol{list-style-type:upper-roman}.md-typeset ol[type],.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table.data:not(.plain){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto;width:-moz-max-content;width:max-content}@media print{.md-typeset table.data:not(.plain){display:table}}.md-typeset table.data:not(.plain)+*{margin-top:1.5em}.md-typeset table.data:not(.plain) td>:first-child,.md-typeset table.data:not(.plain) th>:first-child{margin-top:0}.md-typeset table.data:not(.plain) td>:last-child,.md-typeset table.data:not(.plain) th>:last-child{margin-bottom:0}.md-typeset table.data:not(.plain) td:not([align],.align-center,.align-left,.align-right),.md-typeset table.data:not(.plain) th:not([align],.align-center,.align-left,.align-right){text-align:left}[dir=rtl] .md-typeset table.data:not(.plain) td:not([align],.align-center,.align-left,.align-right),[dir=rtl] .md-typeset table.data:not(.plain) th:not([align],.align-center,.align-left,.align-right){text-align:right}.md-typeset table.data:not(.plain) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table.data:not(.plain) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table.data:not(.plain) tbody tr{transition:background-color 125ms}.md-typeset table.data:not(.plain) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table.data:not(.plain) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-typeset .md-author{border-radius:100%;display:block;flex-shrink:0;height:1.6rem;overflow:hidden;position:relative;transition:color 125ms,transform 125ms;width:1.6rem}.md-typeset .md-author img{display:block}.md-typeset .md-author--more{background:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--lighter);font-size:.6rem;font-weight:700;line-height:1.6rem;text-align:center}.md-typeset .md-author--long{height:2.4rem;width:2.4rem}.md-typeset a.md-author{transform:scale(1)}.md-typeset a.md-author img{border-radius:100%;filter:grayscale(100%) opacity(75%);transition:filter 125ms}.md-typeset a.md-author:focus,.md-typeset a.md-author:hover{transform:scale(1.1);z-index:1}.md-typeset a.md-author:focus img,.md-typeset a.md-author:hover img{filter:grayscale(0)}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;position:absolute;right:.5em;top:.5em;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .md-code__content{display:grid}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:rgba(0,0,0,.54);height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}@media print{.md-feedback{display:none}}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;opacity:.7}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem transparent,0 .2rem .4rem transparent;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-left:1rem;margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem;margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-hero{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-size:1rem;overflow:hidden;transition:background .25s}.md-hero__inner{margin-top:1rem;padding:.8rem .8rem .4rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s;transition-delay:.1s}@media screen and (max-width:76.234375em){.md-hero__inner{margin-bottom:1.2rem;margin-top:2.4rem}}[data-md-state=hidden] .md-hero__inner{opacity:0;pointer-events:none;transform:translateY(.625rem);transition:transform 0ms .4s,opacity .1s 0ms}.md-hero--expand .md-hero__inner{margin-bottom:1.2rem}.md-meta{color:var(--md-default-fg-color--light);font-size:.7rem;line-height:1.3}.md-meta__list{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.md-meta__item:not(:last-child):after{content:"·";margin-left:.2rem;margin-right:.2rem}.md-meta__link{color:var(--md-typeset-a-color)}.md-meta__link:focus,.md-meta__link:hover{color:var(--md-accent-fg-color)}.md-draft{background-color:#ff1744;border-radius:.125em;color:#fff;display:inline-block;font-weight:700;padding-left:.5714285714em;padding-right:.5714285714em}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{align-items:center;color:var(--md-default-fg-color--light);display:flex;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentcolor;display:block;height:2.4rem;max-width:100%;-o-object-fit:contain;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__link{align-items:flex-start;display:flex;gap:.4rem;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link.md-nav__sticky{box-shadow:0 -.625em var(--md-default-bg-color),0 .625em var(--md-default-bg-color)}.md-nav__link--passed{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__link--in-viewport{position:relative}.md-nav__link--in-viewport:before{background-color:var(--md-primary-fg-color);bottom:0;content:"";height:100%;position:absolute;right:calc(100% + .3rem);top:0;width:.05rem}.md-nav__link .md-ellipsis{position:relative}[dir=ltr] .md-nav__link .md-icon:last-child{margin-left:auto}[dir=rtl] .md-nav__link .md-icon:last-child{margin-right:auto}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em;position:relative}.md-nav__link[for]:focus,.md-nav__link[for]:hover,.md-nav__link[href]:focus,.md-nav__link[href]:hover{color:var(--md-accent-fg-color);cursor:pointer}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__container>.md-nav__link{margin-top:0}.md-nav__container>.md-nav__link:first-child{flex-grow:1;min-width:0}.md-nav__sticky{background-color:var(--md-default-bg-color);position:sticky;top:var(--md-nav__header-height,0);z-index:var(--md-nav__sticky-zindex)}.md-nav .md-ellipsis{display:block;flex-grow:1;white-space:normal}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.234375em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__sticky{background-color:transparent;box-shadow:none;position:static;z-index:auto}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;line-height:2.4rem;min-height:5.6rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link svg{margin-top:.1em}.md-nav--primary .md-nav__link>.md-nav__link{padding:0}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:transparent;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:transparent}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{backface-visibility:hidden}.md-nav .md-nav__title .md-ellipsis{white-space:nowrap}.md-nav .md-nav__title .md-ellipsis wbr{display:none}}@media screen and (max-width:59.984375em){.md-nav__current-nested{display:none!important}.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav{margin-bottom:-.4rem}.md-nav__current-toc{display:none!important}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--secondary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--secondary .md-nav__list{padding-right:.6rem}.md-nav--secondary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--secondary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--secondary .md-nav__item>.md-nav__link{margin-left:.4rem}}@media screen and (min-width:76.25em){.md-nav{margin-bottom:-.4rem;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--primary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--primary .md-nav__list{padding-right:.6rem}.md-nav--primary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--primary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--primary .md-nav__item>.md-nav__link{margin-left:.4rem}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:minmax(.4rem,0fr);opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:minmax(.4rem,1fr);opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav>.md-nav__list,.md-nav__toggle:checked~.md-nav>.md-nav__list{overflow:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link[for]{color:var(--md-default-fg-color--light)}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav__link .md-icon,.md-nav__item--section>.md-nav__link>[for]{display:none}[dir=ltr] .md-nav__item--section>.md-nav{margin-left:-.6rem}[dir=rtl] .md-nav__item--section>.md-nav{margin-right:-.6rem}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s;width:.9rem}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;border-radius:100%;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;vertical-align:-.1rem;width:100%}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);margin-top:0;position:sticky;top:0;z-index:var(--md-nav__sticky-zindex,1)}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}[dir=ltr] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-left:-.6rem}[dir=rtl] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-right:-.6rem}.md-nav--lifted>.md-nav__list>.md-nav__item>[for]{color:var(--md-default-fg-color--light)}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:minmax(.4rem,1fr);opacity:1;visibility:visible}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}.md-pagination{font-size:.8rem;font-weight:700;gap:.4rem}.md-pagination,.md-pagination>*{align-items:center;display:flex;justify-content:center}.md-pagination>*{border-radius:.2rem;height:1.8rem;min-width:1.8rem;text-align:center}.md-pagination__current{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light)}.md-pagination__link{transition:color 125ms,background-color 125ms}.md-pagination__link:focus,.md-pagination__link:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-pagination__link:focus svg,.md-pagination__link:hover svg{color:var(--md-accent-fg-color)}.md-pagination__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-pagination__link svg{fill:currentcolor;color:var(--md-default-fg-color--lighter);display:block;max-height:100%;width:1.2rem}.md-post__back{border-bottom:.05rem solid var(--md-default-fg-color--lightest);margin-bottom:1.2rem;padding-bottom:1.2rem}@media screen and (max-width:76.234375em){.md-post__back{display:none}}[dir=rtl] .md-post__back svg{transform:scaleX(-1)}.md-post__authors{display:flex;flex-direction:column;gap:.6rem;margin:0 .6rem 1.2rem}.md-post .md-post__meta a{transition:color 125ms}.md-post .md-post__meta a:focus,.md-post .md-post__meta a:hover{color:var(--md-accent-fg-color)}.md-post__title{color:var(--md-default-fg-color--light);font-weight:700}.md-post--excerpt{margin-bottom:3.2rem}.md-post--excerpt .md-post__header{align-items:center;display:flex;gap:.6rem;min-height:1.6rem}.md-post--excerpt .md-post__authors{align-items:center;display:inline-flex;flex-direction:row;gap:.2rem;margin:0;min-height:2.4rem}[dir=ltr] .md-post--excerpt .md-post__meta .md-meta__list{margin-right:.4rem}[dir=rtl] .md-post--excerpt .md-post__meta .md-meta__list{margin-left:.4rem}.md-post--excerpt .md-post__content>:first-child{--md-scroll-margin:6rem;margin-top:0}.md-post>.md-nav--secondary{margin:1em 0}.md-profile{align-items:center;display:flex;font-size:.7rem;gap:.6rem;line-height:1.4;width:100%}.md-profile__description{flex-grow:1}.md-content--post{display:flex}@media screen and (max-width:76.234375em){.md-content--post{flex-flow:column-reverse}}.md-content--post>.md-content__inner{flex-grow:1;min-width:0}@media screen and (min-width:76.25em){[dir=ltr] .md-content--post>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-content--post>.md-content__inner{margin-right:1.2rem}}@media screen and (max-width:76.234375em){.md-sidebar.md-sidebar--post{padding:0;position:static;width:100%}.md-sidebar.md-sidebar--post .md-sidebar__scrollwrap{overflow:visible}.md-sidebar.md-sidebar--post .md-sidebar__inner{padding:0}.md-sidebar.md-sidebar--post .md-post__meta{margin-left:.6rem;margin-right:.6rem}.md-sidebar.md-sidebar--post .md-nav__item{border:none;display:inline}.md-sidebar.md-sidebar--post .md-nav__list{display:inline-flex;flex-wrap:wrap;gap:.6rem;padding-bottom:.6rem;padding-top:.6rem}.md-sidebar.md-sidebar--post .md-nav__link{padding:0}.md-sidebar.md-sidebar--post .md-nav{height:auto;margin-bottom:0;position:static}}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:rgba(0,0,0,.54);cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{backface-visibility:hidden}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__inner{float:right}[dir=rtl] .md-search__inner{float:left}.md-search__inner{padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}}@media screen and (min-width:60em) and (max-width:76.234375em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem transparent;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:rgba(0,0,0,.26);border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:hsla(0,0%,100%,.12)}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem rgba(0,0,0,.07);color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:transparent;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::-moz-placeholder{-moz-transition:color .25s;transition:color .25s}.md-search__input::placeholder{transition:color .25s}.md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.984375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::-moz-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::-moz-placeholder{color:transparent}[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:transparent}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>.md-icon{margin-left:.2rem}[dir=rtl] .md-search__options>.md-icon{margin-right:.2rem}.md-search__options>.md-icon{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>.md-icon:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.984375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:focus,.md-search-result__link:hover{background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more>summary{cursor:pointer;display:block;outline:none;position:sticky;scroll-snap-align:start;top:0;z-index:1}.md-search-result__more>summary::marker{display:none}.md-search-result__more>summary::-webkit-details-marker{display:none}.md-search-result__more>summary>div{color:var(--md-typeset-a-color);font-size:.64rem;padding:.75em .8rem;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more>summary>div{padding-left:2.2rem}[dir=rtl] .md-search-result__more>summary>div{padding-right:2.2rem}}.md-search-result__more>summary:focus>div,.md-search-result__more>summary:hover>div{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more[open]>summary{background-color:var(--md-default-bg-color)}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.984375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result .md-typeset{color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.6}.md-search-result .md-typeset h1{color:var(--md-default-fg-color);font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}.md-search-result .md-typeset h1 mark{text-decoration:none}.md-search-result .md-typeset h2{color:var(--md-default-fg-color);font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result .md-typeset h2 mark{text-decoration:none}.md-search-result__terms{color:var(--md-default-fg-color);display:block;font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:transparent;color:var(--md-accent-fg-color);text-decoration:underline}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid transparent;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid transparent;border-right:.2rem solid transparent;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{scrollbar-gutter:stable;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.234375em){.md-overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:inline-flex;flex-wrap:wrap;gap:.5em;margin-bottom:.75em;margin-top:-.125em}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:700;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.5rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-style:normal;font-weight:400;outline:none;text-align:initial;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:xxx;list-style:none}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(xxx);counter-increment:xxx;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(-.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid transparent;border-right:var(--md-tooltip-tail) solid transparent;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 hsla(0,0%,0%,.05))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 hsla(0,0%,0%,.05));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.5,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=tooltip]>.md-tooltip2__inner{font-size:.5rem;font-weight:700;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__alias{margin-left:.3rem;opacity:.7}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.075rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid;transition:box-shadow 125ms}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition:focus-within,.md-typeset details:focus-within{box-shadow:0 0 0 .2rem rgba(68,138,255,.1)}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:rgba(68,138,255,.1);border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .admonition.note:focus-within,.md-typeset details.note:focus-within{box-shadow:0 0 0 .2rem rgba(68,138,255,.1)}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:rgba(68,138,255,.1)}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{border-color:#00b0ff}.md-typeset .admonition.abstract:focus-within,.md-typeset details.abstract:focus-within{box-shadow:0 0 0 .2rem rgba(0,176,255,.1)}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary{background-color:rgba(0,176,255,.1)}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{border-color:#00b8d4}.md-typeset .admonition.info:focus-within,.md-typeset details.info:focus-within{box-shadow:0 0 0 .2rem rgba(0,184,212,.1)}.md-typeset .info>.admonition-title,.md-typeset .info>summary{background-color:rgba(0,184,212,.1)}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .admonition.tip:focus-within,.md-typeset details.tip:focus-within{box-shadow:0 0 0 .2rem rgba(0,191,165,.1)}.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:rgba(0,191,165,.1)}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{border-color:#00c853}.md-typeset .admonition.success:focus-within,.md-typeset details.success:focus-within{box-shadow:0 0 0 .2rem rgba(0,200,83,.1)}.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:rgba(0,200,83,.1)}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{border-color:#64dd17}.md-typeset .admonition.question:focus-within,.md-typeset details.question:focus-within{box-shadow:0 0 0 .2rem rgba(100,221,23,.1)}.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:rgba(100,221,23,.1)}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{border-color:#ff9100}.md-typeset .admonition.warning:focus-within,.md-typeset details.warning:focus-within{box-shadow:0 0 0 .2rem rgba(255,145,0,.1)}.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:rgba(255,145,0,.1)}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{border-color:#ff5252}.md-typeset .admonition.failure:focus-within,.md-typeset details.failure:focus-within{box-shadow:0 0 0 .2rem rgba(255,82,82,.1)}.md-typeset .failure>.admonition-title,.md-typeset .failure>summary{background-color:rgba(255,82,82,.1)}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{border-color:#ff1744}.md-typeset .admonition.danger:focus-within,.md-typeset details.danger:focus-within{box-shadow:0 0 0 .2rem rgba(255,23,68,.1)}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary{background-color:rgba(255,23,68,.1)}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .admonition.bug:focus-within,.md-typeset details.bug:focus-within{box-shadow:0 0 0 .2rem rgba(245,0,87,.1)}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:rgba(245,0,87,.1)}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .admonition.example:focus-within,.md-typeset details.example:focus-within{box-shadow:0 0 0 .2rem rgba(124,77,255,.1)}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:rgba(124,77,255,.1)}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .admonition.quote:focus-within,.md-typeset details.quote:focus-within{box-shadow:0 0 0 .2rem hsla(0,0%,62%,.1)}.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:hsla(0,0%,62%,.1)}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:-moz-min-content;width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .kc,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying]{display:initial}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;padding-right:.5882352941em}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result,.md-typeset .highlighttable+.result,.md-typeset .literal-block-wrapper+.result,.md-typeset .results-prefix+.result,.md-typeset div[class^=highlight-]+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after,.md-typeset .highlighttable+.result:after,.md-typeset .literal-block-wrapper+.result:after,.md-typeset .results-prefix+.result:after,.md-typeset div[class^=highlight-]+.result:after{clear:both;content:"";display:block}.md-typeset .results .results-prefix+.result{margin-top:0}.md-typeset .results .results-prefix{background-color:var(--md-code-bg-color);font-size:.85em;font-weight:700;margin-top:-1em;padding:.6617647059em 1.1764705882em}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid transparent;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,transparent);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,transparent);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}.rst-versions{font-family:var(--md-text-font-family)}.rst-versions.rst-badge{bottom:inherit!important;font-size:.85rem;height:auto;top:50px}@media print{.giscus,[id=__comments]{display:none}}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}:root>*{--md-graphviz-edge-color:var(--md-default-fg-color);--md-graphviz-node-bg-color:var(--md-accent-fg-color--transparent);--md-graphviz-node-fg-color:var(--md-accent-fg-color);--md-graphviz-label-bg-color:var(--md-default-bg-color);--md-graphviz-label-fg-color:var(--md-code-fg-color);--md-graphviz-a-hover-color:var(--md-primary-fg-color)}.graphviz{margin:1em 0}.graphviz a:hover>text{fill:var(--md-graphviz-hover-color)!important}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.1rem;display:block;margin:0;padding:.8rem;transition:border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:transparent;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}}.md-typeset .align-left{text-align:left}.md-typeset .align-right{text-align:right}.md-typeset .align-center{clear:both;text-align:center}.md-typeset .align-top{vertical-align:top}.md-typeset .align-middle{vertical-align:middle}.md-typeset .align-bottom{vertical-align:bottom}.md-typeset .figure.align-left,.md-typeset figure.align-left,.md-typeset img.align-left,.md-typeset object.align-left,.md-typeset table.align-left{margin-right:auto}.md-typeset .figure.align-center,.md-typeset figure.align-center,.md-typeset img.align-center,.md-typeset object.align-center,.md-typeset table.align-center{margin-left:auto;margin-right:auto}.md-typeset .figure.align-right,.md-typeset figure.align-right,.md-typeset img.align-right,.md-typeset object.align-right,.md-typeset table.align-right{margin-left:auto}.md-typeset .figure.align-center,.md-typeset .figure.align-right,.md-typeset figure.align-center,.md-typeset figure.align-right,.md-typeset img.align-center,.md-typeset img.align-right,.md-typeset object.align-center,.md-typeset object.align-right{display:block}.md-typeset .figure.align-left,.md-typeset .figure.align-right,.md-typeset figure.align-left,.md-typeset figure.align-right,.md-typeset table.align-center,.md-typeset table.align-left,.md-typeset table.align-right{text-align:inherit}.md-typeset .rubric{font-weight:700}.md-typeset .viewcode-block .viewcode-back{float:right}.md-typeset .versionmodified{font-style:italic}.md-typeset div.line-block{display:block}.md-typeset div.line-block div.line-block{margin-left:1.5em}.md-typeset aside.footnote,.md-typeset div.citation{display:grid;grid-auto-columns:minmax(auto,max-content)}.md-typeset aside.footnote>span.label,.md-typeset div.citation>span.label{grid-column:1}.md-typeset aside.footnote>span.backrefs,.md-typeset div.citation>span.backrefs{grid-column:2}.md-typeset aside.footnote>span:last-of-type,.md-typeset div.citation>span:last-of-type{padding-right:.5em}.md-typeset aside.footnote>:not(span.backrefs,span.label),.md-typeset div.citation>:not(span.backrefs,span.label){grid-column:3}.md-typeset aside.footnote>:not(span.backrefs,span.label):first-of-type,.md-typeset div.citation>:not(span.backrefs,span.label):first-of-type{margin-top:0}.md-typeset aside.footnote>:not(span.backrefs,span.label):last-child,.md-typeset div.citation>:not(span.backrefs,span.label):last-child{margin-bottom:0}.md-typeset aside.footnote>:not(span.backrefs,span.label):last-child:after,.md-typeset div.citation>:not(span.backrefs,span.label):last-child:after{clear:both;content:""}.md-typeset dl.api-field>dt,.md-typeset dl.objdesc>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family)}.md-typeset dl.api-field>dt code,.md-typeset dl.objdesc>dt code{border-radius:0;padding:0}.md-typeset dl.api-field>dt .sig-name:not(.sig-name-nonprimary),.md-typeset dl.objdesc>dt .sig-name:not(.sig-name-nonprimary){color:var(--md-code-hl-name-color);font-weight:700;padding:0}.md-typeset dl.api-field>dt .sig-param,.md-typeset dl.objdesc>dt .sig-param{font-style:normal}.md-typeset dl.api-field>dt .sig-param .n:not(.desctype),.md-typeset dl.objdesc>dt .sig-param .n:not(.desctype){color:var(--md-default-fg-color--light)}.md-typeset dl.api-field>dt dd,.md-typeset dl.api-field>dt dl,.md-typeset dl.objdesc>dt dd,.md-typeset dl.objdesc>dt dl{margin-bottom:0;margin-top:0}.md-typeset dl.api-field>dt .sig-param a.reference .n:not(.desctype):hover,.md-typeset dl.objdesc>dt .sig-param a.reference .n:not(.desctype):hover{color:var(--md-accent-fg-color)}.md-typeset dl.api-field>dt.sig-wrap .sig-param-decl:before,.md-typeset dl.objdesc>dt.sig-wrap .sig-param-decl:before{content:"\a ";white-space:pre}.md-typeset dl.api-field>dt.sig-wrap .sig-paren~.sig-paren:before,.md-typeset dl.objdesc>dt.sig-wrap .sig-paren~.sig-paren:before{content:"\a";white-space:pre}.md-typeset dl.objdesc>dd>dl.field-list>dt>.colon{display:none}.md-typeset .sig-inline a.reference.sig-name,.md-typeset .sig-inline a.reference:not(.desctype)>.n,.md-typeset .sig-inline a.reference>.sig-name,.md-typeset dl.api-field>dt a.reference.sig-name,.md-typeset dl.api-field>dt a.reference:not(.desctype)>.n,.md-typeset dl.api-field>dt a.reference>.sig-name,.md-typeset dl.objdesc>dt a.reference.sig-name,.md-typeset dl.objdesc>dt a.reference:not(.desctype)>.n,.md-typeset dl.objdesc>dt a.reference>.sig-name{color:var(--md-typeset-a-color)}.md-typeset .sig-inline a.reference.sig-name:hover,.md-typeset .sig-inline a.reference:not(.desctype)>.n:hover,.md-typeset .sig-inline a.reference>.sig-name:hover,.md-typeset dl.api-field>dt a.reference.sig-name:hover,.md-typeset dl.api-field>dt a.reference:not(.desctype)>.n:hover,.md-typeset dl.api-field>dt a.reference>.sig-name:hover,.md-typeset dl.objdesc>dt a.reference.sig-name:hover,.md-typeset dl.objdesc>dt a.reference:not(.desctype)>.n:hover,.md-typeset dl.objdesc>dt a.reference>.sig-name:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline .desctype,.md-typeset .sig-inline .desctype>a.reference,.md-typeset dl.api-field>dt .desctype,.md-typeset dl.api-field>dt .desctype>a.reference,.md-typeset dl.objdesc>dt .desctype,.md-typeset dl.objdesc>dt .desctype>a.reference{color:var(--md-code-hl-special-color)}.md-typeset .sig-inline .desctype .n,.md-typeset .sig-inline .desctype>a.reference .n,.md-typeset dl.api-field>dt .desctype .n,.md-typeset dl.api-field>dt .desctype>a.reference .n,.md-typeset dl.objdesc>dt .desctype .n,.md-typeset dl.objdesc>dt .desctype>a.reference .n{color:inherit}.md-typeset .sig-inline .desctype>a.reference:hover,.md-typeset .sig-inline .desctypea.reference:hover,.md-typeset dl.api-field>dt .desctype>a.reference:hover,.md-typeset dl.api-field>dt .desctypea.reference:hover,.md-typeset dl.objdesc>dt .desctype>a.reference:hover,.md-typeset dl.objdesc>dt .desctypea.reference:hover{color:var(--md-accent-fg-color)}.md-typeset dl.objdesc>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family);padding-left:.5em;padding-right:.5em;padding-top:.5em}.md-typeset dl.objdesc>dt,.md-typeset dl.objdesc>dt code{font-size:.75rem}.md-typeset dl.objdesc>dt .property{color:var(--md-code-hl-keyword-color);font-style:normal;font-weight:700}.md-typeset dl.objdesc>dt .sig-prename{color:var(--md-code-hl-name-color);padding:0}.md-typeset dl.objdesc>dt .viewcode-back,.md-typeset dl.objdesc>dt .viewcode-link{float:right;text-align:right}.md-typeset dl.objdesc>dt.api-include-path,.md-typeset dl.objdesc>dt.api-include-path code{font-size:.65rem}.md-typeset dl.objdesc>dt:first-child{padding-top:.5em}.md-typeset dl.objdesc>dt:last-of-type{padding-bottom:.5em}.md-typeset dl.objdesc>dd dl.field-list>dt{font-size:1em;font-weight:700;margin-bottom:1em}.md-typeset dl.objdesc>dd dd.noindent{margin-left:0}.md-typeset dl.api-field>dt{display:table}.md-typeset dl.api-field>dt a.headerlink{left:.5em;margin-left:0;position:relative;width:0}.md-typeset dl.api-field>dt,.md-typeset dl.api-field>dt code{font-size:.65rem}.md-typeset dl.api-field>dt.api-parameter-kind{float:right;font-family:var(--md-text-font-family)}.md-typeset dl.api-field>dt.api-parameter-kind:before{content:"["}.md-typeset dl.api-field>dt.api-parameter-kind:after{content:"]"}.md-typeset dl.objdesc.summary>dd,.md-typeset dl.objdesc.summary>dd>p:first-child{margin-top:0}.md-typeset .sig-inline.c-texpr,.md-typeset .sig-inline.cpp-texpr{background-color:unset;font-family:unset}.md-nav__link{white-space:nowrap}:root>*{--objinfo-icon-fg-alias:#e65100;--objinfo-icon-fg-default:#424242;--objinfo-icon-fg-data:#1565c0;--objinfo-icon-fg-procedure:#6a1b9a;--objinfo-icon-fg-sub-data:#2e7d32;--objinfo-icon-bg-default:var(--md-default-bg-color)}@media screen{[data-md-color-scheme=slate]{--objinfo-icon-fg-alias:#ffb74d;--objinfo-icon-fg-default:#e0e0e0;--objinfo-icon-fg-data:#64b5f6;--objinfo-icon-fg-procedure:#ce93d8;--objinfo-icon-fg-sub-data:#81c784}}.objinfo-icon{background-color:var(--objinfo-icon-bg-default);border:1px solid var(--objinfo-icon-fg-default);border-radius:2px;color:var(--objinfo-icon-fg-default);display:inline-table;flex-shrink:0;font-family:var(--md-text-font-family);font-weight:500;height:16px;line-height:16px;margin-right:8px;text-align:center;vertical-align:middle;width:16px}.objinfo-icon__alias{background-color:var(--objinfo-icon-fg-alias);border:1px solid var(--objinfo-icon-fg-alias);color:var(--objinfo-icon-bg-default)}.objinfo-icon__procedure{background-color:var(--objinfo-icon-fg-procedure);border:1px solid var(--objinfo-icon-fg-procedure);color:var(--objinfo-icon-bg-default)}.objinfo-icon__data{background-color:var(--objinfo-icon-fg-data);border:1px solid var(--objinfo-icon-fg-data);color:var(--objinfo-icon-bg-default)}.objinfo-icon__sub-data{background-color:var(--objinfo-icon-fg-sub-data);border:1px solid var(--objinfo-icon-fg-sub-data);color:var(--objinfo-icon-bg-default)}.search-result-objlabel{border:1px solid var(--md-default-fg-color--light);border-radius:2px;float:right;padding:2px}table.longtable.docutils.data.align-default tbody>tr>td>p>a.reference.internal>code.xref.py.py-obj.docutils.literal.notranslate>span.pre{word-break:normal} +@media screen{[data-md-color-scheme=slate]{--md-default-fg-color:hsla(var(--md-hue),15%,90%,0.82);--md-default-fg-color--light:hsla(var(--md-hue),15%,90%,0.56);--md-default-fg-color--lighter:hsla(var(--md-hue),15%,90%,0.32);--md-default-fg-color--lightest:hsla(var(--md-hue),15%,90%,0.12);--md-default-bg-color:hsla(var(--md-hue),15%,14%,1);--md-default-bg-color--light:hsla(var(--md-hue),15%,14%,0.54);--md-default-bg-color--lighter:hsla(var(--md-hue),15%,14%,0.26);--md-default-bg-color--lightest:hsla(var(--md-hue),15%,14%,0.07);--md-code-fg-color:hsla(var(--md-hue),18%,86%,0.82);--md-code-bg-color:hsla(var(--md-hue),15%,18%,1);--md-code-hl-color:#2977ff;--md-code-hl-color--light:rgba(41,119,255,.1);--md-code-hl-number-color:#e6695b;--md-code-hl-special-color:#f06090;--md-code-hl-function-color:#c973d9;--md-code-hl-constant-color:#9383e2;--md-code-hl-keyword-color:#6791e0;--md-code-hl-string-color:#2fb170;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-kbd-color:hsla(var(--md-hue),15%,90%,0.12);--md-typeset-kbd-accent-color:hsla(var(--md-hue),15%,90%,0.2);--md-typeset-kbd-border-color:hsla(var(--md-hue),15%,14%,1);--md-typeset-mark-color:rgba(66,135,255,.3);--md-typeset-table-color:hsla(var(--md-hue),15%,95%,0.12);--md-typeset-table-color--light:hsla(var(--md-hue),15%,95%,0.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-bg-color:hsla(var(--md-hue),15%,10%,0.87);--md-footer-bg-color--dark:hsla(var(--md-hue),15%,8%,1);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.05),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.25),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.4),0 0 0.05rem rgba(0,0,0,.35);color-scheme:dark}[data-md-color-scheme=slate] img[src$="#gh-light-mode-only"],[data-md-color-scheme=slate] img[src$="#only-light"]{display:none}[data-md-color-scheme=slate][data-md-color-primary=pink]{--md-typeset-a-color:#ed5487}[data-md-color-scheme=slate][data-md-color-primary=purple]{--md-typeset-a-color:#c46fd3}[data-md-color-scheme=slate][data-md-color-primary=deep-purple]{--md-typeset-a-color:#a47bea}[data-md-color-scheme=slate][data-md-color-primary=indigo]{--md-typeset-a-color:#5488e8}[data-md-color-scheme=slate][data-md-color-primary=teal]{--md-typeset-a-color:#00ccb8}[data-md-color-scheme=slate][data-md-color-primary=green]{--md-typeset-a-color:#71c174}[data-md-color-scheme=slate][data-md-color-primary=deep-orange]{--md-typeset-a-color:#ff764d}[data-md-color-scheme=slate][data-md-color-primary=brown]{--md-typeset-a-color:#c1775c}[data-md-color-scheme=slate][data-md-color-primary=black],[data-md-color-scheme=slate][data-md-color-primary=blue-grey],[data-md-color-scheme=slate][data-md-color-primary=grey],[data-md-color-scheme=slate][data-md-color-primary=white]{--md-typeset-a-color:#5e8bde}[data-md-color-switching] *,[data-md-color-switching] :after,[data-md-color-switching] :before{transition-duration:0ms!important}}[data-md-color-accent=red]{--md-accent-fg-color:#ff1947;--md-accent-fg-color--transparent:rgba(255,25,71,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=pink]{--md-accent-fg-color:#f50056;--md-accent-fg-color--transparent:rgba(245,0,86,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=purple]{--md-accent-fg-color:#df41fb;--md-accent-fg-color--transparent:rgba(223,65,251,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=deep-purple]{--md-accent-fg-color:#7c4dff;--md-accent-fg-color--transparent:rgba(124,77,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=indigo]{--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=blue]{--md-accent-fg-color:#4287ff;--md-accent-fg-color--transparent:rgba(66,135,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-blue]{--md-accent-fg-color:#0091eb;--md-accent-fg-color--transparent:rgba(0,145,235,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=cyan]{--md-accent-fg-color:#00bad6;--md-accent-fg-color--transparent:rgba(0,186,214,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=teal]{--md-accent-fg-color:#00bda4;--md-accent-fg-color--transparent:rgba(0,189,164,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=green]{--md-accent-fg-color:#00c753;--md-accent-fg-color--transparent:rgba(0,199,83,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-green]{--md-accent-fg-color:#63de17;--md-accent-fg-color--transparent:rgba(99,222,23,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=lime]{--md-accent-fg-color:#b0eb00;--md-accent-fg-color--transparent:rgba(176,235,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=yellow]{--md-accent-fg-color:#ffd500;--md-accent-fg-color--transparent:rgba(255,213,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=amber]{--md-accent-fg-color:#fa0;--md-accent-fg-color--transparent:rgba(255,170,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=orange]{--md-accent-fg-color:#ff9100;--md-accent-fg-color--transparent:rgba(255,145,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=deep-orange]{--md-accent-fg-color:#ff6e42;--md-accent-fg-color--transparent:rgba(255,110,66,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=red]{--md-primary-fg-color:#ef5552;--md-primary-fg-color--light:#e57171;--md-primary-fg-color--dark:#e53734;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=pink]{--md-primary-fg-color:#e92063;--md-primary-fg-color--light:#ec417a;--md-primary-fg-color--dark:#c3185d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=purple]{--md-primary-fg-color:#ab47bd;--md-primary-fg-color--light:#bb69c9;--md-primary-fg-color--dark:#8c24a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=deep-purple]{--md-primary-fg-color:#7e56c2;--md-primary-fg-color--light:#9574cd;--md-primary-fg-color--dark:#673ab6;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=indigo]{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=blue]{--md-primary-fg-color:#2094f3;--md-primary-fg-color--light:#42a5f5;--md-primary-fg-color--dark:#1975d2;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-blue]{--md-primary-fg-color:#02a6f2;--md-primary-fg-color--light:#28b5f6;--md-primary-fg-color--dark:#0287cf;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=cyan]{--md-primary-fg-color:#00bdd6;--md-primary-fg-color--light:#25c5da;--md-primary-fg-color--dark:#0097a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=teal]{--md-primary-fg-color:#009485;--md-primary-fg-color--light:#26a699;--md-primary-fg-color--dark:#007a6c;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=green]{--md-primary-fg-color:#4cae4f;--md-primary-fg-color--light:#68bb6c;--md-primary-fg-color--dark:#398e3d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-green]{--md-primary-fg-color:#8bc34b;--md-primary-fg-color--light:#9ccc66;--md-primary-fg-color--dark:#689f38;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=lime]{--md-primary-fg-color:#cbdc38;--md-primary-fg-color--light:#d3e156;--md-primary-fg-color--dark:#b0b52c;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=yellow]{--md-primary-fg-color:#ffec3d;--md-primary-fg-color--light:#ffee57;--md-primary-fg-color--dark:#fbc02d;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=amber]{--md-primary-fg-color:#ffc105;--md-primary-fg-color--light:#ffc929;--md-primary-fg-color--dark:#ffa200;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=orange]{--md-primary-fg-color:#ffa724;--md-primary-fg-color--light:#ffa724;--md-primary-fg-color--dark:#fa8900;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=deep-orange]{--md-primary-fg-color:#ff6e42;--md-primary-fg-color--light:#ff8a66;--md-primary-fg-color--dark:#f4511f;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=brown]{--md-primary-fg-color:#795649;--md-primary-fg-color--light:#8d6e62;--md-primary-fg-color--dark:#5d4037;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=grey]{--md-primary-fg-color:#757575;--md-primary-fg-color--light:#9e9e9e;--md-primary-fg-color--dark:#616161;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=blue-grey]{--md-primary-fg-color:#546d78;--md-primary-fg-color--light:#607c8a;--md-primary-fg-color--dark:#455a63;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=light-green]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#72ad2e}[data-md-color-primary=lime]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#8b990a}[data-md-color-primary=yellow]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#b8a500}[data-md-color-primary=amber]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#d19d00}[data-md-color-primary=orange]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#e68a00}[data-md-color-primary=white]{--md-primary-fg-color:hsla(var(--md-hue),0%,100%,1);--md-primary-fg-color--light:hsla(var(--md-hue),0%,100%,0.7);--md-primary-fg-color--dark:hsla(var(--md-hue),0%,0%,0.07);--md-primary-bg-color:hsla(var(--md-hue),0%,0%,0.87);--md-primary-bg-color--light:hsla(var(--md-hue),0%,0%,0.54);--md-typeset-a-color:#4051b5}[data-md-color-primary=white] .md-button{color:var(--md-typeset-a-color)}[data-md-color-primary=white] .md-button--primary{background-color:var(--md-typeset-a-color);border-color:var(--md-typeset-a-color);color:hsla(var(--md-hue),0%,100%,1)}[data-md-color-primary=white] .md-hero--expand{border-bottom:.05rem solid rgba(0,0,0,.07)}@media screen and (max-width:76.234375em){[data-md-color-primary=white] .md-hero{border-bottom:.05rem solid rgba(0,0,0,.07)}}@media screen and (min-width:60em){[data-md-color-primary=white] .md-search__form{background-color:hsla(var(--md-hue),0%,0%,.07)}[data-md-color-primary=white] .md-search__form:hover{background-color:hsla(var(--md-hue),0%,0%,.32)}[data-md-color-primary=white] .md-search__input+.md-search__icon{color:hsla(var(--md-hue),0%,0%,.87)}}@media screen and (min-width:76.25em){[data-md-color-primary=white] .md-tabs{border-bottom:.05rem solid rgba(0,0,0,.07)}}[data-md-color-primary=black]{--md-primary-fg-color:hsla(var(--md-hue),15%,9%,1);--md-primary-fg-color--light:hsla(var(--md-hue),15%,9%,0.54);--md-primary-fg-color--dark:hsla(var(--md-hue),15%,9%,1);--md-primary-bg-color:hsla(var(--md-hue),15%,100%,1);--md-primary-bg-color--light:hsla(var(--md-hue),15%,100%,0.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=black] .md-button{color:var(--md-typeset-a-color)}[data-md-color-primary=black] .md-button--primary{background-color:var(--md-typeset-a-color);border-color:var(--md-typeset-a-color);color:hsla(var(--md-hue),0%,100%,1)}[data-md-color-primary=black] .md-header{background-color:hsla(var(--md-hue),15%,9%,1)}[data-md-color-primary=black] .md-hero{background-color:#000}@media screen and (max-width:59.984375em){[data-md-color-primary=black] .md-nav__source{background-color:hsla(var(--md-hue),15%,11%,.87)}}@media screen and (max-width:76.234375em){html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer]{background-color:hsla(var(--md-hue),15%,9%,1)}}@media screen and (min-width:76.25em){[data-md-color-primary=black] .md-tabs{background-color:hsla(var(--md-hue),15%,9%,1)}} +@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: normal;src: url(fonts/6d26fc8ce47383c3acc58ba2e9058844.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/2f45b23744b48cb8432ebce3a7785b15.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/a147e4366336588aae172d59e25deef1.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/6b76c51e06a497bee64b065b08ad96b8.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/79e33408703a4c71c3b985b963a5d516.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/b8b678e335cca488ceeab549e0ee7c43.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/e340d891a3edd4db23f95f759fe85e53.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/752686e9f1580c8dc3eef03805ffd49e.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/f6c56d7a605e19cba07493bde4326ca0.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;font-stretch: 100%;src: url(fonts/529667aea70b09ba8845845f8b791127.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: normal;src: url(fonts/826d42af215f1727ea4ef9055df04fc7.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/94333af3cbb89d3b83773d25618f1706.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/9faa7062eb32d692b0b5f69f0e42fe62.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/2fdf026badd63aad0ca82a950790c3ad.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/5c20fe772ae00739c191fcf5fc92d383.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/2a9ccbf9e2fc7ffc329cabcb326cac11.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/2e991b4c7e5e35481357bf270b4d10e3.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/d06d842a080c12b21bf6521a5d9dc79d.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/6ea4bf3cac225e29318cd2a18a4f9ffa.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;font-stretch: 100%;src: url(fonts/0204e961adca27dd4947c6df130dd96f.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: normal;src: url(fonts/73569e58a695276963fb8c3c1026376d.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/264c5b476ab42c43d6af4c257bb04477.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/85b7e87c4d7247aaf8824e30b4144465.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/80b21d8db6045c871d36ad4a2c985722.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/2f39871937f1093b0ff8429081c6ec7b.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/13a92d073c751034247a6d47e8134fdd.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/0f65443c2941435f9a90afb8921573f4.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/05ada379c350a1406544195bc7289117.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/c2018a1ed955d97c427d0f06f40d6050.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 200;font-stretch: 100%;src: url(fonts/8e67a526354c56c027c959a53b68147e.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: normal;src: url(fonts/af8b9493960aacd72b94c7567ab45c9e.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/b7cae3f403e6f573f0a7fed865887af4.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/a2d2c60ad40172211ff4782075414565.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/ca7f31435e0446821dcd43fc0e766e31.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/16ef93a23793ea9defec5f01265a3fdc.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/027cb81785975d282bd176dd05d6cd51.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/f8dc85e7e10f9eafb62db41ba60e19a3.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/51d978655b85a660b5ec352ab9eff784.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/31ce4972e0eedf25b993cb820d192cdf.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 200;font-stretch: 100%;src: url(fonts/c29bd9cd79bb0a8a71ce2962919e8b0d.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: normal;src: url(fonts/8c65ea83f430ace76d95c746dcc7d8dc.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/a94c81d0b3f6bb97fd97cfcfbfa5dcaf.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/ce4650b74cac95f6c9484a808c046790.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/b7f1713b565f769b0605291cc28102c0.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/e1a38cc8ff546d3df1459c89df87b8ea.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/ab0a020935184477d441bd13b3b9e642.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/3b6666c0da3a7fc7977e7ad30d57a213.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/b39a3761f41f9476dfd827446487cb79.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/a966ed9a844cd60b56d4e1b31b0051fe.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;font-stretch: 100%;src: url(fonts/2e43802a9d1556dbe360c22e2b85a597.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: normal;src: url(fonts/258446abf19534d57203b8e4b8a37c99.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/79003e6320341ae4b3dc73aafa30e2a6.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/df3312dfbf327224b9f2f9632c7ccd8c.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/17111913977f7ec5077bbdbc046fbc6a.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/92e018250353983874a958541296cfa6.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/f6ae49575b5a269d35d25f3c774bcc7f.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/1b1a774a3e0e9b725eaa711a2afb7392.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/b17158b92ca6f9303712a3378bfb5636.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/6ae8f8b730d4bfe372997d78612486ac.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;font-stretch: 100%;src: url(fonts/66b26b3c84c6a918a3c1d323b81184cf.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: normal;src: url(fonts/72205716fd182d68ae7159fc3cbc22f8.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/aae577798ff3f4e9e1d9640a97dea39a.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/fe56d0d137acb0f9b17754d3670f5eca.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/7635b26cac7923a2a94ad867d41afe4c.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/742a490470ad5add81a8614602f59609.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/a08aab97ea21fc5299645d12e3ef57bf.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/add79d702aef2d1f1cf4865df00911e0.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/beabfea8c7ef7693427c37f99ece071f.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/fdd953c288159a1f149911720d8a19fa.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;font-stretch: 100%;src: url(fonts/e44c11f4834bdd4d6b6da7b8ee5eaebc.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: normal;src: url(fonts/99214e5d9bc3ce84af84175a45f4ba0b.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/4e6d69d748044d096e9487d38ffb071c.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/a346eb01892d90d3150a27bcc3490add.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/96a6a4e9dd5d1505226c82c13d410deb.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/b7c212f5d900890107f648d1f28310a8.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/5f72bfaf9e281f741c41abe46dff3e1d.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/dcac443a527040572c077cb2b28ac8ca.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/e1c796916b3538c0a441a60a90f5520a.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/a712dd5fa12c7c09e52d44cfce499e33.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;font-stretch: 100%;src: url(fonts/cc7318e183292c701800a2c61d807c98.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: normal;src: url(fonts/59310440fd3e41969b9f1511a08d7cc5.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/a620860b63de9c40dac9a59b0094c61a.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/dcfb096c0a3b3089bfce4753d16eda3b.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/e38d3465f2c8bf67cc531b6a68484b01.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/f2b9287e870e65639bc34af8a226575b.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/219dddc355ee1f0ae550a97bae8a2531.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/21a4306e449be7b5403a98b97f9dd0f9.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/b5c6e34d471a72326c3151f6f89b70b3.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/ed5bf02d648da84d8d68e5e7a9261c19.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;font-stretch: 100%;src: url(fonts/e5b29c36b2e7a2f4db58307359fa5740.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: normal;src: url(fonts/77882429b96adeaa683dd0bcddff6e57.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/bbd1d1a14cde3b29e24f67475f7c0569.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/26646b9d877d16236aa3267f8231ca4c.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/e6f072bccf56c7a5885cad43b269048e.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/723cbd6f8aa09d478166cf4b328ec440.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/3e253f072fd8cb460de5e9daadfcc565.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/89bd2cbbc4b133be434990f66ea692cb.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/a84df1f533205686b83a3232b24efa87.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/026a36b060c2ef6c88ac125a50e8b4c9.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;font-stretch: 100%;src: url(fonts/6c29edce0214f7ce5c29596630dda4df.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: normal;src: url(fonts/61ade56110af07e1fb875b7b045dfad3.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/3eb393e3a3d57bfe84e0705f86a042da.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/e25d7629424c8d89c39bddb9b6a99b6f.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/d7ed3965fb236543ca714c28aa93846d.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/3774b4ecc75b5d7dbf2ec07da7fb53e4.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/6fea4c96d85aafe12ccfa3a7403b3fd4.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/ecb54ce0193aacd9bc7dbdb75eb9c824.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/079efa5d2641f256a97c9c802c168ef3.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/7426b8382b0c7ce632df53261dce20be.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 600;font-stretch: 100%;src: url(fonts/7608821ae7a01e76cb42e6fda12421e5.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: normal;src: url(fonts/c28df7ae5ed0937c97304fcbc60e61d2.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/2dc356092de7c114b1259e518a7f539a.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/70df311f920b9db2b2647692b885aed8.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/ef1fccbc8e3265cc39de4e7bab29fc77.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/d4577260f133e8b3d89369ab48596774.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/eee5f43c92cb9030d97f216bbb2ba34e.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/0fe4d8168abe6e917ef92b63a22ebccb.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/6b4464ee024fff1bd7a9f622659eaaea.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/f491d519ae3928214f725a9b27936bf9.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 600;font-stretch: 100%;src: url(fonts/5ae9b4b2ee6c8b3ded2d4008ccf058b7.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: normal;src: url(fonts/601e118215ded34377e51a2e84d014c9.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/7e0b492e21cac0154068c32b5c353d34.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/2b413a610bc96fdc0d550d28ff5c575e.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/88b7c5e61902ab86691356a44517e57e.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/47a2eb0e55070af53746643240dace61.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/ee85eaf88a859d80dedaa048b0e142f7.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/c4705b13de24588bbf5ac6c4d29db389.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/43d3927918baa5dafbbf682c2ab6cd51.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/8f1a4367b3d00ca55ea9b650136e690b.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;font-stretch: 100%;src: url(fonts/2bef6bc763635f137e6b49fc7d01d0d1.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: normal;src: url(fonts/a6883e4c27bb2b4d33116a6228bbc9ff.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/426ea34d21839226fe870b5d07da1c1c.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/1f39a390e50a9034847927b40b8fd1a1.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/4b92658fb886583bb0500a5e2fa672d1.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/8084f78186f127f1d12ba99276efe997.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/61f9fec22049e0ca94afdbf42e754714.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/4050a23ec5cf36be5af409d6af66246b.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/11ed281341a6dd16e758cb1e38e59f78.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/99f6d8a464743ae3c388b32ab525bf87.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;font-stretch: 100%;src: url(fonts/3bb26e5fa6a6c594d2e343a95693893b.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: normal;src: url(fonts/e4f3be7a1ed443693c97b52476b67b58.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/7ef81fadcc090047e1c258f05066207d.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/ebfaffa0ce7a84bf2216d03982a7a79b.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/cdec81ab55fb735870442a76524651c7.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/e43155115077f8ce42db882a6bed76a7.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/8a08f5c435eed0f2414b3eeb3ce8c217.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/c32d88b77c94ccea3e7a03e87fcbbad8.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/a4afb0badd14ab3594ee2ef01392b285.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/5eb5872bb169d41a79e46876e0441311.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 800;font-stretch: 100%;src: url(fonts/f07d0c93a3147897fad7ae0f6d52fba1.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: normal;src: url(fonts/94edfe2c34615cf4291ff718187862ea.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/550faacd31f18c0b9cfa0ab0825b94ed.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/c99a92c471d6f433b19fde75b2552e38.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/75d351ba4b7ae0ba4a2287ef48ae282b.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/d22c7353a102a9be9c67988ab7a16188.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/f200b88b158918b03884c3529a49f6c3.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/52672870c9b3b0e5d8e74c9fdd522491.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/28d2d42c2dc05f74362e21c4810e20cf.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/3937a4c765110f2cc43d71e4daccfc13.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 800;font-stretch: 100%;src: url(fonts/bef5ef5511a39f5f2a5ec4d20ad5bbf7.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: normal;src: url(fonts/83323e13092c5323935518bb1ed3654b.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/c3afdd3c83b6de20c3d9e87740770c9e.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/4caa7d82d0e5f6f127292f4f4c9af27a.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/7a5681247aa6fc3418022342557bf3e3.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/8638bf59a1e3ceb5b51df17bcf7bd7fc.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/98901a616b22ef6dbca6abebf3560b6b.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/e29a95b21321270ffb79543ee0cba17d.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/b5b98bb4e5069d0f063d919167ba6653.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/b965f477e38a00cafdcfba8553d17d35.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;font-stretch: 100%;src: url(fonts/0ef8a8fa25c458bcf4ac50a6dd593225.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: normal;src: url(fonts/11decf95fec8f66b914587f5c114f9c4.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/af09b935bb3d7e0f6541002b82baf166.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/e86101cc8a902668923f9cabfd607fdb.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/512757a4e09f30e718530112a3be087c.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/7a8bcfe0a68bb4832124e2e022554fa3.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/bd6bbdda9ebfa829f1b1314a929f1197.woff2) format('woff2');unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/96dbb7d9188b2e0703f002e68077f967.woff2) format('woff2');unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/542e2fd31336075667f486dbb0e086fd.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/40d9a7ba120fbde112edc76a0e9f27fc.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;font-stretch: 100%;src: url(fonts/e972943c8c50df41fca0fab199af6055.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/b078d17cfea0b0c47b499eeb79153746.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/5c032390bf8eb86dc4e7cbe575174e63.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/ce31a3d939f25087b2b8b08f6b386523.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/6c6a1c0a595735b92096a64feba801ab.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/a77dc0ac7d95f0f4254cc1a78f3c07db.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/ba534299c2b72e3b905f313cc81dd4fa.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/1a35ae0d4ce7da20107242fdfcfbff81.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/871d2e9fd0b24c64bb3bfba59560196a.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/7c632ba05b03720375e7caf795836efb.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/f67cbe19918d1ea33e927a2b83dfc964.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/422db4f94eb2639310cc49eb0c5232f7.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/fe89051f65780458ad298ceb78c1812a.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/442508ca6b49e1c39559e6e3cc7e2815.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/9f8dec9e15435e26b10359950ee22fed.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/6f93a718640e4084dd22b48e4c81d95a.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/a1fa19f89170d7580d17c2b8b8970ec4.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/117c76def7e509f636b6992214a3e006.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/8f3dd654717149daea27dad82c649a7a.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/868a11959e0c21a053df779c3cdeaad1.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/9a70a7678eae9689a2e903377e3c259e.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/4984943fb416d86430e08c11c95ea560.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/0feda7435983533516a4869176c31719.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/6bf499f36f403374a272b5adb80aefc3.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/ec52baba03c31dfa5c0d0bc6906ba425.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/e38070f61c248c215a19fee66f151635.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/84b502edbdb3fb25714c78ad3e33827c.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/f04ac67be64e2ad4a8e0900f60287d6c.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/2eccf6c0d5b3656754d3d21cf62213ce.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/682534463397d85ffd5965a4f70a947d.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/46097cf128244dfb1bd2419e3479dea0.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/5193a8c91a003cfe41866c6844be22d0.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/36ad3d233422da0692b766d17b2cf840.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/e3476a3f9c6b9343a3398c7b1d5c84eb.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/b11130c54c74efd6daafe68f038f84db.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/54dae5e8ef1a5aad1b61d8fd6d9cb6d0.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/917fc800a4cfb7ea65dac264d5a38eb6.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/13a019687fdb60cb1ff759f2aa5a09c9.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/fd2133ab2aba43ef040fad88322b695b.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/66cd4926f8b79b3df6d888564d4bddcc.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/c780beba9d1521f4930e8612ffb1535c.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/420106fda3528ff19100ff961bf017a5.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/7031e540f4a2dc07a28e6e9a9ee85359.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/4a91a3f5b5892a43e491b614d30e3132.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/de9d9d69c7140eb0ba951986b1181ff1.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/e3e9abf60b61dbf89160e8ad6cbc60ba.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/4b1c9b0ba29c3f32c0a04915792aeab9.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/90237ead9085efcdb757ba498a2d4646.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/3d1e72bf2f7f579e5680e87a492bf14f.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/e03013e0baa5690a803c188da2214d92.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/4d2765a0e0008da1d571566a55631207.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/04a4e747fa3f0133c028bd4d76ffcb4f.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/362193de66077cdecea259d864fb6a32.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/98ad4f585b76c4e883b39c991192a77c.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/237c47406e9e4a75786c423ab40d1a98.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/5deb0b03027599395fa49424334c383b.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/e4a744be99f104ecbd224af9a91da2a7.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/f5eae6b0ac5ed02f8d5a9a35a51f7c74.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/96ff010e106cae30b33bbc2f4b6c3f60.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/117fa76afb2f349d9d3e898f24eb5263.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/96246862b6453fb62d5ba6dcfa043c02.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/e6bae3f6087387a22a5897fef44189b7.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/f9943037d734ce0a3dca872da278a77c.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/ce7027efa5c894e8b244b0ca05ec121b.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/858fdc48287ed646b82bfdf31ce60e5b.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/3da92e22ed8b5a86d3cba6011ac25860.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/97bc75da499078ba9c8f0cee4ad2920a.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/465f2ba0417b6b16ef8718992301efd8.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/a3efd151d530b9353dbb771102f217a9.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/2ae735028a2bdd6e73c6aec996cf9ad9.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/6ae318fb48664db81936182f961e5c32.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/c5d0a8d5e21d71fe4aed01ef6c6e904a.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/ae4c0081383f95289e776a828f29831c.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/26d45c6882b664dbea7b47896d0c2bc8.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/8f0b23da93d60488a6162d1ebe93431b.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/f38f5947317e57e3c4cc20b55cf53710.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/d7c7c06d1be056d03709ceae2b003606.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/0ee2e6f8f9dcd2af7bc0c6b519c28395.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/4ac413e37db56eeeb4bb5cc1015ef5cb.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/b89ebf50f35195132ecff30f6fcf4b66.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/3128f62492065ac0b20b397b3c2eb517.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/04ae2fa764d886b85410579faccf3e3e.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/396a86833bb247070b487483b2ffee96.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/52d548b023a99019b1540895b1eeec9c.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/bc65abe41b621168458f550dd21f3e85.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/c71e1ed02ffd053fbc7f851cd79198f0.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/dbcb7acd17899c70335fc7724aefcec8.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/cdc3adef34f3d5d51ccbd1e93cee04e9.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/0bf080b4cbce22785a90a3b464e34dc4.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/00254b3347f6117a719cec84ec0a8d0b.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/8458ffb1652db9f2f466c228153373bd.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/283fbef73f42c21722c5a3efc7a44b0c.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/c0b55e2fa00cb3538e82dbb7d2f8dc66.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/e9a3e9f5f5250477366117d455632fb8.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/1f149703dd15543c6b006e681cdc6760.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/079db204eccfd1129698a5247c2e088b.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/a875ce2faf827acf96c74d348b861a09.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/5317ff42c10ad2360d9f9c7f4da5b439.woff2) format('woff2');unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/21eb25612d5c76e78c41bacf87adf6db.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;} +:root{--si-icon--octicons_eye-24:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_file-document-edit-outline:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_school:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_alert-circle:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_delete:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_close:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_alert-decagram:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_trash-can:url('data:image/svg+xml;charset=utf-8,');}.md-typeset .si-icon-inline.octicons_eye-24::before{-webkit-mask-image:var(--si-icon--octicons_eye-24);mask-image:var(--si-icon--octicons_eye-24);}.md-typeset .si-icon-inline.material_file-document-edit-outline::before{-webkit-mask-image:var(--si-icon--material_file-document-edit-outline);mask-image:var(--si-icon--material_file-document-edit-outline);}.md-typeset .si-icon-inline.material_school::before{-webkit-mask-image:var(--si-icon--material_school);mask-image:var(--si-icon--material_school);}.md-typeset .si-icon-inline.material_alert-circle::before{-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .si-icon-inline.material_delete::before{-webkit-mask-image:var(--si-icon--material_delete);mask-image:var(--si-icon--material_delete);}.md-typeset .si-icon-inline.material_close::before{-webkit-mask-image:var(--si-icon--material_close);mask-image:var(--si-icon--material_close);}.md-typeset .si-icon-inline.material_alert-decagram::before{-webkit-mask-image:var(--si-icon--material_alert-decagram);mask-image:var(--si-icon--material_alert-decagram);}.md-typeset .si-icon-inline.material_trash-can::before{-webkit-mask-image:var(--si-icon--material_trash-can);mask-image:var(--si-icon--material_trash-can);}.md-typeset .admonition.seealso{border-color:rgb(215,59,205);}.md-typeset .seealso>.admonition-title{background-color:rgba(215,59,205,0.1);border-color:rgb(215,59,205);}.md-typeset .seealso>.admonition-title::before{background-color:rgb(215,59,205);-webkit-mask-image:var(--si-icon--octicons_eye-24);mask-image:var(--si-icon--octicons_eye-24);}.md-typeset .note>.admonition-title::before{-webkit-mask-image:var(--si-icon--material_file-document-edit-outline);mask-image:var(--si-icon--material_file-document-edit-outline);}.md-typeset .hint>.admonition-title::before{-webkit-mask-image:var(--si-icon--material_school);mask-image:var(--si-icon--material_school);}.md-typeset .tip>.admonition-title::before{-webkit-mask-image:var(--si-icon--material_school);mask-image:var(--si-icon--material_school);}.md-typeset .important>.admonition-title::before{-webkit-mask-image:var(--si-icon--material_school);mask-image:var(--si-icon--material_school);}.md-typeset .admonition.versionadded{border-color:rgb(72,138,87);}.md-typeset .versionadded>.admonition-title{background-color:rgba(72,138,87,0.1);border-color:rgb(72,138,87);}.md-typeset .versionadded>.admonition-title::before{background-color:rgb(72,138,87);-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .admonition.versionchanged{border-color:rgb(238,144,64);}.md-typeset .versionchanged>.admonition-title{background-color:rgba(238,144,64,0.1);border-color:rgb(238,144,64);}.md-typeset .versionchanged>.admonition-title::before{background-color:rgb(238,144,64);-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .admonition.deprecated{border-color:rgb(203,70,83);}.md-typeset .deprecated>.admonition-title{background-color:rgba(203,70,83,0.1);border-color:rgb(203,70,83);}.md-typeset .deprecated>.admonition-title::before{background-color:rgb(203,70,83);-webkit-mask-image:var(--si-icon--material_delete);mask-image:var(--si-icon--material_delete);}.md-typeset .admonition.versionremoved{border-color:rgb(203,70,83);}.md-typeset .versionremoved>.admonition-title{background-color:rgba(203,70,83,0.1);border-color:rgb(203,70,83);}.md-typeset .versionremoved>.admonition-title::before{background-color:rgb(203,70,83);-webkit-mask-image:var(--si-icon--material_close);mask-image:var(--si-icon--material_close);}.md-status--new::after { mask-image: var(--si-icon--material_alert-decagram); -webkit-mask-image: var(--si-icon--material_alert-decagram);}.md-status--deprecated::after { mask-image: var(--si-icon--material_trash-can); -webkit-mask-image: var(--si-icon--material_trash-can);} diff --git a/_static/sphinx_immaterial_theme.32136f45f91ae6956.min.js b/_static/sphinx_immaterial_theme.32136f45f91ae6956.min.js new file mode 100644 index 00000000..9891f3f6 --- /dev/null +++ b/_static/sphinx_immaterial_theme.32136f45f91ae6956.min.js @@ -0,0 +1,14 @@ +"use strict";(()=>{var Ni=Object.create;var Er=Object.defineProperty;var Di=Object.getOwnPropertyDescriptor;var Wi=Object.getOwnPropertyNames,qt=Object.getOwnPropertySymbols,zi=Object.getPrototypeOf,wr=Object.prototype.hasOwnProperty,fo=Object.prototype.propertyIsEnumerable;var mo=(e,t,r)=>t in e?Er(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,I=(e,t)=>{for(var r in t||(t={}))wr.call(t,r)&&mo(e,r,t[r]);if(qt)for(var r of qt(t))fo.call(t,r)&&mo(e,r,t[r]);return e};var uo=(e,t)=>{var r={};for(var o in e)wr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&qt)for(var o of qt(e))t.indexOf(o)<0&&fo.call(e,o)&&(r[o]=e[o]);return r};var Tr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var qi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Wi(t))!wr.call(e,n)&&n!==r&&Er(e,n,{get:()=>t[n],enumerable:!(o=Di(t,n))||o.enumerable});return e};var vt=(e,t,r)=>(r=e!=null?Ni(zi(e)):{},qi(t||!e||!e.__esModule?Er(r,"default",{value:e,enumerable:!0}):r,e));var Ie=(e,t,r)=>new Promise((o,n)=>{var i=l=>{try{s(r.next(l))}catch(c){n(c)}},a=l=>{try{s(r.throw(l))}catch(c){n(c)}},s=l=>l.done?o(l.value):Promise.resolve(l.value).then(i,a);s((r=r.apply(e,t)).next())});var bo=Tr((Sr,ho)=>{(function(e,t){typeof Sr=="object"&&typeof ho!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Sr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(_){return!!(_&&_!==document&&_.nodeName!=="HTML"&&_.nodeName!=="BODY"&&"classList"in _&&"contains"in _.classList)}function l(_){var De=_.type,ke=_.tagName;return!!(ke==="INPUT"&&a[De]&&!_.readOnly||ke==="TEXTAREA"&&!_.readOnly||_.isContentEditable)}function c(_){_.classList.contains("focus-visible")||(_.classList.add("focus-visible"),_.setAttribute("data-focus-visible-added",""))}function p(_){_.hasAttribute("data-focus-visible-added")&&(_.classList.remove("focus-visible"),_.removeAttribute("data-focus-visible-added"))}function m(_){_.metaKey||_.altKey||_.ctrlKey||(s(r.activeElement)&&c(r.activeElement),o=!0)}function u(_){o=!1}function d(_){s(_.target)&&(o||l(_.target))&&c(_.target)}function h(_){s(_.target)&&(_.target.classList.contains("focus-visible")||_.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),p(_.target))}function b(_){document.visibilityState==="hidden"&&(n&&(o=!0),O())}function O(){document.addEventListener("mousemove",B),document.addEventListener("mousedown",B),document.addEventListener("mouseup",B),document.addEventListener("pointermove",B),document.addEventListener("pointerdown",B),document.addEventListener("pointerup",B),document.addEventListener("touchmove",B),document.addEventListener("touchstart",B),document.addEventListener("touchend",B)}function K(){document.removeEventListener("mousemove",B),document.removeEventListener("mousedown",B),document.removeEventListener("mouseup",B),document.removeEventListener("pointermove",B),document.removeEventListener("pointerdown",B),document.removeEventListener("pointerup",B),document.removeEventListener("touchmove",B),document.removeEventListener("touchstart",B),document.removeEventListener("touchend",B)}function B(_){_.target.nodeName&&_.target.nodeName.toLowerCase()==="html"||(o=!1,K())}document.addEventListener("keydown",m,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",b,!0),O(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var dr=Tr((vy,_n)=>{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var ka=/["'&<>]/;_n.exports=$a;function $a(e){var t=""+e,r=ka.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Vt=="object"&&typeof Qr=="object"?Qr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Vt=="object"?Vt.ClipboardJS=r():t.ClipboardJS=r()})(Vt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Vi}});var a=i(279),s=i.n(a),l=i(370),c=i.n(l),p=i(817),m=i.n(p);function u(N){try{return document.execCommand(N)}catch(A){return!1}}var d=function(A){var L=m()(A);return u("cut"),L},h=d;function b(N){var A=document.documentElement.getAttribute("dir")==="rtl",L=document.createElement("textarea");L.style.fontSize="12pt",L.style.border="0",L.style.padding="0",L.style.margin="0",L.style.position="absolute",L.style[A?"right":"left"]="-9999px";var U=window.pageYOffset||document.documentElement.scrollTop;return L.style.top="".concat(U,"px"),L.setAttribute("readonly",""),L.value=N,L}var O=function(A,L){var U=b(A);L.container.appendChild(U);var V=m()(U);return u("copy"),U.remove(),V},K=function(A){var L=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},U="";return typeof A=="string"?U=O(A,L):A instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(A==null?void 0:A.type)?U=O(A.value,L):(U=m()(A),u("copy")),U},B=K;function _(N){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?_=function(L){return typeof L}:_=function(L){return L&&typeof Symbol=="function"&&L.constructor===Symbol&&L!==Symbol.prototype?"symbol":typeof L},_(N)}var De=function(){var A=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},L=A.action,U=L===void 0?"copy":L,V=A.container,G=A.target,$e=A.text;if(U!=="copy"&&U!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(G!==void 0)if(G&&_(G)==="object"&&G.nodeType===1){if(U==="copy"&&G.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(U==="cut"&&(G.hasAttribute("readonly")||G.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if($e)return B($e,{container:V});if(G)return U==="cut"?h(G):B(G,{container:V})},ke=De;function Ce(N){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Ce=function(L){return typeof L}:Ce=function(L){return L&&typeof Symbol=="function"&&L.constructor===Symbol&&L!==Symbol.prototype?"symbol":typeof L},Ce(N)}function Dt(N,A){if(!(N instanceof A))throw new TypeError("Cannot call a class as a function")}function bt(N,A){for(var L=0;L0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=Ce(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var G=this;this.listener=c()(V,"click",function($e){return G.onClick($e)})}},{key:"onClick",value:function(V){var G=V.delegateTarget||V.currentTarget,$e=this.action(G)||"copy",zt=ke({action:$e,container:this.container,target:this.target(G),text:this.text(G)});this.emit(zt?"success":"error",{action:$e,text:zt,trigger:G,clearSelection:function(){G&&G.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return xr("action",V)}},{key:"defaultTarget",value:function(V){var G=xr("target",V);if(G)return document.querySelector(G)}},{key:"defaultText",value:function(V){return xr("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return B(V,G)}},{key:"cut",value:function(V){return h(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],G=typeof V=="string"?[V]:V,$e=!!document.queryCommandSupported;return G.forEach(function(zt){$e=$e&&!!document.queryCommandSupported(zt)}),$e}}]),L}(s()),Vi=Ui},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,l){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(l))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(p,m,u,d,h){var b=c.apply(this,arguments);return p.addEventListener(u,b,h),{destroy:function(){p.removeEventListener(u,b,h)}}}function l(p,m,u,d,h){return typeof p.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof p=="string"&&(p=document.querySelectorAll(p)),Array.prototype.map.call(p,function(b){return s(b,m,u,d,h)}))}function c(p,m,u,d){return function(h){h.delegateTarget=a(h.target,m),h.delegateTarget&&d.call(p,h)}}o.exports=l},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function l(u,d,h){if(!u&&!d&&!h)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(u))return c(u,d,h);if(a.nodeList(u))return p(u,d,h);if(a.string(u))return m(u,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(u,d,h){return u.addEventListener(d,h),{destroy:function(){u.removeEventListener(d,h)}}}function p(u,d,h){return Array.prototype.forEach.call(u,function(b){b.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(u,function(b){b.removeEventListener(d,h)})}}}function m(u,d,h){return s(document.body,u,d,h)}o.exports=l},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var l=window.getSelection(),c=document.createRange();c.selectNodeContents(i),l.removeAllRanges(),l.addRange(c),a=l.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var l=this.e||(this.e={});return(l[i]||(l[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var l=this;function c(){l.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),l=0,c=s.length;for(l;l0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function Y(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],a;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(s){a={error:s}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(a)throw a.error}}return i}function Q(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||l(d,b)})},h&&(n[d]=h(n[d])))}function l(d,h){try{c(o[d](h))}catch(b){u(i[0][3],b)}}function c(d){d.value instanceof it?Promise.resolve(d.value.v).then(p,m):u(i[0][2],d)}function p(d){l("next",d)}function m(d){l("throw",d)}function u(d,h){d(h),i.shift(),i.length&&l(i[0][0],i[0][1])}}function yo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof be=="function"?be(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(a){return new Promise(function(s,l){a=e[i](a),n(s,l,a.done,a.value)})}}function n(i,a,s,l){Promise.resolve(l).then(function(c){i({value:c,done:s})},a)}}function k(e){return typeof e=="function"}function gt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Bt=gt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function We(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var je=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=be(a),l=s.next();!l.done;l=s.next()){var c=l.value;c.remove(this)}}catch(b){t={error:b}}finally{try{l&&!l.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var p=this.initialTeardown;if(k(p))try{p()}catch(b){i=b instanceof Bt?b.errors:[b]}var m=this._finalizers;if(m){this._finalizers=null;try{for(var u=be(m),d=u.next();!d.done;d=u.next()){var h=d.value;try{xo(h)}catch(b){i=i!=null?i:[],b instanceof Bt?i=Q(Q([],Y(i)),Y(b.errors)):i.push(b)}}}catch(b){o={error:b}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Bt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)xo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&We(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&We(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Lr=je.EMPTY;function Yt(e){return e instanceof je||e&&"closed"in e&&k(e.remove)&&k(e.add)&&k(e.unsubscribe)}function xo(e){k(e)?e():e.unsubscribe()}var Pe={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var yt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,a=n.isStopped,s=n.observers;return i||a?Lr:(this.currentObservers=null,s.push(r),new je(function(){o.currentObservers=null,We(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,o){return new _o(r,o)},t}(F);var _o=function(e){re(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Lr},t}(E);var Hr=function(e){re(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(E);var kt={now:function(){return(kt.delegate||Date).now()},delegate:void 0};var $t=function(e){re(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=kt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,l=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+l)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),l=0;l0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(Tt);var Ho=function(e){re(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(St);var Pr=new Ho(Co);var ko=function(e){re(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=wt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var a=r.actions;o!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==o&&(wt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(Tt);var $o=function(e){re(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(St);var ce=new $o(ko);var M=new F(function(e){return e.complete()});function Qt(e){return e&&k(e.schedule)}function Rr(e){return e[e.length-1]}function Ze(e){return k(Rr(e))?e.pop():void 0}function He(e){return Qt(Rr(e))?e.pop():void 0}function Xt(e,t){return typeof Rr(e)=="number"?e.pop():t}var Ot=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Zt(e){return k(e==null?void 0:e.then)}function er(e){return k(e[Et])}function tr(e){return Symbol.asyncIterator&&k(e==null?void 0:e[Symbol.asyncIterator])}function rr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ea(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var or=ea();function nr(e){return k(e==null?void 0:e[or])}function ir(e){return go(this,arguments,function(){var r,o,n,i;return Kt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,it(r.read())];case 3:return o=a.sent(),n=o.value,i=o.done,i?[4,it(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,it(n)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function ar(e){return k(e==null?void 0:e.getReader)}function D(e){if(e instanceof F)return e;if(e!=null){if(er(e))return ta(e);if(Ot(e))return ra(e);if(Zt(e))return oa(e);if(tr(e))return Po(e);if(nr(e))return na(e);if(ar(e))return ia(e)}throw rr(e)}function ta(e){return new F(function(t){var r=e[Et]();if(k(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ra(e){return new F(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?y(function(n,i){return e(n,i,o)}):le,Te(1),r?Ue(t):Qo(function(){return new Lt}))}}function Wr(e){return e<=0?function(){return M}:w(function(t,r){var o=[];t.subscribe(T(r,function(n){o.push(n),e=2,!0))}function ue(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new E}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,l=s===void 0?!0:s;return function(c){var p,m,u,d=0,h=!1,b=!1,O=function(){m==null||m.unsubscribe(),m=void 0},K=function(){O(),p=u=void 0,h=b=!1},B=function(){var _=p;K(),_==null||_.unsubscribe()};return w(function(_,De){d++,!b&&!h&&O();var ke=u=u!=null?u:r();De.add(function(){d--,d===0&&!b&&!h&&(m=qr(B,l))}),ke.subscribe(De),!p&&d>0&&(p=new ze({next:function(Ce){return ke.next(Ce)},error:function(Ce){b=!0,O(),m=qr(K,n,Ce),ke.error(Ce)},complete:function(){h=!0,O(),m=qr(K,a),ke.complete()}}),D(_).subscribe(p))})(c)}}function qr(e,t){for(var r=[],o=2;oe.next(document)),e}function P(e,t=document){return Array.from(t.querySelectorAll(e))}function R(e,t=document){let r=de(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function de(e,t=document){return t.querySelector(e)||void 0}function Re(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var Ta=$(v(document.body,"focusin"),v(document.body,"focusout")).pipe(_e(1),q(void 0),f(()=>Re()||document.body),ee(1));function tt(e){return Ta.pipe(f(t=>e.contains(t)),X())}function It(e,t){return C(()=>$(v(e,"mouseenter").pipe(f(()=>!0)),v(e,"mouseleave").pipe(f(()=>!1))).pipe(t?lt(r=>ve(+!r*t)):le,q(e.matches(":hover"))))}function tn(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)tn(e,r)}function g(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)tn(o,n);return o}function lr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function pr(e){let t=g("script",{src:e});return C(()=>(document.head.appendChild(t),$(v(t,"load"),v(t,"error").pipe(x(()=>Ir(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(f(()=>{}),H(()=>document.head.removeChild(t)),Te(1))))}var rn=new E,Sa=C(()=>typeof ResizeObserver=="undefined"?pr("https://unpkg.com/resize-observer-polyfill"):j(void 0)).pipe(f(()=>new ResizeObserver(e=>e.forEach(t=>rn.next(t)))),x(e=>$(st,j(e)).pipe(H(()=>e.disconnect()))),ee(1));function pe(e){return{width:e.offsetWidth,height:e.offsetHeight}}function he(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return Sa.pipe(S(r=>r.observe(t)),x(r=>rn.pipe(y(o=>o.target===t),H(()=>r.unobserve(t)))),f(()=>pe(e)),q(pe(e)))}function jt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function on(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function nn(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Ve(e){return{x:e.offsetLeft,y:e.offsetTop}}function an(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function sn(e){return $(v(window,"load"),v(window,"resize")).pipe(Me(0,ce),f(()=>Ve(e)),q(Ve(e)))}function mr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Je(e){return $(v(e,"scroll"),v(window,"scroll"),v(window,"resize")).pipe(Me(0,ce),f(()=>mr(e)),q(mr(e)))}var cn=new E,Oa=C(()=>j(new IntersectionObserver(e=>{for(let t of e)cn.next(t)},{threshold:0}))).pipe(x(e=>$(st,j(e)).pipe(H(()=>e.disconnect()))),ee(1));function rt(e){return Oa.pipe(S(t=>t.observe(e)),x(t=>cn.pipe(y(({target:r})=>r===e),H(()=>t.unobserve(e)),f(({isIntersecting:r})=>r))))}var fr={drawer:R("[data-md-toggle=drawer]"),search:R("[data-md-toggle=search]")};function ln(e){return fr[e].checked}function Ge(e,t){fr[e].checked!==t&&fr[e].click()}function ot(e){let t=fr[e];return v(t,"change").pipe(f(()=>t.checked),q(t.checked))}function La(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ma(){return $(v(window,"compositionstart").pipe(f(()=>!0)),v(window,"compositionend").pipe(f(()=>!1))).pipe(q(!1))}function pn(){let e=v(window,"keydown").pipe(y(t=>!(t.metaKey||t.ctrlKey)),f(t=>({mode:ln("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),y(({mode:t,type:r})=>{if(t==="global"){let o=Re();if(typeof o!="undefined")return!La(o,r)}return!0}),ue());return Ma().pipe(x(t=>t?M:e))}function ge(){return new URL(location.href)}function ut(e,t=!1){if(J("navigation.instant")&&!t){let r=g("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function mn(){return new E}function fn(){return location.hash.slice(1)}function un(e){let t=g("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function _a(e){return $(v(window,"hashchange"),e).pipe(f(fn),q(fn()),y(t=>t.length>0),ee(1))}function dn(e){return _a(e).pipe(f(t=>de(`[id="${t}"]`)),y(t=>typeof t!="undefined"))}function Ft(e){let t=matchMedia(e);return cr(r=>t.addListener(()=>r(t.matches))).pipe(q(t.matches))}function hn(){let e=matchMedia("print");return $(v(window,"beforeprint").pipe(f(()=>!0)),v(window,"afterprint").pipe(f(()=>!1))).pipe(q(e.matches))}function Br(e,t){return e.pipe(x(r=>r?t():M))}function Yr(e,t){return new F(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let a=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+a*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function Qe(e,t){return Yr(e,t).pipe(x(r=>r.text()),f(r=>JSON.parse(r)),ee(1))}function bn(e,t){let r=new DOMParser;return Yr(e,t).pipe(x(o=>o.text()),f(o=>r.parseFromString(o,"text/html")),ee(1))}function vn(e,t){let r=new DOMParser;return Yr(e,t).pipe(x(o=>o.text()),f(o=>r.parseFromString(o,"text/xml")),ee(1))}function gn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function yn(){return $(v(window,"scroll",{passive:!0}),v(window,"resize",{passive:!0})).pipe(f(gn),q(gn()))}function xn(){return{width:innerWidth,height:innerHeight}}function En(){return v(window,"resize",{passive:!0}).pipe(f(xn),q(xn()))}function wn(){return W([yn(),En()]).pipe(f(([e,t])=>({offset:e,size:t})),ee(1))}function ur(e,{viewport$:t,header$:r}){let o=t.pipe(Z("size")),n=W([o,r]).pipe(f(()=>Ve(e)));return W([r,t,n]).pipe(f(([{height:i},{offset:a,size:s},{x:l,y:c}])=>({offset:{x:a.x-l,y:a.y-c+i},size:s})))}var Aa=R("#__config"),At=JSON.parse(Aa.textContent);At.base=`${new URL(At.base,ge())}`;function me(){return At}function J(e){return At.features.includes(e)}function ye(e,t){return typeof t!="undefined"?At.translations[e].replace("#",t.toString()):At.translations[e]}function Se(e,t=document){return R(`[data-md-component=${e}]`,t)}function ae(e,t=document){return P(`[data-md-component=${e}]`,t)}function Ca(e){let t=R(".md-typeset > :first-child",e);return v(t,"click",{once:!0}).pipe(f(()=>R(".md-typeset",e)),f(r=>({hash:__md_hash(r.innerHTML)})))}function Tn(e){if(!J("announce.dismiss")||!e.childElementCount)return M;if(!e.hidden){let t=R(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return C(()=>{let t=new E;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Ca(e).pipe(S(r=>t.next(r)),H(()=>t.complete()),f(r=>I({ref:e},r)))})}function Ha(e,{target$:t}){return t.pipe(f(r=>({hidden:r!==e})))}function Sn(e,t){let r=new E;return r.subscribe(({hidden:o})=>{e.hidden=o}),Ha(e,t).pipe(S(o=>r.next(o)),H(()=>r.complete()),f(o=>I({ref:e},o)))}function Ut(e,t){return t==="inline"?g("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},g("div",{class:"md-tooltip__inner md-typeset"})):g("div",{class:"md-tooltip",id:e,role:"tooltip"},g("div",{class:"md-tooltip__inner md-typeset"}))}function On(...e){return g("div",{class:"md-tooltip2",role:"tooltip"},g("div",{class:"md-tooltip2__inner md-typeset"},e))}function Ln(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return g("aside",{class:"md-annotation",tabIndex:0},Ut(t),g("a",{href:r,class:"md-annotation__index",tabIndex:-1},g("span",{"data-md-annotation-id":e})))}else return g("aside",{class:"md-annotation",tabIndex:0},Ut(t),g("span",{class:"md-annotation__index",tabIndex:-1},g("span",{"data-md-annotation-id":e})))}function Mn(e){return g("button",{class:"md-clipboard md-icon",title:ye("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var An=vt(dr());function Jr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(l=>!e.terms[l]).reduce((l,c)=>[...l,g("del",null,(0,An.default)(c))," "],[]).slice(0,-1),i=me(),a=new URL(e.location,i.base);J("search.highlight")&&a.searchParams.set("h",Object.entries(e.terms).filter(([,l])=>l).reduce((l,[c])=>`${l} ${c}`.trim(),""));let{tags:s}=me();return g("a",{href:`${a}`,class:"md-search-result__link",tabIndex:-1},g("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&g("div",{class:"md-search-result__icon md-icon"}),r>0&&g("h1",null,e.title),r<=0&&g("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&g("nav",{class:"md-tags"},e.tags.map(l=>{let c=s?l in s?`md-tag-icon md-tag--${s[l]}`:"md-tag-icon":"";return g("span",{class:`md-tag ${c}`},l)})),o>0&&n.length>0&&g("p",{class:"md-search-result__terms"},ye("search.result.term.missing"),": ",...n)))}function Cn(e){let t=e[0].score,r=[...e],o=me(),n=r.findIndex(p=>!`${new URL(p.location,o.base)}`.includes("#")),[i]=r.splice(n,1),a=r.findIndex(p=>p.scoreJr(p,1)),...l.length?[g("details",{class:"md-search-result__more"},g("summary",{tabIndex:-1},g("div",null,l.length>0&&l.length===1?ye("search.result.more.one"):ye("search.result.more.other",l.length))),...l.map(p=>Jr(p,1)))]:[]];return g("li",{class:"md-search-result__item"},c)}function Hn(e){return g("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>g("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?lr(r):r)))}function Gr(e){let t=`tabbed-control tabbed-control--${e}`;return g("div",{class:t,hidden:!0},g("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function kn(e){return g("div",{class:"md-typeset__scrollwrap"},g("div",{class:"md-typeset__table"},e))}function Pa(e){var o;let t=me(),r=new URL(`${e.version}/`,new URL("../",t.base));return g("li",{class:"md-version__item"},g("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&g("span",{class:"md-version__alias"},e.aliases[0])))}function $n(e,t){var o;let r=me();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),g("div",{class:"md-version"},g("button",{class:"md-version__current","aria-label":ye("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&g("span",{class:"md-version__alias"},t.aliases[0])),g("ul",{class:"md-version__list"},e.map(Pa)))}var Ra=0;function Ia(e){let t=W([tt(e),It(e)]).pipe(f(([o,n])=>o||n),X()),r=C(()=>nn(e)).pipe(te(Je),ft(1),Ke(t),f(()=>an(e)));return t.pipe(pt(o=>o),x(()=>W([t,r])),f(([o,n])=>({active:o,offset:n})),ue())}function ja(e,t){let{content$:r,viewport$:o}=t,n=`__tooltip2_${Ra++}`;return C(()=>{let i=new E,a=new Hr(!1);i.pipe(oe(),ne(!1)).subscribe(a);let s=a.pipe(lt(c=>ve(+!c*250,Pr)),X(),x(c=>c?r:M),S(c=>c.id=n),ue());W([i.pipe(f(({active:c})=>c)),s.pipe(x(c=>It(c,250)),q(!1))]).pipe(f(c=>c.some(p=>p))).subscribe(a);let l=a.pipe(y(c=>c),ie(s,o),f(([c,p,{size:m}])=>{let u=e.getBoundingClientRect(),d=u.width/2;if(p.role==="tooltip")return{x:d,y:8+u.height};if(u.y>=m.height/2){let{height:h}=pe(p);return{x:d,y:-16-h}}else return{x:d,y:16+u.height}}));return W([s,i,l]).subscribe(([c,{offset:p},m])=>{c.style.setProperty("--md-tooltip-host-x",`${p.x}px`),c.style.setProperty("--md-tooltip-host-y",`${p.y}px`),c.style.setProperty("--md-tooltip-x",`${m.x}px`),c.style.setProperty("--md-tooltip-y",`${m.y}px`),c.classList.toggle("md-tooltip2--top",m.y<0),c.classList.toggle("md-tooltip2--bottom",m.y>=0)}),a.pipe(y(c=>c),ie(s,(c,p)=>p),y(c=>c.role==="tooltip")).subscribe(c=>{let p=pe(R(":scope > *",c));c.style.setProperty("--md-tooltip-width",`${p.width}px`),c.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(X(),Le(ce),ie(s)).subscribe(([c,p])=>{p.classList.toggle("md-tooltip2--active",c)}),W([a.pipe(y(c=>c)),s]).subscribe(([c,p])=>{p.role==="dialog"?(e.setAttribute("aria-controls",n),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",n)}),a.pipe(y(c=>!c)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),Ia(e).pipe(S(c=>i.next(c)),H(()=>i.complete()),f(c=>I({ref:e},c)))})}function dt(e,{viewport$:t},r=document.body){return ja(e,{content$:new F(o=>{let n=e.title,i=On(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t})}function Fa(e,t){let r=C(()=>W([sn(e),Je(t)])).pipe(f(([{x:o,y:n},i])=>{let{width:a,height:s}=pe(e);return{x:o-i.x+a/2,y:n-i.y+s/2}}));return tt(e).pipe(x(o=>r.pipe(f(n=>({active:o,offset:n})),Te(+!o||1/0))))}function Pn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return C(()=>{let i=new E,a=i.pipe(oe(),ne(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),rt(e).pipe(z(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),$(i.pipe(y(({active:s})=>s)),i.pipe(_e(250),y(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Me(16,ce)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(ft(125,ce),y(()=>!!e.offsetParent),f(()=>e.offsetParent.getBoundingClientRect()),f(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),v(n,"click").pipe(z(a),y(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),v(n,"mousedown").pipe(z(a),ie(i)).subscribe(([s,{active:l}])=>{var c;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(l){s.preventDefault();let p=e.parentElement.closest(".md-annotation");p instanceof HTMLElement?p.focus():(c=Re())==null||c.blur()}}),r.pipe(z(a),y(s=>s===o),Be(125)).subscribe(()=>e.focus()),Fa(e,t).pipe(S(s=>i.next(s)),H(()=>i.complete()),f(s=>I({ref:e},s)))})}function Ua(e){return e.tagName==="CODE"?P(".c, .c1, .cm",e):[e]}function Va(e){let t=[];for(let r of Ua(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,l]=a;if(typeof l=="undefined"){let c=i.splitText(a.index);i=c.splitText(s.length),t.push(c)}else{i.textContent=s,t.push(i);break}}}}return t}function Rn(e,t){t.append(...Array.from(e.childNodes))}function hr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,a=new Map;for(let s of Va(t)){let[,l]=s.textContent.match(/\((\d+)\)/);de(`:scope > li:nth-child(${l})`,e)&&(a.set(l,Ln(l,i)),s.replaceWith(a.get(l)))}return a.size===0?M:C(()=>{let s=new E,l=s.pipe(oe(),ne(!0)),c=[];for(let[p,m]of a)c.push([R(".md-typeset",m),R(`:scope > li:nth-child(${p})`,e)]);return o.pipe(z(l)).subscribe(p=>{e.hidden=!p,e.classList.toggle("md-annotation-list",p);for(let[m,u]of c)p?Rn(m,u):Rn(u,m)}),$(...[...a].map(([,p])=>Pn(p,t,{target$:r}))).pipe(H(()=>s.complete()),ue())})}function In(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return In(t)}}function jn(e,t){return C(()=>{let r=In(e);return typeof r!="undefined"?hr(r,e,t):M})}var Fn=vt(Xr());var Na=0;function Un(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Un(t)}}function Da(e){return he(e).pipe(f(({width:t})=>({scrollable:jt(e).width>t})),Z("scrollable"))}function Vn(e,t){let{matches:r}=matchMedia("(hover)"),o=C(()=>{let n=new E,i=n.pipe(Wr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[];if(Fn.default.isSupported()&&(e.closest(".copy")||J("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Na++}`;let p=Mn(c.id);c.insertBefore(p,e),J("content.tooltips")&&a.push(dt(p,{viewport$}))}let s=e.closest(".highlight");if(s instanceof HTMLElement){let c=Un(s);if(typeof c!="undefined"&&(s.classList.contains("annotate")||J("content.code.annotate"))){let p=hr(c,e,t);a.push(he(s).pipe(z(i),f(({width:m,height:u})=>m&&u),X(),x(m=>m?p:M)))}}return P(":scope > span[id]",e).length&&e.classList.add("md-code__content"),Da(e).pipe(S(c=>n.next(c)),H(()=>n.complete()),f(c=>I({ref:e},c)),Ye(...a))});return J("content.lazy")?rt(e).pipe(y(n=>n),Te(1),x(()=>o)):o}function Wa(e,{target$:t,print$:r}){let o=!0;return $(t.pipe(f(n=>n.closest("details:not([open])")),y(n=>e===n),f(()=>({action:"open",reveal:!0}))),r.pipe(y(n=>n||!o),S(()=>o=e.open),f(n=>({action:n?"open":"close"}))))}function Nn(e,t){return C(()=>{let r=new E;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Wa(e,t).pipe(S(o=>r.next(o)),H(()=>r.complete()),f(o=>I({ref:e},o)))})}var Dn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:transparent}.flowchartTitleText{fill:var(--md-mermaid-label-fg-color)}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}.classDiagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs marker.marker.composition.class path,defs marker.marker.dependency.class path,defs marker.marker.extension.class path{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs marker.marker.aggregation.class path{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}.statediagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.entityTitleText{fill:var(--md-mermaid-label-fg-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}text:not([class]):last-child{fill:var(--md-mermaid-label-fg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Zr,qa=0,Ka=me();function Ba(){return typeof mermaid=="undefined"||mermaid instanceof Element?pr(`${Ka.base}_static/mermaid/mermaid.min.js`):j(void 0)}function Wn(e){return e.classList.remove("mermaid"),Zr||(Zr=Ba().pipe(S(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Dn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),f(()=>{}),ee(1))),Zr.subscribe(()=>Ie(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${qa++}`,r=g("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),a=r.attachShadow({mode:"closed"});a.innerHTML=n,e.replaceWith(r),i==null||i(a)})),Zr.pipe(f(()=>({ref:e})))}var zn=g("table");function qn(e){return e.replaceWith(zn),zn.replaceWith(kn(e)),j({ref:e})}function Ya(e){let t=e.find(r=>r.checked)||e[0];return $(...e.map(r=>v(r,"change").pipe(f(()=>R(`label[for="${r.id}"]`))))).pipe(q(R(`label[for="${t.id}"]`)),f(r=>({active:r})))}function Kn(e,{viewport$:t,target$:r}){let o=R(".tabbed-labels",e),n=P(":scope > input",e),i=Gr("prev");e.append(i);let a=Gr("next");return e.append(a),C(()=>{let s=new E,l=s.pipe(oe(),ne(!0));W([s,he(e),rt(e)]).pipe(z(l),Me(1,ce)).subscribe({next([{active:c},p]){let m=Ve(c),{width:u}=pe(c);e.style.setProperty("--md-indicator-x",`${m.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=mr(o);(m.xd.x+p.width)&&o.scrollTo({left:Math.max(0,m.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),W([Je(o),he(o)]).pipe(z(l)).subscribe(([c,p])=>{let m=jt(o);i.hidden=c.x<16,a.hidden=c.x>m.width-p.width-16}),$(v(i,"click").pipe(f(()=>-1)),v(a,"click").pipe(f(()=>1))).pipe(z(l)).subscribe(c=>{let{width:p}=pe(o);o.scrollBy({left:p*c,behavior:"smooth"})}),r.pipe(z(l),y(c=>n.includes(c))).subscribe(c=>c.click()),o.classList.add("tabbed-labels--linked");for(let c of n){let p=R(`label[for="${c.id}"]`);p.replaceChildren(g("a",{href:`#${p.htmlFor}`,tabIndex:-1},...Array.from(p.childNodes))),v(p.firstElementChild,"click").pipe(z(l),y(m=>!(m.metaKey||m.ctrlKey)),S(m=>{m.preventDefault(),m.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${p.htmlFor}`),p.click()})}return J("content.tabs.link")&&s.pipe(Ae(1),ie(t)).subscribe(([{active:c},{offset:p}])=>{let m=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-p.y;for(let h of P("[data-tabs]"))for(let b of P(":scope > input",h)){let O=R(`label[for="${b.id}"]`);if(O!==c&&O.innerText.trim()===m){O.setAttribute("data-md-switching",""),b.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([m,...d])])}}),s.pipe(z(l)).subscribe(()=>{for(let c of P("audio, video",e))c.pause()}),Ya(n).pipe(S(c=>s.next(c)),H(()=>s.complete()),f(c=>I({ref:e},c)))}).pipe(qe(se))}function Bn(e,{viewport$:t,target$:r,print$:o}){return $(...P(".annotate:not(.highlight)",e).map(n=>jn(n,{target$:r,print$:o})),...P("pre:not(.mermaid) > code",e).map(n=>Vn(n,{target$:r,print$:o})),...P("pre.mermaid",e).map(n=>Wn(n)),...P("table:not([class])",e).map(n=>qn(n)),...P("details",e).map(n=>Nn(n,{target$:r,print$:o})),...P("[data-tabs]",e).map(n=>Kn(n,{viewport$:t,target$:r})),...P("[title]",e).filter(()=>J("content.tooltips")).map(n=>dt(n,{viewport$:t})))}function Ja(e,{alert$:t}){return t.pipe(x(r=>$(j(!0),j(!1).pipe(Be(2e3))).pipe(f(o=>({message:r,active:o})))))}function Yn(e,t){let r=R(".md-typeset",e);return C(()=>{let o=new E;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ja(e,t).pipe(S(n=>o.next(n)),H(()=>o.complete()),f(n=>I({ref:e},n)))})}var Ga=0;function Qa(e,t){document.body.append(e);let{width:r}=pe(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=on(t),n=typeof o!="undefined"?Je(o):j({x:0,y:0}),i=$(tt(t),It(t)).pipe(X());return W([i,n]).pipe(f(([a,s])=>{let{x:l,y:c}=Ve(t),p=pe(t),m=t.closest("table");return m&&t.parentElement&&(l+=m.offsetLeft+t.parentElement.offsetLeft,c+=m.offsetTop+t.parentElement.offsetTop),{active:a,offset:{x:l-s.x+p.width/2-r/2,y:c-s.y+p.height+8}}}))}function Jn(e){let t=e.title;if(!t.length)return M;let r=`__tooltip_${Ga++}`,o=Ut(r,"inline"),n=R(".md-typeset",o);return n.innerHTML=t,C(()=>{let i=new E;return i.subscribe({next({offset:a}){o.style.setProperty("--md-tooltip-x",`${a.x}px`),o.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),$(i.pipe(y(({active:a})=>a)),i.pipe(_e(250),y(({active:a})=>!a))).subscribe({next({active:a}){a?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Me(16,ce)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(ft(125,ce),y(()=>!!e.offsetParent),f(()=>e.offsetParent.getBoundingClientRect()),f(({x:a})=>a)).subscribe({next(a){a?o.style.setProperty("--md-tooltip-0",`${-a}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Qa(o,e).pipe(S(a=>i.next(a)),H(()=>i.complete()),f(a=>I({ref:e},a)))}).pipe(qe(se))}function Xa({viewport$:e}){if(!J("header.autohide"))return j(!1);let t=e.pipe(f(({offset:{y:n}})=>n),ct(2,1),f(([n,i])=>[nMath.abs(i-n.y)>100),f(([,[n]])=>n),X()),o=ot("search");return W([e,o]).pipe(f(([{offset:n},i])=>n.y>400&&!i),X(),x(n=>n?r:j(!1)),q(!1))}function Gn(e,t){return C(()=>W([he(e),Xa(t)])).pipe(f(([{height:r},o])=>({height:r,hidden:o})),X((r,o)=>r.height===o.height&&r.hidden===o.hidden),ee(1))}function Qn(e,{header$:t,main$:r}){return C(()=>{let o=new E,n=o.pipe(oe(),ne(!0));o.pipe(Z("active"),Ke(t)).subscribe(([{active:a},{hidden:s}])=>{e.classList.toggle("md-header--shadow",a&&!s),e.hidden=s});let i=fe(P("[title]",e)).pipe(y(()=>J("content.tooltips")),te(a=>Jn(a)));return r.subscribe(o),t.pipe(z(n),f(a=>I({ref:e},a)),Ye(i.pipe(z(n))))})}function Za(e,{viewport$:t,header$:r}){return ur(e,{viewport$:t,header$:r}).pipe(f(({offset:{y:o}})=>{let{height:n}=pe(e);return{active:o>=n}}),Z("active"))}function Xn(e,t){return C(()=>{let r=new E;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=de(".md-content h1, .objdesc > dt .descname");return typeof o=="undefined"?M:Za(o,t).pipe(S(n=>r.next(n)),H(()=>r.complete()),f(n=>I({ref:e},n)))})}function Zn(e,{viewport$:t,header$:r}){let o=r.pipe(f(({height:i})=>i),X()),n=o.pipe(x(()=>he(e).pipe(f(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),Z("bottom"))));return W([o,n,t]).pipe(f(([i,{top:a,bottom:s},{offset:{y:l},size:{height:c}}])=>(c=Math.max(0,c-Math.max(0,a-l,i)-Math.max(0,c+l-s)),{offset:a-i,height:c,active:a-i<=l})),X((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function es(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return j(...e).pipe(te(o=>v(o,"change").pipe(f(()=>o))),q(e[r]),f(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),ee(1))}function ei(e){let t=P("input",e),r=g("meta",{name:"theme-color"});document.head.appendChild(r);let o=g("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Ft("(prefers-color-scheme: light)");return C(()=>{let i=new E;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),l=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=l.getAttribute("data-md-color-scheme"),a.color.primary=l.getAttribute("data-md-color-primary"),a.color.accent=l.getAttribute("data-md-color-accent")}for(let[s,l]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,l);for(let s=0;sa.key==="Enter"),ie(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(f(()=>{let a=Se("header"),s=window.getComputedStyle(a);return o.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(l=>(+l).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(Le(se)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),es(t).pipe(z(n.pipe(Ae(1))),mt(),S(a=>i.next(a)),H(()=>i.complete()),f(a=>I({ref:e},a)))})}function ti(e,{progress$:t}){return C(()=>{let r=new E;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(S(o=>r.next({value:o})),H(()=>r.complete()),f(o=>({ref:e,value:o})))})}function ts(e){let{searchParams:t}=ge();t.has("q")&&(Ge("search",!0),e.value=t.get("q"),e.focus(),ot("search").pipe(pt(n=>!n)).subscribe(()=>{let n=ge();n.searchParams.delete("q"),history.replaceState({},"",`${n}`)}));let r=tt(e),o=$(v(e,"keyup"),r).pipe(f(()=>e.value),X());return W([o,r]).pipe(f(([n,i])=>({value:n,focus:i})),ee(1))}function ri(e){let t=new E,r=t.pipe(oe(),ne(!0));t.pipe(Z("focus")).subscribe(({focus:n})=>{n&&Ge("search",n)}),v(e.form,"reset").pipe(z(r)).subscribe(()=>e.focus());let o=R("header [for=__search]");return v(o,"click").subscribe(()=>e.focus()),ts(e).pipe(S(n=>t.next(n)),H(()=>t.complete()),f(n=>I({ref:e},n)),ee(1))}var to=vt(dr());var rs=me();function eo(e){return`${rs.base}${e}`}var br;function oi(e){return new Promise((t,r)=>{let o=document.createElement("script"),n=eo(e);o.src=n,o.addEventListener("load",()=>t()),o.addEventListener("error",()=>{console.error(`Failed to load search data: ${n}`),r()}),document.body.appendChild(o)})}function os(){return br!==void 0||(br=Promise.all([oi("_static/language_data.js"),oi("searchindex.js")]).then(()=>{})),br}var Ne={objNameMatch:11,objPartialMatch:6,objPrio:{0:15,1:5,2:-5},objPrioDefault:0,title:15,partialTitle:7,term:5,partialTerm:2},ro;window.Search={setIndex:e=>{ro=e}};var ns=!1;function is(e,t){let{docurls:r,objects:o,objnames:n,titles:i}=ro,a=[];function s(l,c,p,m,u,d,h){var K;let b=(l?`${l}.`:"")+d,O=b.toLowerCase();if(O.indexOf(e)>-1){let B=0,_=O.split(".");O===e||_[_.length-1]===e?B+=Ne.objNameMatch:_[_.length-1].indexOf(e)>-1&&(B+=Ne.objPartialMatch);let De=n[p][2],ke=i[c];if(t.length>0){let Ce=`${l} ${d} ${De} ${ke} ${h!=null?h:""}`.toLowerCase(),Dt=!0;for(let bt=0;bt2){let d=oo(p);if(!n[p])for(let h in n)h.match(d)&&u.push({files:n[h],score:Ne.partialTerm});if(!i[p])for(let h in i)h.match(d)&&u.push({files:i[h],score:Ne.partialTitle})}if(u.every(d=>d.files===void 0))break;u.forEach(d=>{let h=d.files;if(h!==void 0){Array.isArray(h)||(h=[h]),m.push(...h);for(let b=0;bd.length>2).length;if(!(a[p].length!==e.length&&a[p].length!==u)){for(let d=0;ds[c][h]));l.push({docurl:r[c],title:o[c],anchor:"",objectLabel:null,synopsis:null,score:d})}}}return l}function cs(e){let t=new DOMParser().parseFromString(e,"text/html");t.querySelectorAll(".headerlink").forEach(l=>{var c;(c=l.parentNode)==null||c.removeChild(l)});let r=t.querySelector("[role=main]");if(r===null)return console.warn("Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template."),[];let o=r.querySelectorAll("h1, h2, h3, h4, h5, h6"),n,i=[],a=t.createRange(),s=(l,c)=>{var d;l!==void 0?a.setStartAfter(l):a.setStartBefore(r),c!==void 0?a.setEndBefore(c):a.setEndAfter(r);let p=a.toString().trim(),m=(d=l==null?void 0:l.textContent)==null?void 0:d.trim();if(!m&&!p)return;let u=l!==void 0?`#${l.id}`:"";i.push({title:m!=null?m:"",anchor:u,text:p})};return o.forEach(l=>{if(!l.id)return;let p=n;n=l,s(p,l)}),s(n,void 0),i}function ls(e,t){let r=cs(e),o=t.map(i=>new RegExp(oo(i),"im")),n=[];for(let i=0;ii.score!==a.score?a.score-i.score:i.sectionIndex-a.sectionIndex),n.length!==0)return n.map(i=>{let s=r[i.sectionIndex],l=Math.max(i.snippetIndex-240/2,0);return{snippet:(l>0?"\u2026":"")+s.text.substr(l,240).trim()+(l+240${(0,to.default)(e.objectLabel)}`,text:r(e.synopsis)}];let a=eo(e.docurl),s;if(window.location.protocol!=="file:")try{let m=yield(yield fetch(a)).text();s=ls(m,t)}catch(p){console.warn("Failed to retrieve search result document: ",p)}s===void 0&&(s=[{score:-1,title:"",anchor:"",snippet:"",terms:i}]);let l=[];s[0].score!==-1&&l.push({location:o,score:e.score,terms:i,title:r(n),text:""});let c;for(let p of s)c===void 0&&(c=p.score),l.push({location:o+p.anchor,score:p.score===c?e.score:0,terms:p.terms,title:r(p.title||n),text:r(p.snippet)});return l})}function ms(e){return new DOMParser().parseFromString(e,"text/html").body.textContent||""}function ni(e){return Ie(this,null,function*(){yield os();let t=new Stemmer,r=[],o=[],n=[],i=[];for(let p of as(e)){let m=!1;p[0]==="-"&&(m=!0,p=p.substring(1));let u=p.toLowerCase();if(u.length===0)continue;i.push(u);let d=!1;for(let h of u.matchAll(new RegExp("\\p{L}+","gu"))){let b=h[0];if(stopwords.indexOf(b)!==-1)continue;let O=t.stemWord(b);O.length<3&&b.length>=3&&(O=b);let K;m?K=o:(K=r,d=!0),K.indexOf(O)===-1&&K.push(O)}!m&&d&&n.push(u)}let a=[];for(let p=0;p{let u=p.score,d=m.score;if(u!==d)return d-u;let h=p.title.toLowerCase(),b=m.title.toLowerCase();return h>b?1:h`${p}`,c=p=>(0,to.default)(p).replace(s,l).replace(/<\/mark>(\s+)]*>/gimu,"$1");return{count:a.length,get:p=>ps(a[p],n,c)}})}function ii(e,{query$:t}){let r=R(":scope > :first-child",e),o=R(":scope > :last-child",e);ot("search").subscribe(m=>o.setAttribute("role",m?"list":"presentation"));let n,i,a=e.parentElement,s=16,l=()=>a.scrollTop+a.clientHeight+s>a.scrollHeight,c=()=>{i!==void 0&&l()&&(i(),i=void 0)};a.addEventListener("scroll",c,{passive:!0}),window.addEventListener("resize",c,{passive:!0});let p=m=>Ie(this,null,function*(){n=m;let u=4,d=u;for(let h=0;h{i=()=>O(void 0)})),d+=u),n!==m)return;let b=yield m.get(h);if(n!==m)return;o.appendChild(Cn(b))}});return t.pipe(Z("value"),lt(()=>Ur(250)),Nr(m=>Ie(this,null,function*(){if(m.value)return ni(m.value)})),Le(ce)).subscribe(m=>{switch(o.innerHTML="",m?m.count:0){case 0:r.textContent=m?ye("search.result.none"):ye("search.result.placeholder");break;case 1:r.textContent=ye("search.result.one");break;default:let u=lr(m.count);r.textContent=ye("search.result.other",u)}m&&p(m)}),j()}function fs(e,{query$:t}){return t.pipe(f(({value:r})=>{let o=ge();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function ai(e,t){let r=new E,o=r.pipe(oe(),ne(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),v(e,"click").pipe(z(o)).subscribe(n=>n.preventDefault()),fs(e,t).pipe(S(n=>r.next(n)),H(()=>r.complete()),f(n=>I({ref:e},n)))}function si(e,{keyboard$:t}){let r=Se("search-query");return t.pipe(y(({mode:o})=>o==="search")).subscribe(o=>{switch(o.type){case"ArrowRight":e.innerText.length&&r.selectionStart===r.value.length&&(r.value=e.innerText);break}}),j()}function ci(e,{keyboard$:t}){try{let r=Se("search-query",e),o=Se("search-result",e);v(e,"click").pipe(y(({target:i})=>i instanceof Element&&!!i.closest("a"))).subscribe(()=>Ge("search",!1)),t.pipe(y(({mode:i})=>i==="search")).subscribe(i=>{let a=Re();switch(i.type){case"Enter":if(a===r){let s=new Map;for(let l of P(":first-child [href]",o)){let c=l.firstElementChild;s.set(l,parseFloat(c.getAttribute("data-md-score")))}if(s.size){let[[l]]=[...s].sort(([,c],[,p])=>p-c);l.click()}i.claim()}break;case"Escape":case"Tab":Ge("search",!1),r.blur();break;case"ArrowUp":case"ArrowDown":if(typeof a=="undefined")r.focus();else{let s=[r,...P(":not(details) > [href], summary, details[open] [href]",o)],l=Math.max(0,(Math.max(0,s.indexOf(a))+s.length+(i.type==="ArrowUp"?-1:1))%s.length);s[l].focus()}i.claim();break;default:r!==Re()&&r.focus()}}),t.pipe(y(({mode:i})=>i==="global")).subscribe(i=>{switch(i.type){case"f":case"s":case"/":r.focus(),r.select(),i.claim();break}});let n=ri(r);return $(n,ii(o,{query$:n})).pipe(Ye(...ae("search-share",e).map(i=>ai(i,{query$:n})),...ae("search-suggest",e).map(i=>si(i,{keyboard$:t}))))}catch(r){return e.hidden=!0,st}}var no=vt(Xr());function us(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function li({alert$:e}){no.default.isSupported()&&new F(t=>{new no.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||us(R(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(S(t=>{t.trigger.focus()}),f(()=>ye("clipboard.copied"))).subscribe(e)}function pi(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function ds(e,t){let r=new Map;for(let o of P("url",e)){let n=R("loc",o),i=[pi(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let a of P("[rel=alternate]",o)){let s=a.getAttribute("href");s!=null&&i.push(pi(new URL(s),t))}}return r}function vr(e){return vn(new URL("sitemap.xml",e)).pipe(f(t=>ds(t,new URL(e))),we(()=>j(new Map)))}function hs(e,t){if(!(e.target instanceof Element))return M;let r=e.target.closest("a");if(r===null)return M;if(r.target||e.metaKey||e.ctrlKey)return M;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),j(new URL(r.href))):M}function mi(e){let t=new Map;for(let r of P(":scope > *",e.head))t.set(r.outerHTML,r);return t}function fi(e){for(let t of P("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return j(e)}function bs(e){return Ie(this,null,function*(){let t=new Set,r=new Set;for(let a of P("script",document))a.src?t.add(new URL(a.src,document.baseURI).toString()):r.add(a.outerHTML);for(let a of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...J("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let s=de(a),l=de(a,e);typeof s!="undefined"&&typeof l!="undefined"&&s.replaceWith(l)}let o=mi(document);for(let[a,s]of mi(e))o.has(a)?o.delete(a):document.head.appendChild(s);for(let a of o.values()){let s=a.getAttribute("name");s!=="theme-color"&&s!=="color-scheme"&&a.remove()}let n=[];for(let a of P("script",e))if(a.src){let s=new URL(a.src,document.baseURI).toString();if(!t.has(s)){let l=document.createElement("script");for(let c of a.getAttributeNames())l.setAttribute(c,a.getAttribute(c));l.src=s,l.async||n.push(new Promise(c=>l.addEventListener("load",()=>c()))),document.body.appendChild(l),t.add(s)}}else{let s=a.outerHTML;if(!r.has(s)){let l=document.createElement("script");for(let c of a.getAttributeNames())l.setAttribute(c,a.getAttribute(c));l.textContent=a.textContent,document.body.appendChild(l),r.add(s)}}yield Promise.all(n);let i=Se("container");return yield jr(Fe(P("script",i)).pipe(x(a=>{let s=e.createElement("script");if(a.src){for(let l of a.getAttributeNames())s.setAttribute(l,a.getAttribute(l));return a.replaceWith(s),new F(l=>{s.onload=()=>l.complete()})}else return s.textContent=a.textContent,a.replaceWith(s),M}),oe(),ne(document))),document})}function ui({location$:e,viewport$:t,progress$:r}){let o=me();if(location.protocol==="file:")return M;let n=vr(o.base);j(document).subscribe(fi);let i=v(document.body,"click").pipe(Ke(n),x(([l,c])=>hs(l,c)),ue()),a=v(window,"popstate").pipe(f(ge),ue());i.pipe(ie(t)).subscribe(([l,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",l)}),$(i,a).subscribe(e);let s=e.pipe(Z("pathname"),x(l=>bn(l,{progress$:r}).pipe(we(()=>(ut(l,!0),M)))),x(fi),x(bs),ue());return $(s.pipe(ie(e,(l,c)=>c)),s.pipe(x(()=>e),Z("hash")),e.pipe(X((l,c)=>l.pathname===c.pathname&&l.hash===c.hash),x(()=>i),S(()=>history.back()))).subscribe(l=>{var c,p;history.state!==null||!l.hash?window.scrollTo(0,(p=(c=history.state)==null?void 0:c.y)!=null?p:0):(history.scrollRestoration="auto",un(l.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),v(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(Z("offset"),_e(100)).subscribe(({offset:l})=>{history.replaceState(l,"")}),s}var di=vt(dr());function hi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(0,di.default)(a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function bi(e){var p;let{selectedVersionSitemap:t,selectedVersionBaseURL:r,currentLocation:o,currentBaseURL:n}=e,i=(p=io(n))==null?void 0:p.pathname;if(i===void 0)return;let a=vs(o.pathname,i);if(a===void 0)return;let s=ys(t.keys());if(!t.has(s))return;let l=io(a,s);if(!l||!t.has(l.href))return;let c=io(a,r);if(c)return c.hash=o.hash,c.search=o.search,c}function io(e,t){try{return new URL(e,t)}catch(r){return}}function vs(e,t){if(e.startsWith(t))return e.slice(t.length)}function gs(e,t){let r=Math.min(e.length,t.length),o;for(o=0;onew URL(s,o).toString().replace(/\/*$/,""),i=r.pipe(f(s=>{let l=t.base.toString().replace(/\/*$/,"");return s.find(({version:c,aliases:p})=>n(c)===l||p.find(m=>n(m)===l))||s[0]}));r.pipe(f(s=>new Map(s.map(l=>[`${new URL(`../${l.version}/`,t.base)}`,l]))),x(s=>v(document.body,"click").pipe(y(l=>!l.metaKey&&!l.ctrlKey),ie(i),x(([l,c])=>{if(l.target instanceof Element){let p=l.target.closest("a");if(p&&!p.target&&s.has(p.href)){let m=p.href;return!l.target.closest(".md-version")&&s.get(m)===c?M:(l.preventDefault(),j(new URL(m)))}}return M}),x(l=>vr(l).pipe(f(c=>{var p;return(p=bi({selectedVersionSitemap:c,selectedVersionBaseURL:l,currentLocation:ge(),currentBaseURL:t.base}))!=null?p:l})))))).subscribe(s=>ut(s,!0)),W([r,i]).subscribe(([s,l])=>{R(".md-header__topic").appendChild($n(s,l))}),e.pipe(x(()=>i)).subscribe(s=>{var p;let l=new URL(t.base),c=__md_get("__outdated",sessionStorage,l);if(c===null){c=!0;let m=((p=t.version)==null?void 0:p.default)||"latest";Array.isArray(m)||(m=[m]);e:for(let u of m)for(let d of s.aliases.concat(s.version))if(new RegExp(u,"i").test(d)){c=!1;break e}__md_set("__outdated",c,sessionStorage,l)}if(c)for(let m of ae("outdated"))m.hidden=!1})}function gi(e,{location$:t}){let r={lang:[],separator:"\\s+",pipeline:[]};return W([t.pipe(q(ge()),y(o=>!!o.searchParams.get("h")))]).pipe(f(([o])=>hi(r)(o.searchParams.get("h"))),f(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let l=s.textContent,c=o(l);c.length>l.length&&n.set(s,c)}for(let[s,l]of n){let{childNodes:c}=g("span",null,l);s.replaceWith(...Array.from(c))}return{ref:e,nodes:n}}))}function xs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return W([r,t]).pipe(f(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(n,Math.max(0,s-i))-n,{height:a,locked:s>=i+n})),X((i,a)=>i.height===a.height&&i.locked===a.locked))}function ao(e,o){var n=o,{header$:t}=n,r=uo(n,["header$"]);let i=R(".md-sidebar__scrollwrap",e),{y:a}=Ve(i);return C(()=>{let s=new E,l=s.pipe(oe(),ne(!0)),c=s.pipe(Me(0,ce));return c.pipe(ie(t)).subscribe({next([{height:p},{height:m}]){i.style.height=`${p-2*a}px`,e.style.top=`${m}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(pt()).subscribe(()=>{for(let p of P(".md-nav__link--active[href]",e)){if(!p.clientHeight)continue;let m=p.closest(".md-sidebar__scrollwrap");if(typeof m!="undefined"){let u=p.offsetTop-m.offsetTop,{height:d}=pe(m);m.scrollTo({top:u-d/2})}}}),fe(P("label[tabindex]",e)).pipe(te(p=>v(p,"click").pipe(Le(se),f(()=>p),z(l)))).subscribe(p=>{let m=R(`[id="${p.htmlFor}"]`);R(`[aria-labelledby="${p.id}"]`).setAttribute("aria-expanded",`${m.checked}`)}),xs(e,r).pipe(S(p=>s.next(p)),H(()=>s.complete()),f(p=>I({ref:e},p)))})}function yi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Rt(Qe(`${r}/releases/latest`).pipe(we(()=>M),f(o=>({version:o.tag_name})),Ue({})),Qe(r).pipe(we(()=>M),f(o=>({stars:o.stargazers_count,forks:o.forks_count})),Ue({}))).pipe(f(([o,n])=>I(I({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Qe(r).pipe(f(o=>({repositories:o.public_repos})),Ue({}))}}function xi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Rt(Qe(`${r}/releases/permalink/latest`).pipe(we(()=>M),f(({tag_name:o})=>({version:o})),Ue({})),Qe(r).pipe(we(()=>M),f(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Ue({}))).pipe(f(([o,n])=>I(I({},o),n)))}function Ei(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return yi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return xi(r,o)}return M}var Es;function ws(e){return Es||(Es=C(()=>{let t=__md_get("__source",sessionStorage);if(t)return j(t);if(ae("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return M}return Ei(e.href).pipe(S(o=>__md_set("__source",o,sessionStorage)))}).pipe(we(()=>M),y(t=>Object.keys(t).length>0),f(t=>({facts:t})),ee(1)))}function wi(e){let t=R(":scope > :last-child",e);return C(()=>{let r=new E;return r.subscribe(({facts:o})=>{t.appendChild(Hn(o)),t.classList.add("md-source__repository--active")}),ws(e).pipe(S(o=>r.next(o)),H(()=>r.complete()),f(o=>I({ref:e},o)))})}function Ts(e,{viewport$:t,header$:r}){return he(document.body).pipe(x(()=>ur(e,{header$:r,viewport$:t})),f(({offset:{y:o}})=>({hidden:o>=10})),Z("hidden"))}function Ti(e,t){return C(()=>{let r=new E;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(J("navigation.tabs.sticky")?j({hidden:!1}):Ts(e,t)).pipe(S(o=>r.next(o)),H(()=>r.complete()),f(o=>I({ref:e},o)))})}function Ss(e,{viewport$:t,header$:r,excludedLinks:o}){let n=new Map,i=P("a[href]",e);for(let l of i){if(o!=null&&o.has(l))continue;let c=l.getAttribute("href"),p;if(c.startsWith("#")){let m=decodeURIComponent(l.hash.substring(1));p=de(`[id="${m}"]`)}else p=de(`a.pseudo-toc-entry[href=${CSS.escape(c)}]`);if(typeof p!="undefined"){let m=l.closest(".md-nav__link");m!==null&&n.set(m,p)}}let a=r.pipe(Z("height"),f(({height:l})=>{let c=Se("main"),p=R(":scope > :first-child",c);return l+.8*(p.offsetTop-c.offsetTop)}),ue());return he(document.body).pipe(Z("height"),x(l=>C(()=>{let c=[];return j([...n].reduce((p,[m,u])=>{for(;c.length&&n.get(c[c.length-1]).tagName>=u.tagName;)c.pop();let d=u.offsetTop;for(;!d&&u.parentElement;)u=u.parentElement,d=u.offsetTop;let h=u.offsetParent;for(;h;h=h.offsetParent)d+=h.offsetTop;return p.set([...c=[...c,m]].reverse(),d)},new Map))}).pipe(f(c=>new Map([...c].sort(([,p],[,m])=>p-m))),Ke(a),x(([c,p])=>t.pipe(zr(([m,u],{offset:{y:d},size:h})=>{let b=d+h.height>=Math.floor(l.height);for(;u.length;){let[,O]=u[0];if(O-p=d&&!b)u=[m.pop(),...u];else break}return[m,u]},[[],[...c]]),X((m,u)=>m[0]===u[0]&&m[1]===u[1])))))).pipe(f(([l,c])=>({prev:l.map(([p])=>p),next:c.map(([p])=>p)})),q({prev:[],next:[]}),ct(2,1),f(([l,c])=>l.prev.length{let n=new E,i=n.pipe(oe(),ne(!0)),a=e.dataset.mdComponent==="toc",s=a?"md-nav__link--active":"md-nav__link--in-viewport";if(n.subscribe(({prev:c,next:p})=>{for(let[m]of p)m.classList.remove("md-nav__link--passed"),m.classList.remove(s);for(let[m,[u]]of c.entries())u.classList.add("md-nav__link--passed"),u.classList.toggle(s,m===c.length-1)}),J("toc.follow")&&(a||!J("toc.integrate"))){let c=!a||J("toc.integrate");n.pipe(_e(1)).subscribe(({prev:p})=>{var h;let m;if(p.length===0&&c&&(m=(h=e.querySelector("a[href='#']"))!=null?h:e),c=!1,p.length!==0&&(m=p[p.length-1][0]),m===void 0||!m.offsetHeight)return;let u=m.parentElement,d=5;for(;u!==null&&u.scrollHeight-d<=u.clientHeight;)u=u.parentElement;if(u!==null&&u!==document.body&&u!==document.documentElement){let b=m.getBoundingClientRect(),O=u.getBoundingClientRect();u.scrollTo({top:u.scrollTop+(b.y-O.height/2-O.y)})}})}a&&J("navigation.tracking")&&t.pipe(z(i),Z("offset"),_e(250),Ae(1),z(o.pipe(Ae(1))),mt({delay:250}),ie(n)).subscribe(([,{prev:c}])=>{let p=ge(),m=c[c.length-1];if(m&&m.length){let[u]=m,{hash:d}=new URL(u.href);p.hash!==d&&(p.hash=d,history.replaceState({},"",`${p}`))}else p.hash="",history.replaceState({},"",`${p}`)}),J("toc.sticky")&&he(document.body).pipe(Z("width"),_e(0)).subscribe(()=>{let c=new Map,p="--md-nav__header-height";for(let m of P(".md-nav__link",e)){let u=m.nextElementSibling;if(!(u instanceof HTMLElement)||u.tagName!=="NAV")continue;let d="",h=NaN,b=u.parentElement.closest("nav");if(b!==null){let O=c.get(b);O!==void 0&&(d=`${O.height} + `,h=O.zindex-1)}isNaN(h)&&(h=100),d+=`${m.offsetHeight}px + 0.625em`,m.classList.add("md-nav__sticky"),m.style.setProperty("--md-nav__sticky-zindex",h.toString()),u.style.setProperty(p,`calc(${d})`),c.set(u,{height:d,zindex:h})}});let l=a?void 0:new Set(P("[data-md-component='toc'] a[href]",e));return Ss(e,{viewport$:t,header$:r,excludedLinks:l}).pipe(S(c=>n.next(c)),H(()=>n.complete()),f(c=>I({ref:e},c)))})}function Os(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(f(({offset:{y:a}})=>a),ct(2,1),f(([a,s])=>a>s&&s>0),X()),i=r.pipe(f(({active:a})=>a));return W([i,n]).pipe(f(([a,s])=>!(a&&s)),X(),z(o.pipe(Ae(1))),ne(!0),mt({delay:250}),f(a=>({hidden:a})))}function Si(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new E,a=i.pipe(oe(),ne(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(z(a),Z("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),v(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),Os(e,{viewport$:t,main$:o,target$:n}).pipe(S(s=>i.next(s)),H(()=>i.complete()),f(s=>I({ref:e},s)))}function Oi({document$:e,viewport$:t}){e.pipe(x(()=>P(".md-ellipsis")),te(r=>rt(r).pipe(z(e.pipe(Ae(1))),y(o=>o),f(()=>r),Te(1))),y(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,J("content.tooltips")?dt(n,{viewport$:t}).pipe(z(e.pipe(Ae(1))),H(()=>n.removeAttribute("title"))):M})).subscribe(),J("content.tooltips")&&e.pipe(x(()=>P(".md-status")),te(r=>dt(r,{viewport$:t}))).subscribe()}function Li({document$:e,tablet$:t}){e.pipe(x(()=>P(".md-toggle--indeterminate")),S(r=>{r.indeterminate=!0,r.checked=!1}),te(r=>v(r,"change").pipe(Kr(()=>r.classList.contains("md-toggle--indeterminate")),f(()=>r))),ie(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ls(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Mi({document$:e}){e.pipe(x(()=>P("[data-md-scrollfix]")),S(t=>t.removeAttribute("data-md-scrollfix")),y(Ls),te(t=>v(t,"touchstart").pipe(f(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function _i({viewport$:e,tablet$:t}){W([ot("search"),t]).pipe(f(([r,o])=>r&&!o),x(r=>j(r).pipe(Be(r?400:100))),ie(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var nt=en(),Nt=mn(),ht=dn(Nt),co=pn(),xe=wn(),gr=Ft("(min-width: 960px)"),Ci=Ft("(min-width: 1220px)"),Hi=hn(),Ms=me(),lo=new E;li({alert$:lo});var po=new E;J("navigation.instant")&&ui({location$:Nt,viewport$:xe,progress$:po}).subscribe(nt);var Ai;((Ai=Ms.version)==null?void 0:Ai.provider)==="mike"&&vi({document$:nt});$(Nt,ht).pipe(Be(125)).subscribe(()=>{Ge("drawer",!1),Ge("search",!1)});co.pipe(y(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=de("link[rel=prev]");typeof t!="undefined"&&ut(t);break;case"n":case".":let r=de("link[rel=next]");typeof r!="undefined"&&ut(r);break;case"Enter":let o=Re();o instanceof HTMLLabelElement&&o.click()}});Oi({viewport$:xe,document$:nt});Li({document$:nt,tablet$:gr});Mi({document$:nt});_i({viewport$:xe,tablet$:gr});var Xe=Gn(Se("header"),{viewport$:xe}),Ct=nt.pipe(f(()=>Se("main")),x(e=>Zn(e,{viewport$:xe,header$:Xe})),ee(1)),_s=$(...ae("consent").map(e=>Sn(e,{target$:ht})),...ae("dialog").map(e=>Yn(e,{alert$:lo})),...ae("palette").map(e=>ei(e)),...ae("progress").map(e=>ti(e,{progress$:po})),...ae("search").map(e=>ci(e,{keyboard$:co})),...ae("source").map(e=>wi(e))),As=C(()=>$(...ae("announce").map(e=>Tn(e)),...ae("content").map(e=>Bn(e,{viewport$:xe,target$:ht,print$:Hi})),...ae("content").map(e=>J("search.highlight")?gi(e,{location$:Nt}):M),...ae("header").map(e=>Qn(e,{viewport$:xe,header$:Xe,main$:Ct})),...ae("header-title").map(e=>Xn(e,{viewport$:xe,header$:Xe})),...ae("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Br(Ci,()=>ao(e,{viewport$:xe,header$:Xe,main$:Ct})):Br(gr,()=>ao(e,{viewport$:xe,header$:Xe,main$:Ct}))),...ae("tabs").map(e=>Ti(e,{viewport$:xe,header$:Xe})),...ae("toc").map(e=>so(e,{viewport$:xe,header$:Xe,main$:Ct,target$:ht})),...ae("sidebar").filter(e=>e.getAttribute("data-md-type")==="navigation").map(e=>so(e,{viewport$:xe,header$:Xe,main$:Ct,target$:ht})),...ae("top").map(e=>Si(e,{viewport$:xe,header$:Xe,main$:Ct,target$:ht})))),ki=nt.pipe(x(()=>As),Ye(_s),ee(1));ki.subscribe();window.document$=nt;window.location$=Nt;window.target$=ht;window.keyboard$=co;window.viewport$=xe;window.tablet$=gr;window.screen$=Ci;window.print$=Hi;window.alert$=lo;window.progress$=po;window.component$=ki;})(); diff --git a/cchk.toml b/cchk.toml deleted file mode 100644 index 431612ef..00000000 --- a/cchk.toml +++ /dev/null @@ -1,23 +0,0 @@ -[commit] -# https://www.conventionalcommits.org -conventional_commits = true -subject_capitalized = false -subject_imperative = true -subject_max_length = 80 -subject_min_length = 5 -allow_commit_types = ["feat", "fix", "docs", "style", "refactor", "test", "chore", "ci"] -allow_merge_commits = true -allow_revert_commits = true -allow_empty_commits = false -allow_fixup_commits = true -allow_wip_commits = false -require_body = false -require_signed_off_by = false -ignore_authors = ["dependabot[bot]", "copilot[bot]", "pre-commit-ci[bot]"] - -[branch] -# https://conventional-branch.github.io/ -conventional_branch = true -allow_branch_types = ["feature", "bugfix", "hotfix", "release", "chore", "feat", "fix"] -require_rebase_target = "main" -ignore_authors = ["dependabot[bot]", "copilot[bot]", "pre-commit-ci[bot]", "shenxianpeng"] diff --git a/changelog.html b/changelog.html new file mode 100644 index 00000000..ee9f4409 --- /dev/null +++ b/changelog.html @@ -0,0 +1,918 @@ + + + + + + + + + + + + + + + + + + + + + + + + Changelog - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Changelog

+

All notable changes to this project will be documented in this file.

+

Full changelog available at GitHub releases.

+

v2.0.0 (2025-10-01)

+
+

Attention

+

This major release introduces significant architectural changes and breaking updates to commit-check. Please review carefully before upgrading.

+
+

What’s New

+
    +
  • TOML Configuration — Replaces the old .commit-check.yml with cchk.toml or commit-check.toml for clearer syntax.

  • +
  • Simplified CLI & Hooks — Legacy pre-commit hooks and command-line options have been removed for a cleaner, more consistent interface.

  • +
  • New Validation Engine — The validation system has been completely redesigned around a new ValidationEngine to improve maintainability and flexibility.

  • +
+

Breaking Changes

+

Configuration Format:

+
    +
  • .commit-check.yml has been replaced with cchk.toml or commit-check.toml.

  • +
  • All YAML configurations must be migrated to TOML from this version onward.

  • +
  • See the Migration Guide for step-by-step instructions.

  • +
+

Removed Pre-commit Hooks and CLI Options:

+
    +
  • Several legacy hooks and command-line flags have been removed in favor of a simplified interface.

  • +
  • Removed hooks: check-commit-signoff, check-merge-base, check-imperative.

  • +
  • Removed CLI options: --signoff, --merge-base, --imperative.

  • +
+

Module Removal:

+
    +
  • The following legacy modules have been removed: author.py, branch.py, commit.py, error.py.

  • +
+

Architecture Redesign:

+
    +
  • The validation system has been completely restructured around the new ValidationEngine, breaking compatibility with any code or integrations relying on the old module structure.

  • +
+

See PR #280

+

v0.10.2 (2025-08-26)

+

Last release before the big v2.0 changes.

+

v0.1.0 (2022-11-02)

+

Initial release of commit-check.

+ + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/cli_args.html b/cli_args.html new file mode 100644 index 00000000..f666f04a --- /dev/null +++ b/cli_args.html @@ -0,0 +1,997 @@ + + + + + + + + + + + + + + + + + + + + + + commit-check –help - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

commit-check –help

+

usage: commit-check [-h] [-v] [-c CONFIG] [-m [MESSAGE]] [-b] [-n] [-e] [-d]

+

Check commit message, branch name, author name, email, and more.

+

options:

+
+
+-h, --help
+
+
-h, --help
+

show this help message and exit

+
+
+
+ +
+
+-v, --version
+
+
-v, --version
+

show program’s version number and exit

+
+
+
+ +
+
+-c, --config
+
+
-c CONFIG, --config CONFIG
+

path to config file (cchk.toml or commit-check.toml). +If not specified, searches for cchk.toml in current +directory

+
+
+
+ +
+
+-m, --message
+
+
-m [MESSAGE], –message [MESSAGE]

validate commit message. Optionally specify file path, +otherwise reads from stdin if available

+
+
+
+ +
+
+-b, --branch
+
+
-b, --branch
+

check current git branch name

+
+
+
+ +
+
+-n, --author-name
+
+
-n, --author-name
+

check git author name

+
+
+
+ +
+
+-e, --author-email
+
+
-e, --author-email
+

check git author email

+
+
+
+ +
+
+-d, --dry-run
+
+
-d, --dry-run
+

perform a dry run without failing (always returns 0)

+
+
+
+ + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/commit_check/__init__.py b/commit_check/__init__.py deleted file mode 100644 index 1e169609..00000000 --- a/commit_check/__init__.py +++ /dev/null @@ -1,62 +0,0 @@ -"""The commit-check package's base module. - -Exports: - PASS / FAIL exit codes - ANSI color constants - __version__ (package version) -""" - -from importlib.metadata import version - -# Exit codes used across the package -PASS = 0 -FAIL = 1 - -# ANSI color codes used for CLI output -RED = "\033[91m" -GREEN = "\033[92m" -YELLOW = "\033[93m" -RESET_COLOR = "\033[0m" - -# Follow conventional commits -DEFAULT_COMMIT_TYPES = [ - "feat", - "fix", - "docs", - "style", - "refactor", - "test", - "chore", - "perf", - "build", - "ci", -] -# Follow conventional branch -DEFAULT_BRANCH_TYPES = [ - "feature", - "bugfix", - "hotfix", - "release", - "chore", - "feat", - "fix", -] -# Additional allowed branch names (e.g., develop, staging) -DEFAULT_BRANCH_NAMES: list[str] = [] - -# Handle different default values for different rules -DEFAULT_BOOLEAN_RULES = { - "subject_capitalized": False, - "subject_imperative": False, - "allow_merge_commits": True, - "allow_revert_commits": True, - "allow_empty_commits": True, - "allow_fixup_commits": True, - "allow_wip_commits": True, - "require_body": False, - "require_signed_off_by": False, -} - - -CONFIG_FILE = "." # Search current directory for commit-check.toml or cchk.toml -__version__ = version("commit-check") diff --git a/commit_check/config.py b/commit_check/config.py deleted file mode 100644 index e197ec82..00000000 --- a/commit_check/config.py +++ /dev/null @@ -1,37 +0,0 @@ -"""TOML config loader and schema for commit-check.""" - -from typing import Any, Dict -from pathlib import Path - -try: - import tomllib - - toml_load = tomllib.load -except ImportError: - import tomli # type: ignore - - toml_load = tomli.load - -DEFAULT_CONFIG_PATHS = [ - Path("cchk.toml"), - Path("commit-check.toml"), -] - - -def load_config(path_hint: str = "") -> Dict[str, Any]: - """Load and validate config from TOML file.""" - if path_hint: - p = Path(path_hint) - if not p.exists(): - raise FileNotFoundError(f"Specified config file not found: {path_hint}") - with open(p, "rb") as f: - return toml_load(f) - - # Check default config paths only when no specific path is provided - for candidate in DEFAULT_CONFIG_PATHS: - if candidate.exists(): - with open(candidate, "rb") as f: - return toml_load(f) - - # Return empty config if no default config files found - return {} diff --git a/commit_check/engine.py b/commit_check/engine.py deleted file mode 100644 index aaf1ea60..00000000 --- a/commit_check/engine.py +++ /dev/null @@ -1,563 +0,0 @@ -"""Clean validation engine following SOLID principles.""" - -from typing import List, Optional, Dict, Type -from abc import ABC, abstractmethod -from dataclasses import dataclass -from enum import IntEnum -from dataclasses import field - -from commit_check.rule_builder import ValidationRule -from commit_check.util import ( - get_commit_info, - get_branch_name, - has_commits, - git_merge_base, -) -from commit_check.imperatives import IMPERATIVES - - -class ValidationResult(IntEnum): - """Validation result codes.""" - - PASS = 0 - FAIL = 1 - - -@dataclass(frozen=True) -class ValidationContext: - """Context for validation operations.""" - - stdin_text: Optional[str] = None - commit_file: Optional[str] = None - config: Dict = field(default_factory=dict) - - -class BaseValidator(ABC): - """Abstract base validator.""" - - def __init__(self, rule: ValidationRule): - self.rule = rule - - @abstractmethod - def validate(self, context: ValidationContext) -> ValidationResult: - """Perform validation and return result.""" - pass - - def _should_skip_validation(self, context: ValidationContext) -> bool: - """ - Determine if validation should be skipped. - - Skip only when there is no stdin_text, no commit_file, and no commits. - """ - return ( - context.stdin_text is None - and context.commit_file is None - and not has_commits() - ) - - def _should_skip_commit_validation(self, context: ValidationContext) -> bool: - """ - Determine if commit validation should be skipped. - - Skip if the current author is in the ignore_authors list for commits, - or if no stdin_text, no commit_file, and no commits exist. - """ - ignore_authors = context.config.get("commit", {}).get("ignore_authors", []) - current_author = get_commit_info("an") - if current_author and current_author in ignore_authors: - return True - return ( - context.stdin_text is None - and context.commit_file is None - and not has_commits() - ) - - def _should_skip_branch_validation(self, context: ValidationContext) -> bool: - """ - Determine if branch validation should be skipped. - - Skip if the current author is in the ignore_authors list for branches, - or if no stdin_text and no commits exist. - """ - ignore_authors = context.config.get("branch", {}).get("ignore_authors", []) - current_author = get_commit_info("an") - if current_author and current_author in ignore_authors: - return True - return context.stdin_text is None and not has_commits() - - def _print_failure(self, actual_value: str, regex_or_constraint: str = "") -> None: - """Print standardized failure message.""" - from commit_check.util import _print_failure - - rule_dict = self.rule.to_dict() - constraint = regex_or_constraint or rule_dict.get("regex", "") - _print_failure(rule_dict, constraint, actual_value) - - -class CommitMessageValidator(BaseValidator): - """Validates commit messages against conventional commit standards.""" - - def validate(self, context: ValidationContext) -> ValidationResult: - if self._should_skip_commit_validation(context): - return ValidationResult.PASS - - message = self._get_commit_message(context) - if not message: - return ValidationResult.PASS - - import re - - if self.rule.regex and re.match(self.rule.regex, message): - return ValidationResult.PASS - - self._print_failure(message) - return ValidationResult.FAIL - - def _get_commit_message(self, context: ValidationContext) -> str: - """Get commit message from context or git.""" - if context.stdin_text: - return context.stdin_text.strip() - - if context.commit_file: - try: - with open(context.commit_file, "r") as f: - return f.read().strip() - except FileNotFoundError: - pass - - # Fallback to git log - subject = get_commit_info("s") - body = get_commit_info("b") - return f"{subject}\n\n{body}".strip() - - -class SubjectValidator(BaseValidator): - """Validates commit subject lines.""" - - def validate(self, context: ValidationContext) -> ValidationResult: - if self._should_skip_commit_validation(context): - return ValidationResult.PASS - - subject = self._get_subject(context) - if not subject: - return ValidationResult.PASS - - return self._validate_subject(subject) - - def _get_subject(self, context: ValidationContext) -> str: - """Extract subject from commit message.""" - if context.stdin_text: - return context.stdin_text.strip().split("\n")[0] - - if context.commit_file: - try: - with open(context.commit_file, "r") as f: - message = f.read().strip() - return message.split("\n")[0] - except FileNotFoundError: - pass - - return get_commit_info("s") - - def _validate_subject(self, subject: str) -> ValidationResult: - """Override in subclasses for specific validation logic.""" - return ValidationResult.PASS - - -class SubjectCapitalizationValidator(SubjectValidator): - """Validates that subject starts with capital letter.""" - - def _validate_subject(self, subject: str) -> ValidationResult: - # Skip merge commits - if subject.lower().startswith("merge"): - return ValidationResult.PASS - - # For conventional commits, check the description part after the colon - import re - - match = re.match(r"^(?:\w+(?:\([^)]*\))?[!:]?\s*)(.*)", subject) - if match: - description = match.group(1).strip() - if description and description[0].isupper(): - return ValidationResult.PASS - else: - # For non-conventional commits, check the first character - if subject and subject[0].isupper(): - return ValidationResult.PASS - - self._print_failure(subject) - return ValidationResult.FAIL - - -class SubjectImperativeValidator(SubjectValidator): - """Validates that subject uses imperative mood.""" - - def _validate_subject(self, subject: str) -> ValidationResult: - # Skip merge commits and fixup commits - if subject.lower().startswith(("merge", "fixup!")): - return ValidationResult.PASS - - # Extract first word (ignore conventional commit prefixes) - import re - - # support breaking changes (feat!:) - match = re.match(r"^(?:\w+(?:\([^)]*\))?!?:\s*)?(\w+)", subject) - if not match: - return ValidationResult.PASS - - first_word = match.group(1).lower() - if first_word in IMPERATIVES: - return ValidationResult.PASS - - self._print_failure(subject) - return ValidationResult.FAIL - - -class SubjectLengthValidator(SubjectValidator): - """Validates subject line length constraints.""" - - def _validate_subject(self, subject: str) -> ValidationResult: - # Skip merge commits for length checks - if subject.lower().startswith("merge"): - return ValidationResult.PASS - - length = len(subject) - constraint_value = self.rule.value - - if self.rule.check == "subject_max_length" and length <= constraint_value: - return ValidationResult.PASS - elif self.rule.check == "subject_min_length" and length >= constraint_value: - return ValidationResult.PASS - elif self.rule.check not in ["subject_max_length", "subject_min_length"]: - return ValidationResult.PASS - - self._print_failure(subject, f"length={length}, constraint={constraint_value}") - return ValidationResult.FAIL - - -class AuthorValidator(BaseValidator): - """Validates author information.""" - - def validate(self, context: ValidationContext) -> ValidationResult: - # Use commit skip logic for ignore_authors - if self._should_skip_commit_validation(context): - return ValidationResult.PASS - - author_value = self._get_author_value(context) - if not author_value: - return ValidationResult.PASS - - return self._validate_author(author_value) - - def _get_author_value(self, context: ValidationContext) -> str: - """Get author value based on rule type.""" - if context.stdin_text: - return context.stdin_text.strip() - - format_map = { - "author_name": "an", - "author_email": "ae", - } - format_str = format_map.get(self.rule.check, "") - return get_commit_info(format_str) if format_str else "" - - def _validate_author(self, author_value: str) -> ValidationResult: - """Validate author against rule constraints.""" - if self.rule.regex: - import re - - if re.match(self.rule.regex, author_value): - return ValidationResult.PASS - self._print_failure(author_value) - return ValidationResult.FAIL - - if self.rule.allowed and author_value not in self.rule.allowed: - self._print_failure(author_value, f"allowed={sorted(self.rule.allowed)}") - return ValidationResult.FAIL - - if self.rule.ignored and author_value in self.rule.ignored: - return ValidationResult.PASS # Ignored authors pass silently - - return ValidationResult.PASS - - -class BranchValidator(BaseValidator): - """Validates branch names.""" - - def validate(self, context: ValidationContext) -> ValidationResult: - if self._should_skip_branch_validation(context): - return ValidationResult.PASS - branch_name = ( - context.stdin_text.strip() if context.stdin_text else get_branch_name() - ) - - if not self.rule.regex: - return ValidationResult.PASS - - import re - - if re.match(self.rule.regex, branch_name): - return ValidationResult.PASS - - self._print_failure(branch_name) - return ValidationResult.FAIL - - -class MergeBaseValidator(BaseValidator): - """Validates merge base ancestry.""" - - def validate(self, context: ValidationContext) -> ValidationResult: - if self._should_skip_branch_validation(context): - return ValidationResult.PASS - - current_branch = get_branch_name() - target_pattern = self.rule.regex - - if not target_pattern: - return ValidationResult.PASS - - # Find target branch matching the pattern - target_branch = self._find_target_branch(target_pattern) - if not target_branch: - return ValidationResult.PASS - - result = git_merge_base(target_branch, current_branch) - if result == 0: - return ValidationResult.PASS - - self._print_failure(current_branch, f"target={target_branch}") - return ValidationResult.FAIL - - def _find_target_branch(self, pattern: str) -> Optional[str]: - """Find target branch matching the pattern.""" - import subprocess - import re - - try: - all_branches = subprocess.check_output( - ["git", "branch", "-a"], encoding="utf-8" - ).splitlines() - - for branch in all_branches: - clean_branch = ( - branch.strip().replace("* ", "").replace("remotes/origin/", "") - ) - if re.match(pattern, clean_branch): - return clean_branch - except subprocess.CalledProcessError: - pass - - return None - - -class SignoffValidator(BaseValidator): - """Validates that commit messages contain required signoff trailer.""" - - def validate(self, context: ValidationContext) -> ValidationResult: - if self._should_skip_validation(context): - return ValidationResult.PASS - - message = self._get_commit_message(context) - if not message: - return ValidationResult.PASS - - import re - - if self.rule.regex and re.search(self.rule.regex, message): - return ValidationResult.PASS - - self._print_failure(message) - return ValidationResult.FAIL - - def _get_commit_message(self, context: ValidationContext) -> str: - """Get commit message from context or git.""" - if context.stdin_text: - return context.stdin_text.strip() - - if context.commit_file: - try: - with open(context.commit_file, "r") as f: - return f.read().strip() - except FileNotFoundError: - pass - - # Fallback to git log - subject = get_commit_info("s") - body = get_commit_info("b") - return f"{subject}\n\n{body}".strip() - - -class BodyValidator(BaseValidator): - """Validates that commit messages contain a body when required.""" - - def validate(self, context: ValidationContext) -> ValidationResult: - if self._should_skip_commit_validation(context): - return ValidationResult.PASS - - message = self._get_commit_message(context) - if not message: - return ValidationResult.PASS - - # Split message into lines and check if there's content after the subject - lines = message.strip().split("\n") - - # Filter out empty lines - non_empty_lines = [line.strip() for line in lines if line.strip()] - - # If there's more than just the subject line, we have a body - if len(non_empty_lines) > 1: - return ValidationResult.PASS - - # Check if there's content after the first line (even if separated by empty lines) - if len(lines) > 1: - body_content = "\n".join(lines[1:]).strip() - if body_content: - return ValidationResult.PASS - - self._print_failure(message) - return ValidationResult.FAIL - - def _get_commit_message(self, context: ValidationContext) -> str: - """Get commit message from context or git.""" - if context.stdin_text: - return context.stdin_text.strip() - - if context.commit_file: - try: - with open(context.commit_file, "r") as f: - return f.read().strip() - except FileNotFoundError: - pass - - # Fallback to git log - subject = get_commit_info("s") - body = get_commit_info("b") - return f"{subject}\n\n{body}".strip() - - -class CommitTypeValidator(BaseValidator): - """Base validator for special commit types (merge, revert, fixup, WIP, empty).""" - - def validate(self, context: ValidationContext) -> ValidationResult: - if self._should_skip_commit_validation(context): - return ValidationResult.PASS - - message = self._get_commit_message(context) - if not message: - return ValidationResult.PASS - - # Check if this commit type is allowed based on rule configuration - is_allowed = self._is_commit_type_allowed(message) - - if not is_allowed: - self._print_failure(message) - return ValidationResult.FAIL - - return ValidationResult.PASS - - def _is_commit_type_allowed(self, message: str) -> bool: - """Check if the commit type is allowed based on the rule check.""" - check = self.rule.check - - if check == "allow_merge_commits": - return self._is_merge_commit_allowed(message) - elif check == "allow_revert_commits": - return self._is_revert_commit_allowed(message) - elif check == "allow_empty_commits": - return self._is_empty_commit_allowed(message) - elif check == "allow_fixup_commits": - return self._is_fixup_commit_allowed(message) - elif check == "allow_wip_commits": - return self._is_wip_commit_allowed(message) - - return True - - def _is_merge_commit_allowed(self, message: str) -> bool: - """Check if merge commits are allowed.""" - is_merge = message.startswith("Merge ") - # If rule value is True, allow merge commits. If False, reject them. - return not is_merge or self.rule.value - - def _is_revert_commit_allowed(self, message: str) -> bool: - """Check if revert commits are allowed.""" - is_revert = message.lower().startswith("revert ") - return not is_revert or self.rule.value - - def _is_empty_commit_allowed(self, message: str) -> bool: - """Check if empty commits are allowed.""" - is_empty = not message.strip() - return not is_empty or self.rule.value - - def _is_fixup_commit_allowed(self, message: str) -> bool: - """Check if fixup commits are allowed.""" - is_fixup = message.startswith("fixup!") - return not is_fixup or self.rule.value - - def _is_wip_commit_allowed(self, message: str) -> bool: - """Check if WIP commits are allowed.""" - is_wip = message.upper().startswith("WIP:") - return not is_wip or self.rule.value - - def _get_commit_message(self, context: ValidationContext) -> str: - """Get commit message from context or git.""" - if context.stdin_text: - return context.stdin_text.strip() - - if context.commit_file: - try: - with open(context.commit_file, "r") as f: - return f.read().strip() - except FileNotFoundError: - pass - - # Fallback to git log - subject = get_commit_info("s") - body = get_commit_info("b") - return f"{subject}\n\n{body}".strip() - - -class ValidationEngine: - """Main validation engine that orchestrates all validations.""" - - VALIDATOR_MAP: Dict[str, Type[BaseValidator]] = { - "message": CommitMessageValidator, - "subject_capitalized": SubjectCapitalizationValidator, - "subject_imperative": SubjectImperativeValidator, - "subject_max_length": SubjectLengthValidator, - "subject_min_length": SubjectLengthValidator, - "author_name": AuthorValidator, - "author_email": AuthorValidator, - "branch": BranchValidator, - "merge_base": MergeBaseValidator, - "require_signed_off_by": SignoffValidator, - "require_body": BodyValidator, - "allow_merge_commits": CommitTypeValidator, - "allow_revert_commits": CommitTypeValidator, - "allow_empty_commits": CommitTypeValidator, - "allow_fixup_commits": CommitTypeValidator, - "allow_wip_commits": CommitTypeValidator, - "ignore_authors": CommitTypeValidator, - } - - def __init__(self, rules: List[ValidationRule]): - self.rules = rules - - def validate_all(self, context: ValidationContext) -> ValidationResult: - """Run all validations and return overall result.""" - results = [] - - for rule in self.rules: - validator_class = self.VALIDATOR_MAP.get(rule.check) - if not validator_class: - continue # Skip unknown validators - - validator: BaseValidator = validator_class(rule) - result = validator.validate(context) - results.append(result) - - # Return FAIL if any validation failed - return ( - ValidationResult.FAIL - if ValidationResult.FAIL in results - else ValidationResult.PASS - ) diff --git a/commit_check/imperatives.py b/commit_check/imperatives.py deleted file mode 100644 index adc58f17..00000000 --- a/commit_check/imperatives.py +++ /dev/null @@ -1,242 +0,0 @@ -# https://github.com/crate-ci/imperative/blob/master/assets/imperatives.txt -# Imperative forms of verbs -# -# This file contains the imperative form of frequently encountered -# docstring verbs. Some of these may be more commonly encountered as -# nouns, but blacklisting them for this may cause false positives. - -IMPERATIVES = { - "accept", - "access", - "add", - "adjust", - "aggregate", - "align", - "allow", - "append", - "apply", - "archive", - "assert", - "assign", - "attempt", - "authenticate", - "authorize", - "break", - "build", - "bump", - "cache", - "calculate", - "call", - "cancel", - "capture", - "change", - "check", - "clean", - "clear", - "close", - "collect", - "combine", - "commit", - "compare", - "compute", - "configure", - "confirm", - "connect", - "construct", - "control", - "convert", - "copy", - "count", - "create", - "customize", - "declare", - "decode", - "decorate", - "define", - "delegate", - "delete", - "deprecate", - "derive", - "describe", - "detect", - "determine", - "display", - "download", - "drop", - "dump", - "emit", - "empty", - "enable", - "encapsulate", - "encode", - "end", - "ensure", - "enumerate", - "establish", - "evaluate", - "examine", - "execute", - "exit", - "expand", - "expect", - "export", - "extend", - "extract", - "feed", - "fetch", - "fill", - "filter", - "finalize", - "find", - "fire", - "fix", - "flag", - "force", - "format", - "forward", - "generate", - "get", - "give", - "go", - "group", - "handle", - "help", - "hold", - "identify", - "implement", - "import", - "indicate", - "init", - "initialise", - "initialize", - "initiate", - "input", - "insert", - "instantiate", - "intercept", - "invoke", - "iterate", - "join", - "keep", - "launch", - "list", - "listen", - "load", - "log", - "look", - "make", - "manage", - "manipulate", - "map", - "mark", - "match", - "merge", - "mock", - "modify", - "monitor", - "move", - "normalize", - "note", - "obtain", - "open", - "output", - "override", - "overwrite", - "package", - "pad", - "parse", - "partial", - "pass", - "perform", - "persist", - "pick", - "plot", - "poll", - "populate", - "post", - "prepare", - "print", - "process", - "produce", - "provide", - "publish", - "pull", - "put", - "query", - "raise", - "read", - "record", - "redesign", - "refer", - "refresh", - "register", - "reload", - "remove", - "rename", - "render", - "replace", - "reply", - "report", - "represent", - "request", - "require", - "reset", - "resolve", - "retrieve", - "return", - "revert", - "roll", - "rollback", - "round", - "run", - "sample", - "save", - "scan", - "search", - "select", - "send", - "serialise", - "serialize", - "serve", - "set", - "show", - "simulate", - "source", - "specify", - "split", - "start", - "step", - "stop", - "store", - "strip", - "submit", - "subscribe", - "sum", - "support", - "swap", - "sync", - "synchronise", - "synchronize", - "take", - "tear", - "test", - "time", - "transform", - "translate", - "transmit", - "truncate", - "try", - "turn", - "tweak", - "update", - "upload", - "use", - "validate", - "verify", - "view", - "wait", - "walk", - "wrap", - "write", - "yield", -} diff --git a/commit_check/main.py b/commit_check/main.py deleted file mode 100644 index d1e46738..00000000 --- a/commit_check/main.py +++ /dev/null @@ -1,229 +0,0 @@ -"""Modern commit-check CLI with clean architecture and TOML support.""" - -from __future__ import annotations -import sys -import argparse -from typing import Optional - -from commit_check.config import load_config -from commit_check.rule_builder import RuleBuilder -from commit_check.engine import ValidationEngine, ValidationContext, ValidationResult -from . import __version__ - - -class StdinReader: - """Handles stdin reading with proper error handling.""" - - @staticmethod - def read_piped_input() -> Optional[str]: - """Read commit message content if piped, with proper error handling.""" - try: - if not sys.stdin.isatty(): - data = sys.stdin.read() - return data.strip() if data else None - except (OSError, IOError): - return None - return None - - -def _get_parser() -> argparse.ArgumentParser: - """Get parser to interpret CLI args.""" - parser = argparse.ArgumentParser( - prog="commit-check", - description="Check commit message, branch name, author name, email, and more.", - ) - - parser.add_argument( - "-v", - "--version", - action="version", - version=f"%(prog)s {__version__}", - ) - - parser.add_argument( - "-c", - "--config", - help="path to config file (cchk.toml or commit-check.toml). If not specified, searches for cchk.toml in current directory", - ) - - parser.add_argument( - "-m", - "--message", - nargs="?", - const="", - help="validate commit message. Optionally specify file path, otherwise reads from stdin if available", - ) - - parser.add_argument( - "-b", - "--branch", - help="check current git branch name", - action="store_true", - required=False, - ) - - parser.add_argument( - "-n", - "--author-name", - help="check git author name", - action="store_true", - required=False, - ) - - parser.add_argument( - "-e", - "--author-email", - help="check git author email", - action="store_true", - required=False, - ) - - parser.add_argument( - "-d", - "--dry-run", - help="perform a dry run without failing (always returns 0)", - action="store_true", - required=False, - ) - - return parser - - -def _get_message_content( - message_arg: Optional[str], stdin_reader: StdinReader -) -> Optional[str]: - """Get commit message content from argument, file, or stdin.""" - if message_arg is None: - return None - - # If message_arg is empty string (from nargs="?", const=""), try stdin first, then git - if message_arg == "": - # Try reading from stdin if available - stdin_content = stdin_reader.read_piped_input() - if stdin_content: - return stdin_content - - # Fallback to latest git commit message - try: - from commit_check.util import get_commit_info - - return get_commit_info("B") # Full commit message - except Exception: - print( - "Error: No commit message provided and unable to read from git", - file=sys.stderr, - ) - return None - - # If message_arg is a file path, read from file - try: - with open(message_arg, "r", encoding="utf-8") as f: - return f.read().strip() - except (OSError, IOError) as e: - print(f"Error reading message file '{message_arg}': {e}", file=sys.stderr) - return None - - -def main() -> int: - """The main entrypoint of commit-check program.""" - parser = _get_parser() - args = parser.parse_args() - - if args.dry_run: - return 0 - - stdin_reader = StdinReader() - - try: - # Load configuration - config_data = load_config(args.config) - - # Build validation rules from config - rule_builder = RuleBuilder(config_data) - all_rules = rule_builder.build_all_rules() - - # Filter rules based on CLI arguments - requested_checks = [] - if ( - args.message is not None - ): # Check for None explicitly since empty string is valid - # Add commit message related checks - requested_checks.extend( - [ - "message", - "subject_imperative", - "subject_max_length", - "subject_min_length", - "require_signed_off_by", - "subject_capitalized", - "require_body", - "allow_merge_commits", - "allow_revert_commits", - "allow_empty_commits", - "allow_fixup_commits", - "allow_wip_commits", - ] - ) - if args.branch: - requested_checks.extend(["branch", "merge_base"]) - if args.author_name: - requested_checks.append("author_name") - if args.author_email: - requested_checks.append("author_email") - - # If no specific checks requested, show help - if not requested_checks: - parser.print_help() - return 0 - - # Filter rules to only include requested checks - filtered_rules = [rule for rule in all_rules if rule.check in requested_checks] - - # Create validation engine with filtered rules - engine = ValidationEngine(filtered_rules) - - # Create validation context - stdin_content = None - commit_file_path = None - - if ( - args.message is not None - ): # Check explicitly for None since empty string is valid - if args.message == "": - # Only set stdin_content if there's actual piped input - stdin_content = stdin_reader.read_piped_input() - if not stdin_content: - # No stdin and no file - let validators get data from git themselves - stdin_content = None - else: - # Message is a file path - commit_file_path = args.message - elif not any([args.branch, args.author_name, args.author_email]): - # If no specific validation type is requested, don't read stdin - pass - else: - # For non-message validations (branch, author), check for stdin input - stdin_content = stdin_reader.read_piped_input() - - context = ValidationContext( - stdin_text=stdin_content, - commit_file=commit_file_path, - config=config_data, - ) - - # Run validation - result = engine.validate_all(context) - - # Return appropriate exit code - return 0 if result == ValidationResult.PASS else 1 - - except FileNotFoundError as e: - print(f"Error: {e}", file=sys.stderr) - return 1 - except Exception as e: - print(f"Error: {e}", file=sys.stderr) - return 1 - - -if __name__ == "__main__": # pragma: no cover - raise SystemExit(main()) diff --git a/commit_check/rule_builder.py b/commit_check/rule_builder.py deleted file mode 100644 index 46c57322..00000000 --- a/commit_check/rule_builder.py +++ /dev/null @@ -1,246 +0,0 @@ -"""Rule builder that creates validation rules from config and catalog.""" - -from typing import Dict, Any, List, Optional -from dataclasses import dataclass -from commit_check.rules_catalog import COMMIT_RULES, BRANCH_RULES, RuleCatalogEntry -from commit_check import ( - DEFAULT_COMMIT_TYPES, - DEFAULT_BRANCH_TYPES, - DEFAULT_BRANCH_NAMES, - DEFAULT_BOOLEAN_RULES, -) - - -@dataclass(frozen=True) -class ValidationRule: - """A complete validation rule with all necessary information.""" - - check: str - regex: Optional[str] = None - error: Optional[str] = None - suggest: Optional[str] = None - value: Any = None - allowed: Optional[List[str]] = None - ignored: Optional[List[str]] = None - - def to_dict(self) -> Dict[str, Any]: - """Convert to dictionary for backward compatibility.""" - result: Dict[str, Any] = { - "check": self.check, - "regex": self.regex or "", - "error": self.error or "", - "suggest": self.suggest or "", - } - if self.value is not None: - result["value"] = self.value - if self.allowed: - result["allowed"] = self.allowed - result["allowed_types"] = self.allowed # Backward compatibility - if self.ignored: - result["ignored"] = self.ignored - return result - - -class RuleBuilder: - """Builds validation rules from config and catalog entries.""" - - def __init__(self, config: Dict[str, Any]): - self.config = config - self.commit_config = config.get("commit", {}) - self.branch_config = config.get("branch", {}) - - def build_all_rules(self) -> List[ValidationRule]: - """Build all validation rules from config.""" - rules = [] - rules.extend(self._build_commit_rules()) - rules.extend(self._build_branch_rules()) - return rules - - def _build_commit_rules(self) -> List[ValidationRule]: - """Build commit-related validation rules.""" - rules = [] - - for catalog_entry in COMMIT_RULES: - rule = self._build_single_rule(catalog_entry, self.commit_config) - if rule: - rules.append(rule) - - return rules - - def _build_branch_rules(self) -> List[ValidationRule]: - """Build branch-related validation rules.""" - rules = [] - - for catalog_entry in BRANCH_RULES: - rule = self._build_single_rule(catalog_entry, self.branch_config) - if rule: - rules.append(rule) - - return rules - - def _build_single_rule( - self, catalog_entry: RuleCatalogEntry, section_config: Dict[str, Any] - ) -> Optional[ValidationRule]: - """Build a single validation rule from catalog entry and config.""" - check = catalog_entry.check - - # Handle special cases that need custom logic - if check == "message": - return self._build_conventional_commit_rule(catalog_entry) - elif check == "branch": - return self._build_conventional_branch_rule(catalog_entry) - elif check == "subject_max_length": - return self._build_length_rule(catalog_entry, "subject_max_length") - elif check == "subject_min_length": - return self._build_length_rule(catalog_entry, "subject_min_length") - elif check == "ignore_authors": - return self._build_author_list_rule(catalog_entry, "ignore_authors") - elif check == "merge_base": - return self._build_merge_base_rule(catalog_entry) - else: - return self._build_boolean_rule(catalog_entry, section_config) - - def _build_conventional_commit_rule( - self, catalog_entry: RuleCatalogEntry - ) -> Optional[ValidationRule]: - """Build conventional commit message rule.""" - if not self.commit_config.get("conventional_commits", True): - return None - - allowed_types = self._get_allowed_commit_types() - regex = self._build_conventional_commit_regex(allowed_types) - - return ValidationRule( - check=catalog_entry.check, - regex=regex, - error=catalog_entry.error, - suggest=catalog_entry.suggest, - allowed=allowed_types, - ) - - def _build_conventional_branch_rule( - self, catalog_entry: RuleCatalogEntry - ) -> Optional[ValidationRule]: - """Build conventional branch naming rule.""" - if not self.branch_config.get("conventional_branch", True): - return None - - allowed_types = self._get_allowed_branch_types() - allowed_names = self._get_allowed_branch_names() - regex = self._build_conventional_branch_regex(allowed_types, allowed_names) - - return ValidationRule( - check=catalog_entry.check, - regex=regex, - error=catalog_entry.error, - suggest=catalog_entry.suggest, - allowed=allowed_types, - ) - - def _build_length_rule( - self, catalog_entry: RuleCatalogEntry, config_key: str - ) -> Optional[ValidationRule]: - """Build subject length validation rule.""" - length = self.commit_config.get(config_key) - if not isinstance(length, int): - return None - - error = ( - catalog_entry.error.format(max_len=length, min_len=length) - if catalog_entry.error - else None - ) - - return ValidationRule( - check=catalog_entry.check, - error=error, - suggest=catalog_entry.suggest, - value=length, - ) - - def _build_author_list_rule( - self, catalog_entry: RuleCatalogEntry, config_key: str - ) -> Optional[ValidationRule]: - """Build author allow/ignore list rule.""" - author_list = self.commit_config.get(config_key) - if not isinstance(author_list, list) or not author_list: - return None - - if config_key == "ignore_authors": - return ValidationRule(check=catalog_entry.check, ignored=author_list) - return None - - def _build_merge_base_rule( - self, catalog_entry: RuleCatalogEntry - ) -> Optional[ValidationRule]: - """Build merge base validation rule.""" - target = self.branch_config.get("require_rebase_target") - if not isinstance(target, str) or not target: - return None - - return ValidationRule( - check=catalog_entry.check, - regex=target, - error=catalog_entry.error, - suggest=catalog_entry.suggest, - ) - - def _build_boolean_rule( - self, catalog_entry: RuleCatalogEntry, section_config: Dict[str, Any] - ) -> Optional[ValidationRule]: - """Build boolean-based validation rule.""" - check = catalog_entry.check - - default_value = DEFAULT_BOOLEAN_RULES.get(check, True) - config_value = section_config.get(check, default_value) - - # For "allow_*" rules, only create rule if they're disabled (False) - # For "require_*" rules, only create rule if they're enabled (True) - if check.startswith("allow_") and config_value is True: - return None - elif check.startswith("require_") and config_value is False: - return None - elif ( - check in ["subject_capitalized", "subject_imperative"] - and config_value is False - ): - return None - - return ValidationRule( - check=catalog_entry.check, - regex=catalog_entry.regex, - error=catalog_entry.error, - suggest=catalog_entry.suggest, - value=config_value, - ) - - def _get_allowed_commit_types(self) -> List[str]: - """Get deduplicated list of allowed commit types.""" - types = self.commit_config.get("allow_commit_types", DEFAULT_COMMIT_TYPES) - return list(dict.fromkeys(types)) # Preserve order, remove duplicates - - def _get_allowed_branch_types(self) -> List[str]: - """Get deduplicated list of allowed branch types.""" - types = self.branch_config.get("allow_branch_types", DEFAULT_BRANCH_TYPES) - return list(dict.fromkeys(types)) # Preserve order, remove duplicates - - def _get_allowed_branch_names(self) -> List[str]: - """Get deduplicated list of allowed branch names.""" - names = self.branch_config.get("allow_branch_names", DEFAULT_BRANCH_NAMES) - return list(dict.fromkeys(names)) # Preserve order, remove duplicates - - def _build_conventional_commit_regex(self, allowed_types: List[str]) -> str: - """Build regex for conventional commit messages.""" - types_pattern = "|".join(sorted(set(allowed_types))) - return rf"^({types_pattern}){{1}}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)|(Merge).*|(fixup!.*)" - - def _build_conventional_branch_regex( - self, allowed_types: List[str], allowed_names: List[str] - ) -> str: - """Build regex for conventional branch names.""" - types_pattern = "|".join(allowed_types) - # Build pattern for additional allowed branch names - base_names = ["master", "main", "HEAD", "PR-.+"] - all_names = base_names + allowed_names - names_pattern = ")|(".join(all_names) - return rf"^({types_pattern})\/.+|({names_pattern})" diff --git a/commit_check/rules_catalog.py b/commit_check/rules_catalog.py deleted file mode 100644 index e291915a..00000000 --- a/commit_check/rules_catalog.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Centralized catalog of all commit-check rules, regexes, and error messages.""" - -from dataclasses import dataclass -from typing import Optional - - -@dataclass(frozen=True) -class RuleCatalogEntry: - check: str - regex: Optional[str] = None - error: Optional[str] = None - suggest: Optional[str] = None - - -# Commit message rules -COMMIT_RULES = [ - RuleCatalogEntry( - check="message", - regex=None, # Built dynamically from config - error="The commit message should follow Conventional Commits. See https://www.conventionalcommits.org", - suggest="Use (): with allowed types", - ), - RuleCatalogEntry( - check="subject_capitalized", - regex=None, - error="Subject must start with a capital letter", - suggest="Capitalize the first word of the subject", - ), - RuleCatalogEntry( - check="subject_imperative", - regex=None, - error="Commit message should use imperative mood (e.g., 'Add feature' not 'Added feature')", - suggest="Use imperative mood in the subject line", - ), - RuleCatalogEntry( - check="subject_max_length", - regex=None, - error="Subject must be at most {max_len} characters", - suggest="Keep the subject concise (<= configured max)", - ), - RuleCatalogEntry( - check="subject_min_length", - regex=None, - error="Subject must be at least {min_len} characters", - suggest="Provide a meaningful subject (>= configured min)", - ), - RuleCatalogEntry( - check="allow_merge_commits", - regex=None, - error="Merge commits are not allowed", - suggest="Rebase or squash your changes instead of merging", - ), - RuleCatalogEntry( - check="allow_revert_commits", - regex=None, - error="Revert commits are not allowed", - suggest="Avoid using 'revert' commits; rewrite history if necessary", - ), - RuleCatalogEntry( - check="allow_empty_commits", - regex=None, - error="Empty commit messages are not allowed", - suggest="Provide a non-empty subject", - ), - RuleCatalogEntry( - check="allow_fixup_commits", - regex=None, - error="Fixup commits are not allowed", - suggest="Use interactive rebase to clean up fixup commits", - ), - RuleCatalogEntry( - check="allow_wip_commits", - regex=None, - error="WIP commits are not allowed", - suggest="Complete the work before committing or remove 'WIP'", - ), - RuleCatalogEntry( - check="require_body", - regex=None, - error="Commit body is required", - suggest="Add a body explaining the change", - ), - RuleCatalogEntry( - check="author_name", - regex=r"^[A-Za-zÀ-ÖØ-öø-ÿ\u0100-\u017F\u0180-\u024F ,.'\-]+$|.*(\[bot])", - error="The committer name seems invalid", - suggest="git config user.name 'Your Name'", - ), - RuleCatalogEntry( - check="author_email", - regex=r"^.+@.+$", - error="The committer's email seems invalid", - suggest="git config user.email yourname@example.com", - ), - RuleCatalogEntry( - check="ignore_authors", - regex=None, - error=None, - suggest=None, - ), - RuleCatalogEntry( - check="require_signed_off_by", - regex=r"Signed-off-by:.*[A-Za-z0-9]\s+<.+@.+>", - error="Signed-off-by not found in latest commit", - suggest="git commit --amend --signoff or use --signoff on commit", - ), -] - -# Branch rules -BRANCH_RULES = [ - RuleCatalogEntry( - check="branch", - regex=None, # Built dynamically from config - error="The branch should follow Conventional Branch. See https://conventional-branch.github.io/", - suggest="Use / with allowed types or add branch name to allow_branch_names in config, or use ignore_authors in config branch section to bypass", - ), - RuleCatalogEntry( - check="merge_base", - regex=None, # Provided by config - error="Current branch is not rebased onto target branch", - suggest="Rebase or merge with the target branch", - ), - RuleCatalogEntry( - check="ignore_authors", - regex=None, - error=None, - suggest=None, - ), -] diff --git a/commit_check/util.py b/commit_check/util.py deleted file mode 100644 index 1b4c1e72..00000000 --- a/commit_check/util.py +++ /dev/null @@ -1,269 +0,0 @@ -""" -``commit_check.util`` ---------------------- - -A module containing utility functions. -""" - -import os -import subprocess -import yaml -from pathlib import Path, PurePath -from typing import Any, Dict, Optional -from subprocess import CalledProcessError -from commit_check import RED, GREEN, YELLOW, RESET_COLOR -from commit_check.rule_builder import RuleBuilder - -# Prefer stdlib tomllib (3.11+); fall back to tomli if available; else disabled -try: # pragma: no cover - import paths differ by Python version - import tomllib as _toml # type: ignore[attr-defined] -except Exception: # pragma: no cover - try: - import tomli as _toml # type: ignore[no-redef] - except Exception: # pragma: no cover - _toml = None # type: ignore[assignment] - - -def _find_check(checks: list, check_type: str) -> dict | None: - """Return the first check dict matching check_type, else None.""" - for check in checks: - if check.get("check") == check_type: - return check - return None - - -def _print_failure(check: dict, regex: str, actual: str) -> None: - """Print a standardized failure message.""" - if not print_error_header.has_been_called: - print_error_header() - print_error_message(check["check"], regex, check.get("error", ""), actual) - if check.get("suggest"): - print_suggestion(check.get("suggest")) - - -def get_branch_name() -> str: - """Identify current branch name. - .. note:: - With Git 2.22 and above supports `git branch --show-current` - Please open an issue at https://github.com/commit-check/commit-check/issues - if you encounter any issue. - - :returns: A `str` describing the current branch name. - """ - try: - # Git 2.22 and above supports `git branch --show-current` - commands = ["git", "branch", "--show-current"] - branch_name = cmd_output(commands) - except CalledProcessError: - branch_name = "" - - if not branch_name: - # Fallback to environment variables (GitHub Actions) - branch_name = ( - os.getenv("GITHUB_HEAD_REF") or os.getenv("GITHUB_REF_NAME") or "HEAD" - ) - return branch_name.strip() - - -def has_commits() -> bool: - """Check if there are any commits in the current branch. - :returns: `True` if there are commits, `False` otherwise. - """ - try: - subprocess.run( - ["git", "rev-parse", "--verify", "HEAD"], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=True, - ) - return True - except subprocess.CalledProcessError: - return False - - -def get_commit_info(format_string: str, sha: str = "HEAD") -> str: - """Get latest commits information - :param format_string: could be - - s - subject - - an - author name - - ae - author email - - b - body - - H - commit hash - more: https://git-scm.com/docs/pretty-formats - - :returns: A `str`. - """ - try: - commands = [ - "git", - "log", - "-n", - "1", - f"--pretty=format:%{format_string}", - f"{sha}", - ] - output = cmd_output(commands) - except CalledProcessError: - output = "" - return output - - -def git_merge_base(target_branch: str, current_branch: str) -> int: - """Check ancestors for a given commit. - :param target_branch: target branch - :param current_branch: default is HEAD - - :returns: 0 if ancestor exists, 1 if not, 128 if git command fails. - """ - try: - commands = [ - "git", - "merge-base", - "--is-ancestor", - f"{target_branch}", - f"{current_branch}", - ] - result = subprocess.run( - commands, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8" - ) - return result.returncode - except CalledProcessError: - return 128 - - -def cmd_output(commands: list) -> str: - """Run command - :param commands: list of commands - - :returns: Get `str` output. - """ - result = subprocess.run( - commands, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8" - ) - if result.returncode == 0 and result.stdout is not None: - return result.stdout - elif result.stderr != "": - return result.stderr - else: - return "" - - -def _load_toml(path: PurePath) -> Dict[str, Any]: - """Load TOML from file, tolerant if toml support missing.""" - if _toml is None: - return {} - try: - with open(path, "rb") as f: - return _toml.load(f) # type: ignore[call-arg] - except FileNotFoundError: - return {} - except Exception: - return {} - - -def _find_config_file(path_hint: str) -> Optional[PurePath]: - """Resolve config file. - - - If a directory is passed, search in priority: commit-check.toml, cchk.toml - - If a file ending with .toml is passed, use it if exists. - - Ignore legacy .commit-check.yml entirely. - """ - p = Path(path_hint) - if p.is_dir(): - for name in ("commit-check.toml", "cchk.toml"): - candidate = p / name - if candidate.exists(): - return candidate - return None - # If explicit file path provided - if str(p).endswith((".toml",)) and p.exists(): - return p - return None - - -def validate_config(path_hint: str) -> dict: - """Validate and load configuration from TOML. - - Returns a dict containing a 'checks' list or empty dict if not found/invalid. - """ - cfg_path = _find_config_file(path_hint) - if cfg_path: - raw = _load_toml(cfg_path) - if not raw: - return {} - # Use new rule builder system - rule_builder = RuleBuilder(raw) - rules = rule_builder.build_all_rules() - return {"checks": [rule.to_dict() for rule in rules]} - - # Legacy YAML fallback (maintained for test compatibility) - try: - with open(PurePath(path_hint)) as f: - data = yaml.safe_load(f) # type: ignore[no-redef] - return data or {} - except FileNotFoundError: - return {} - except Exception: - return {} - - -def track_print_call(func): - def wrapper(*args, **kwargs): - wrapper.has_been_called = True - return func(*args, **kwargs) - - wrapper.has_been_called = False # Initialize as False - return wrapper - - -@track_print_call -def print_error_header(): - """Print error message. - :returns: Print error head to user - """ - print("Commit rejected by Commit-Check. ") - print(" ") - print(r" (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) ") - print(r" / ._. \ / ._. \ / ._. \ / ._. \ / ._. \ ") - print(r" __\( C )/__ __\( H )/__ __\( E )/__ __\( C )/__ __\( K )/__ ") - print(r"(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)") - print(r" || E || || R || || R || || O || || R || ") - print(r" _.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._ ") - print(r"(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)") - print(r" `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ ") - print(" ") - print("Commit rejected. ") - print(" ") - - -def print_error_message(check_type: str, regex: str, error: str, reason: str): - """Print error message. - :param check_type: - :param regex: - :param error: - :param reason: - - :returns: Give error messages to user - """ - print( - f"Type {YELLOW}{check_type}{RESET_COLOR} check failed ==> {RED}{reason}{RESET_COLOR} ", - end="", - ) - print("") - print(f"It doesn't match regex: {regex}") - print(error) - - -def print_suggestion(suggest: str | None) -> None: - """Print suggestion to user - :param suggest: what message to print out - """ - if suggest: - print( - f"Suggest: {GREEN}{suggest}{RESET_COLOR} ", - end="", - ) - else: - print(f"commit-check does not support {suggest} yet.") - raise SystemExit(1) - print("\n") diff --git a/configuration.html b/configuration.html new file mode 100644 index 00000000..8788959c --- /dev/null +++ b/configuration.html @@ -0,0 +1,971 @@ + + + + + + + + + + + + + + + + + + + + + + + + Configuration - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Configuration

+

commit-check configuration files support the TOML format. See cchk.toml for an example configuration.

+
+

Tip

+

Default Behavior

+
    +
  • When no configuration file exists, commit-check uses sensible defaults with minimal restrictions.

  • +
  • Only conventional commits format, subject capitalization, and imperative mood are enforced by default.

  • +
  • No length limits, author restrictions, or rebase requirements are applied.

  • +
+
+

commit-check can be configured via a cchk.toml or commit-check.toml file.

+

The file should be placed in the root of your repository.

+

Example Configuration

+
[commit]
+# https://www.conventionalcommits.org
+conventional_commits = true
+subject_capitalized = false
+subject_imperative = false
+# subject_max_length = 50  # Optional - no limit by default
+# subject_min_length = 5   # Optional - no limit by default
+allow_commit_types = ["feat", "fix", "docs", "style", "refactor", "test", "chore"]
+allow_merge_commits = true
+allow_revert_commits = true
+allow_empty_commits = false
+allow_fixup_commits = true
+allow_wip_commits = false
+require_body = false
+# ignore_authors = []      # Optional - no authors ignored by default
+require_signed_off_by = false
+# required_signoff_name = "Your Name"      # Optional
+# required_signoff_email = "your.email@example.com"  # Optional
+
+[branch]
+# https://conventional-branch.github.io/
+conventional_branch = true
+allow_branch_types = ["feature", "bugfix", "hotfix", "release", "chore", "feat", "fix"]
+# allow_branch_names = []  # Optional - additional standalone branch names (e.g., ["develop", "staging"])
+# require_rebase_target = "main"  # Optional - no rebase requirement by default
+# ignore_authors = []      # Optional - no authors ignored by default
+
+
+

Options Table Description

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Section

Option

Type

Default

Description

commit

conventional_commits

bool

true

Enforce Conventional Commits specification.

commit

subject_capitalized

bool

true

Subject must start with a capital letter.

commit

subject_imperative

bool

true

Subject must be in imperative mood. Forms of verbs can be found at imperatives.py

commit

subject_max_length

int

None (no limit)

Maximum length of the subject line.

commit

subject_min_length

int

None (no limit)

Minimum length of the subject line.

commit

allow_commit_types

list[str]

[“feat”, “fix”, “docs”, “style”, “refactor”, “test”, “chore”]

Allowed commit types when conventional_commits is true.

commit

allow_merge_commits

bool

true

Allow merge commits.

commit

allow_revert_commits

bool

true

Allow revert commits.

commit

allow_empty_commits

bool

false

Allow empty commits.

commit

allow_fixup_commits

bool

true

Allow fixup commits (e.g., “fixup! <commit message>”).

commit

allow_wip_commits

bool

false

Allow work-in-progress commits (e.g., “WIP: <commit message>”).

commit

require_body

bool

false

Require a body in the commit message.

commit

ignore_authors

list[str]

[] (none ignored)

List of authors to ignore (i.e., always allow).

commit

require_signed_off_by

bool

false

Require “Signed-off-by” line in the commit message footer.

branch

conventional_branch

bool

true

Enforce Conventional Branch specification.

branch

allow_branch_types

list[str]

[“feature”, “bugfix”, “hotfix”, “release”, “chore”, “feat”, “fix”]

Allowed branch types when conventional_branch is true.

branch

allow_branch_names

list[str]

[] (empty list)

Additional standalone branch names allowed when conventional_branch is true (e.g., [“develop”, “staging”]). By default, master, main, HEAD, and PR-* are always allowed.

branch

require_rebase_target

str

None (no requirement)

Target branch for rebase requirement. If not set, no rebase validation is performed.

branch

ignore_authors

list[str]

[] (none ignored)

List of authors to ignore (i.e., always allow).

+ + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index bc75624c..00000000 --- a/docs/conf.py +++ /dev/null @@ -1,143 +0,0 @@ -# pylint: disable=all -# 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 -import re -import datetime -from pathlib import Path -import subprocess -from sphinx.application import Sphinx - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -project = "commit-check" -copyright = f"{datetime.date.today().year}, shenxianpeng" -author = "shenxianpeng" - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration -extensions = [ - "sphinx_immaterial", - "sphinx.ext.autodoc", - "sphinx.ext.intersphinx", - "sphinx.ext.viewcode", - "sphinx_issues", -] - -autodoc_member_order = "bysource" - -templates_path = ["_templates"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - -default_role = "any" - -# -- Options for sphinx_issues -------------------------------------------------------- -issues_default_group_project = "commit-check/commit-check" - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -html_theme = "sphinx_immaterial" -html_static_path = ["_static"] -# html_logo = "_static/logo.jpg" can not display well in blue background -# html_favicon = "_static/favicon.ico" -html_css_files = ["extra_css.css"] -html_title = "Commit Check" - -html_theme_options = { - "repo_url": "https://github.com/commit-check/commit-check", - "repo_name": "commit-check", - "icon": { - "logo": "material/git", - }, - "palette": [ - { - "media": "(prefers-color-scheme: light)", - "scheme": "default", - "primary": "blue", - "accent": "light-blue", - "toggle": { - "icon": "material/lightbulb-outline", - "name": "Switch to dark mode", - }, - }, - { - "media": "(prefers-color-scheme: dark)", - "scheme": "slate", - "primary": "blue", - "accent": "light-blue", - "toggle": { - "icon": "material/lightbulb", - "name": "Switch to light mode", - }, - }, - ], - "features": [ - "navigation.top", - "navigation.tabs", - "navigation.tabs.sticky", - "toc.sticky", - "toc.follow", - "search.share", - ], -} - -object_description_options = [ - ("py:parameter", dict(include_in_toc=False)), -] - -sphinx_immaterial_custom_admonitions = [ - { - "name": "seealso", - "color": (215, 59, 205), - "icon": "octicons/eye-24", - "override": True, - }, - { - "name": "note", - "icon": "material/file-document-edit-outline", - "override": True, - }, -] -for name in ("hint", "tip", "important"): - sphinx_immaterial_custom_admonitions.append( - dict(name=name, icon="material/school", override=True) - ) - - -def setup(app: Sphinx): - """Generate a doc from the executable script's ``--help`` output.""" - - result = subprocess.run( - ["commit-check", "--help"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - encoding="utf-8", - ) - doc = "commit-check --help\n==============================\n\n" - CLI_OPT_NAME = re.compile(r"^\s*(\-\w)(?:\s+[A-Z_\[\]]*)?(?:,\s+(\-\-[a-z\-]+))?") - in_options_section = False - - for line in result.stdout.splitlines(): - # Start processing options when we see the "options:" line - if line.strip() == "options:": - in_options_section = True - doc += line + "\n" - continue - - # Only process option patterns in the options section - if in_options_section: - match = CLI_OPT_NAME.search(line) - if match is not None: - short_opt = match.group(1) - long_opt = match.group(2) - if short_opt and long_opt: - doc += "\n.. std:option:: " + short_opt + ", " + long_opt + "\n\n" - elif short_opt: - doc += "\n.. std:option:: " + short_opt + "\n\n" - - doc += line + "\n" - cli_doc = Path(app.srcdir, "cli_args.rst") - cli_doc.unlink(missing_ok=True) - cli_doc.write_text(doc) diff --git a/example.html b/example.html new file mode 100644 index 00000000..8e0c6595 --- /dev/null +++ b/example.html @@ -0,0 +1,1360 @@ + + + + + + + + + + + + + + + + + + + + + + + + Usage Examples - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + + + + + + + + + +
+
+ + + + + +

Usage Examples

+

This guide demonstrates how to use commit-check to validate commit messages, branch names, and author information.

+

There are several ways to use commit-check: as a pre-commit hook, via STDIN, or directly with files.

+

Running as GitHub Action

+

Please see commit-check/commit-check-action

+

Running as pre-commit hook

+
    +
  1. Install pre-commit:

  2. +
+
+

Tip

+

Make sure pre-commit is installed.

+
+
pip install pre-commit
+
+
+
    +
  1. Create .pre-commit-config.yaml:

  2. +
+
-   repo: https://github.com/commit-check/commit-check
+    rev: the tag or revision
+    hooks:
+    -   id: check-message
+        stages: [commit-msg]
+    -   id: check-branch
+    -   id: check-author-name
+    -   id: check-author-email
+
+
+
    +
  1. Install the hooks:

  2. +
+
pre-commit install --hook-type pre-commit --hook-type commit-msg
+
+
+
    +
  1. Test the integration:

  2. +
+
# This will trigger validation automatically
+git commit -m "feat: add new user authentication system"
+
+
+

Pre-commit Validation Examples

+

✅ Successful Validation:

+
$ git commit -m "feat: add user authentication system"
+
+check commit message.....................................................Passed
+check committer name.....................................................Passed
+check committer email....................................................Passed
+[main abc1234] feat: add user authentication system
+
+
+

❌ Failed Validation:

+
$ git commit -m "bad commit message"
+
+check commit message.....................................................Failed
+- hook id: check-message
+- exit code: 1
+
+Commit rejected by Commit-Check.
+
+  (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)
+   / ._. \      / ._. \      / ._. \      / ._. \      / ._. \
+ __\( C )/__  __\( H )/__  __\( E )/__  __\( C )/__  __\( K )/__
+(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
+   || E ||      || R ||      || R ||      || O ||      || R ||
+ _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._
+(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
+ `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´
+
+Commit rejected.
+
+Type message check failed ==> bad commit message
+It doesn't match regex: ^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .+
+The commit message should follow Conventional Commits. See https://www.conventionalcommits.org
+Suggest: Use <type>(<scope>): <description> with allowed types
+
+
+

Running as CLI

+

Commit-check provides several command-line options for different validation scenarios. via options or STDIN

+
+

Tip

+

Validate commit messages by piping them through STDIN. This is useful for testing or scripting.

+
+

Available Commands see commit-check –help

+

Message Validation Examples

+
# Validate message from STDIN
+echo "feat: new feature" | commit-check -m
+
+# Validate message from file
+commit-check -m commit_message.txt
+
+# Validate current git commit message (from git log)
+commit-check -m
+
+
+

Reading from file:

+
# Create a commit message file
+cat > commit_message.txt << EOF
+fix(auth): resolve login timeout issue
+
+Users were experiencing timeouts during login.
+Increased session timeout and improved error handling.
+
+Fixes #123
+EOF
+
+# Validate from file
+commit-check -m commit_message.txt
+
+# Or pipe file content
+cat commit_message.txt | commit-check -m
+
+
+

Branch Validation Examples

+
# Check current branch name
+commit-check --branch
+
+# Example valid branch names:
+# - feature/user-auth
+# - fix/login-bug
+# - hotfix/security-patch
+# - release/v1.2.0
+
+
+

Author Validation Examples

+
# Check author name
+commit-check --author-name
+
+# Check author email
+commit-check --author-email
+
+# Check both author name and email
+commit-check --author-name --author-email
+
+
+

Configuration Examples

+
# Use custom configuration file
+echo "feat: test" | commit-check --config my-config.toml -m
+
+# Use configuration from different directory
+commit-check --config /path/to/config/cchk.toml -m
+
+
+

Valid Commit Message Examples

+
# Basic feature
+echo "feat: add user registration" | commit-check -m
+
+# Feature with scope
+echo "feat(auth): implement OAuth2 login" | commit-check -m
+
+# Bug fix
+echo "fix: resolve memory leak in parser" | commit-check -m
+
+# Documentation update
+echo "docs: add installation guide" | commit-check -m
+
+# Breaking change
+echo "feat!: redesign API endpoints" | commit-check -m
+
+# Merge commit (automatically allowed)
+echo "Merge pull request #123 from feature/new-api" | commit-check -m
+
+
+

Invalid Commit Message Examples

+
# No type prefix
+echo "added new feature" | commit-check -m
+
+# Capitalized (if configured to disallow)
+echo "feat: Add new feature" | commit-check -m
+
+# Too short
+echo "fix" | commit-check -m
+
+# Non-imperative mood
+echo "feat: added login functionality" | commit-check -m
+
+# Unknown type
+echo "unknown: some changes" | commit-check -m
+
+
+

Error Output Examples

+

Commit Message Validation Failure:

+
Commit rejected by Commit-Check.
+
+  (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)
+   / ._. \      / ._. \      / ._. \      / ._. \      / ._. \
+ __\( C )/__  __\( H )/__  __\( E )/__  __\( C )/__  __\( K )/__
+(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
+   || E ||      || R ||      || R ||      || O ||      || R ||
+ _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._
+(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
+ `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´
+
+Commit rejected.
+
+Type message check failed ==> test commit message check
+It doesn't match regex: ^(chore|ci|docs|feat|fix|refactor|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)|(Merge).*|(fixup!.*)
+The commit message should follow Conventional Commits. See https://www.conventionalcommits.org
+Suggest: Use <type>(<scope>): <description> with allowed types
+
+
+

Branch Name Validation Failure:

+
Commit rejected by Commit-Check.
+
+  (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)
+   / ._. \      / ._. \      / ._. \      / ._. \      / ._. \
+ __\( C )/__  __\( H )/__  __\( E )/__  __\( C )/__  __\( K )/__
+(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
+   || E ||      || R ||      || R ||      || O ||      || R ||
+ _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._
+(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
+ `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´
+
+Commit rejected.
+
+Type branch check failed ==> test-branch
+It doesn't match regex: ^(feature|bugfix|hotfix|release|chore|feat|fix)\/.+|(master)|(main)|(HEAD)|(PR-.+)
+The branch should follow Conventional Branch. See https://conventional-branch.github.io/
+Suggest: Use <type>/<description> with allowed types or ignore_authors in config branch section to bypass
+
+
+

Commit Signature Validation Failure:

+
Commit rejected by Commit-Check.
+
+  (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)
+   / ._. \      / ._. \      / ._. \      / ._. \      / ._. \
+ __\( C )/__  __\( H )/__  __\( E )/__  __\( C )/__  __\( K )/__
+(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
+   || E ||      || R ||      || R ||      || O ||      || R ||
+ _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._
+(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
+ `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´
+
+Commit rejected.
+
+Type require_signed_off_by check failed ==> fix: add missing file
+It doesn't match regex: Signed-off-by:.*[A-Za-z0-9]\s+<.+@.+>
+Signed-off-by not found in latest commit
+Suggest: git commit --amend --signoff or use --signoff on commit
+
+
+

Imperative Mood Validation Failure:

+
Commit rejected by Commit-Check.
+
+  (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)
+   / ._. \      / ._. \      / ._. \      / ._. \      / ._. \
+ __\( C )/__  __\( H )/__  __\( E )/__  __\( C )/__  __\( K )/__
+(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
+   || E ||      || R ||      || R ||      || O ||      || R ||
+ _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._
+(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
+ `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´
+
+Commit rejected.
+
+Type imperative check failed ==> fix: added missing file
+It doesn't match regex:
+Commit message should use imperative mood (e.g., 'Add feature' not 'Added feature')
+Suggest: Use imperative mood in the subject line
+
+
+

Integration Tips

+

CI/CD Integration

+

You can use commit-check in CI/CD pipelines:

+
# In your CI script
+git log --format="%s" -n 1 | commit-check -m
+
+# or just
+commit-check -m
+
+
+

Scripting

+

Use commit-check in scripts to validate commit messages programmatically:

+
#!/bin/bash
+# validate-commits.sh
+
+# Get all commit messages from last 10 commits
+for i in {0..9}; do
+    msg=$(git log --format="%s" -n 1 --skip=$i)
+    if [ -n "$msg" ]; then
+        echo "Validating: $msg"
+        echo "$msg" | commit-check -m || exit 1
+    fi
+done
+
+echo "All commits are valid!"
+
+
+

For more configuration options, see the Configuration Documentation.

+ + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000..bcce365a --- /dev/null +++ b/genindex.html @@ -0,0 +1,865 @@ + + + + + + + + + + + + + + + + + + + + Index - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Index

+ +
+ Symbols + | C + +
+

Symbols

+ + + +
+ +

C

+ + +
+ + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..c4b408c9 --- /dev/null +++ b/index.html @@ -0,0 +1,949 @@ + + + + + + + + + + + + + + + + + + + + + + Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Commit Check

+

CI Quality Gate Status PyPI commit-check CodeCov SLSA

+

Overview

+

Commit Check (aka cchk) is an open-source tool that enforces commit metadata standards — including commit messages, branch naming, committer name/email, commit signoff, and more — helping teams maintain consistency and compliance.

+

As a lightweight alternative to GitHub Enterprise Metadata restrictions +and Bitbucket’s paid plugin Yet Another Commit Checker, Commit Check integrates DevOps principles and Infrastructure as Code (IaC) practices for a modern workflow.

+

What’s New in v2.0.0

+

Version 2.0.0 is a major release featuring a new configuration format, a modernized architecture, and an improved user experience.

+

✨ Highlights

+
    +
  • TOML Configuration — Replaces .commit-check.yml with cchk.toml or commit-check.toml for clearer, more consistent syntax.

  • +
  • Simplified CLI & Hooks — Legacy pre-commit hooks and options removed to deliver a cleaner, more streamlined interface.

  • +
  • New Validation Engine — Fully redesigned for greater flexibility, performance, and maintainability.

  • +
+

For the full list of updates and improvements, visit the What’s New page.

+

Installation

+

To install Commit Check, you can use pip:

+
pip install commit-check
+
+
+

Or install directly from the GitHub repository:

+
pip install git+https://github.com/commit-check/commit-check.git@main
+
+
+

Then, run commit-check --help or cchk --help (alias for commit-check) from the command line. +For more information, see the docs.

+

Configuration

+

Use Default Configuration

+ +

Use Custom Configuration

+

To customize the behavior, create a configuration file named cchk.toml or commit-check.toml in your repository’s root directory, e.g., cchk.toml

+

Usage

+

For detailed usage instructions including pre-commit hooks, CLI commands, and STDIN examples, see the Usage Examples documentation.

+

Examples

+

Check Commit Message Failed

+
Commit rejected by Commit-Check.
+
+  (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)
+   / ._. \      / ._. \      / ._. \      / ._. \      / ._. \
+ __\( C )/__  __\( H )/__  __\( E )/__  __\( C )/__  __\( K )/__
+(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
+   || E ||      || R ||      || R ||      || O ||      || R ||
+ _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._
+(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
+ `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´
+
+Commit rejected.
+
+Type message check failed ==> test commit message check
+It doesn't match regex: ^(chore|ci|docs|feat|fix|refactor|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)|(Merge).*|(fixup!.*)
+The commit message should follow Conventional Commits. See https://www.conventionalcommits.org
+Suggest: Use <type>(<scope>): <description> with allowed types
+
+
+

Check Branch Naming Failed

+
Commit rejected by Commit-Check.
+
+  (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)    (c).-.(c)
+   / ._. \      / ._. \      / ._. \      / ._. \      / ._. \
+ __\( C )/__  __\( H )/__  __\( E )/__  __\( C )/__  __\( K )/__
+(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
+   || E ||      || R ||      || R ||      || O ||      || R ||
+ _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._  _.' '-' '._
+(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
+ `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´  `-´     `-´
+
+Commit rejected.
+
+Type branch check failed ==> test-branch
+It doesn't match regex: ^(feature|bugfix|hotfix|release|chore|feat|fix)\/.+|(master)|(main)|(HEAD)|(PR-.+)
+The branch should follow Conventional Branch. See https://conventional-branch.github.io/
+Suggest: Use <type>/<description> with allowed types or ignore_authors in config branch section to bypass
+
+
+

More examples see example documentation.

+

Badging your repository

+

You can add a badge to your repository to show that you use commit-check!

+commit-check + +

Markdown

+
[![commit-check](https://img.shields.io/badge/commit--check-enabled-brightgreen?logo=Git&logoColor=white&color=%232c9ccd)](https://github.com/commit-check/commit-check)
+
+
+

reStructuredText

+
.. image:: https://img.shields.io/badge/commit--check-enabled-brightgreen?logo=Git&logoColor=white&color=%232c9ccd
+    :target: https://github.com/commit-check/commit-check
+    :alt: commit-check
+
+
+

Versioning

+

Versioning follows Semantic Versioning.

+

Have question or feedback?

+

Please post to issues for feedback, feature requests, or bug reports.

+

License

+

This project is released under the MIT License

+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/migration.html b/migration.html new file mode 100644 index 00000000..843948d1 --- /dev/null +++ b/migration.html @@ -0,0 +1,1112 @@ + + + + + + + + + + + + + + + + + + + + + + + + Migration Guide - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Migration Guide

+

This guide helps you migrate from commit-check v1.x (YAML configuration) to v2.0+ (TOML configuration).

+

Overview

+

Version 2.0 introduces significant changes to commit-check:

+
    +
  • Configuration format: .commit-check.ymlcchk.toml or commit-check.toml

  • +
  • Simplified architecture: New validation engine with cleaner design

  • +
  • Enhanced functionality: Better error messages and more flexible configuration options

  • +
+

Quick Migration Steps

+
    +
  1. Backup your existing configuration:

    +
    cp .commit-check.yml .commit-check.yml.backup
    +
    +
    +
  2. +
  3. Create new TOML configuration:

    +
    touch cchk.toml  # or commit-check.toml
    +
    +
    +
  4. +
  5. Convert YAML to TOML format (see examples below)

  6. +
  7. Test the new configuration:

    +
    commit-check --help
    +commit-check --message --branch --author-name --author-email --dry-run
    +
    +
    +
  8. +
  9. Remove old YAML file:

    +
    rm .commit-check.yml.backup  # after confirming everything works
    +
    +
    +
  10. +
+

Configuration Format Changes

+

The configuration structure has changed from YAML to TOML format

+

YAML (v1.x) vs TOML (v2.0+)

+

Old YAML format (.commit-check.yml):

+
checks:
+- check: message
+    regex: '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)|(Merge).*|(fixup!.*)'
+    error: "The commit message should be structured as follows:\n\n
+    <type>[optional scope]: <description>\n
+    [optional body]\n
+    [optional footer(s)]\n\n
+    More details please refer to https://www.conventionalcommits.org"
+    suggest: please check your commit message whether matches above regex
+
+- check: branch
+    regex: ^(bugfix|feature|release|hotfix|task|chore)\/.+|(master)|(main)|(HEAD)|(PR-.+)
+    error: "Branches must begin with these types: bugfix/ feature/ release/ hotfix/ task/ chore/"
+    suggest: run command `git checkout -b type/branch_name`
+
+- check: author_name
+    regex: ^[A-Za-zÀ-ÖØ-öø-ÿ\u0100-\u017F\u0180-\u024F ,.\'-]+$|.*(\[bot])
+    error: The committer name seems invalid
+    suggest: run command `git config user.name "Your Name"`
+
+- check: author_email
+    regex: ^.+@.+$
+    error: The committer email seems invalid
+    suggest: run command `git config user.email yourname@example.com`
+
+- check: commit_signoff
+    regex: Signed-off-by:.*[A-Za-z0-9]\s+<.+@.+>
+    error: Signed-off-by not found in latest commit
+    suggest: run command `git commit -m "conventional commit message" --signoff`
+
+- check: merge_base
+    regex: main # it can be master, develop, devel etc based on your project.
+    error: Current branch is not rebased onto target branch
+    suggest: Please ensure your branch is rebased with the target branch
+
+- check: imperative
+    regex: '' # Not used for imperative mood check
+    error: 'Commit message should use imperative mood (e.g., "Add feature" not "Added feature")'
+    suggest: 'Use imperative mood in commit message like "Add", "Fix", "Update", "Remove"'
+
+
+

New TOML format (cchk.toml or commit-check.toml):

+
[commit]
+# https://www.conventionalcommits.org
+conventional_commits = true
+subject_capitalized = false
+subject_imperative = true
+subject_max_length = 80
+subject_min_length = 5
+allow_commit_types = ["feat", "fix", "docs", "style", "refactor", "test", "chore", "ci"]
+allow_merge_commits = true
+allow_revert_commits = true
+allow_empty_commits = false
+allow_fixup_commits = true
+allow_wip_commits = false
+require_body = false
+require_signed_off_by = false
+ignore_authors = ["dependabot[bot]", "copilot[bot]"]
+
+[branch]
+# https://conventional-branch.github.io/
+conventional_branch = true
+allow_branch_types = ["feature", "bugfix", "hotfix", "release", "chore", "feat", "fix"]
+require_rebase_target = "main"
+
+
+

CLI Changes

+

The command-line interface has been simplified:

+

Old CLI (v1.x):

+
commit-check --config .commit-check.yml
+
+
+

New CLI (v2.0+):

+
commit-check --config cchk.toml  # or commit-check.toml
+# Or use defaults (no config file needed)
+commit-check --message --branch
+
+
+

Troubleshooting

+

Common Issues

+

Issue: “Configuration file not found”

+

Solution: Ensure your file is named cchk.toml or commit-check.toml and placed in the repository root.

+

Issue: “Invalid TOML syntax”

+

Solution: Use a TOML validator or check the syntax. Common issues include:

+
    +
  • Missing quotes around strings

  • +
  • Incorrect boolean values (use true/false, not True/False)

  • +
  • Invalid array syntax

  • +
+

Issue: “Validation rules not working as expected”

+

Solution: Check the Configuration Documentation for the correct option names and formats.

+

Validation and Testing

+

After migration, test your configuration:

+
# Test commit message validation
+echo "feat: test commit message" | commit-check --message
+
+# Test branch validation
+commit-check --branch
+
+# Test with dry-run flag
+commit-check --message --branch --author-name --author-email --dry-run
+
+
+

Getting Help

+ + + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/noxfile.py b/noxfile.py deleted file mode 100644 index 44072ced..00000000 --- a/noxfile.py +++ /dev/null @@ -1,64 +0,0 @@ -import nox -import glob - -nox.options.reuse_existing_virtualenvs = True -nox.options.sessions = ["lint"] - -# ----------------------------------------------------------------------------- -# Development Commands -# ----------------------------------------------------------------------------- - - -@nox.session() -def lint(session): - session.install("pre-commit") - # only need pre-commit hook for local development - session.run("pre-commit", "install", "--hook-type", "pre-commit") - session.run("pre-commit", "run", "--all-files") - - -@nox.session(name="test-hook") -def test_hook(session): - session.install("-e", ".") - session.install("pre-commit") - session.run("pre-commit", "try-repo", ".") - - -@nox.session() -def build(session): - session.run("python3", "-m", "pip", "wheel", "--no-deps", "-w", "dist", ".") - - -@nox.session(name="install", requires=["build"]) -def install_wheel(session): - session.run("python3", "-m", "pip", "wheel", "--no-deps", "-w", "dist", ".") - whl_file = glob.glob("dist/*.whl") - session.install(str(whl_file[0])) - - -@nox.session(name="commit-check") -def commit_check(session): - session.install(".") - session.run("commit-check", "--message", "--branch", "--author-email") - - -@nox.session() -def coverage(session): - session.install(".[test]") - session.run("coverage", "run", "--source", "commit_check", "-m", "pytest") - session.run("coverage", "report") - session.run("coverage", "xml") - - -@nox.session() -def docs(session): - session.install(".[docs]") - session.run("sphinx-build", "-E", "-b", "html", "docs", "_build/html") - - -@nox.session(name="docs-live") -def docs_live(session): - session.install(".[docs]") - session.run( - "sphinx-autobuild", "-b", "html", "docs", "_build/html", "--watch", "docs/" - ) diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..a96de190 Binary files /dev/null and b/objects.inv differ diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index dce7b4ea..00000000 --- a/pyproject.toml +++ /dev/null @@ -1,76 +0,0 @@ -[build-system] -requires = ["setuptools>=77", "setuptools-scm"] -build-backend = "setuptools.build_meta" - -[project] -name = "commit-check" -description = "Check commit message formatting, branch naming, commit author, email, and more." -readme = "README.rst" -keywords = ["commit conventions", "conventional commits", "conventional branch", "branch naming", "commit-check", "message", "lint message", "devops"] -license = "MIT" -authors = [ - { name = "Xianpeng Shen", email = "xianpeng.shen@gmail.com" }, -] -requires-python = ">=3.9" -dependencies = ["pyyaml", "typer"] -classifiers = [ - # https://pypi.org/pypi?%3Aaction=list_classifiers - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Natural Language :: English", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", - "Topic :: Utilities" , - "Topic :: Software Development :: Build Tools", - "Topic :: Software Development :: Libraries :: Python Modules", -] -dynamic = ["version"] - -[project.scripts] -commit-check = "commit_check.main:main" -cchk = "commit_check.main:main" # short alias without clobbering system cc - -[project.urls] -source = "https://github.com/commit-check/commit-check" -tracker = "https://github.com/commit-check/commit-check/issues" - -# ... other project metadata fields as specified in: -# https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ - -[project.optional-dependencies] -dev = ['nox'] -test = ['coverage', 'pytest', 'pytest-mock', 'pytest-codspeed'] -docs = ['sphinx<9', 'sphinx-immaterial', 'sphinx-autobuild', 'sphinx_issues'] - -[tool.setuptools] -zip-safe = false -packages = ["commit_check"] - -[tool.setuptools_scm] -# It would be nice to include the commit hash in the version, but that -# can't be done in a PEP 440-compatible way. -version_scheme= "no-guess-dev" -# Test PyPI does not support local versions. -local_scheme = "no-local-version" -fallback_version = "0.0.0" - -[tool.mypy] -show_error_codes = true -show_column_numbers = true - -[tool.coverage] -omit = [ - # don't include tests in coverage - "tests/*", -] - -[tool.pytest.ini_options] -# Silence PytestUnknownMarkWarning for custom marks used in tests -markers = [ - "benchmark: performance-related tests (no-op marker in this project)", -] diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..a4eadc53 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"Additional Resources": [[8, "additional-resources"]], "Architecture Improvements": [[8, "architecture-improvements"]], "Attention": [[1, null]], "Author Validation": [[8, "author-validation"]], "Author Validation Examples": [[4, "author-validation-examples"]], "Badging your repository": [[5, "badging-your-repository"]], "Branch Naming Validation": [[8, "branch-naming-validation"]], "Branch Validation Examples": [[4, "branch-validation-examples"]], "Breaking Changes": [[1, "breaking-changes"]], "Bypass All Hooks": [[7, "bypass-all-hooks"]], "Bypass Specific Hook": [[7, "bypass-specific-hook"]], "CI/CD Integration": [[4, "ci-cd-integration"]], "CLI Changes": [[6, "cli-changes"]], "Changelog": [[1, null]], "Commit Check": [[5, null]], "Commit Message Validation": [[8, "commit-message-validation"]], "Common Issues": [[6, "common-issues"]], "Configuration": [[3, null], [5, "configuration"]], "Configuration Examples": [[4, "configuration-examples"], [8, "configuration-examples"]], "Configuration Format Changes": [[6, "configuration-format-changes"]], "Configuration Format Migration": [[8, "configuration-format-migration"]], "Documentation & Migration": [[8, "documentation-migration"]], "Error Output Examples": [[4, "error-output-examples"]], "Example Configuration": [[3, "example-configuration"]], "Examples": [[5, "examples"]], "For Existing Users": [[8, "for-existing-users"]], "For New Users:": [[8, "for-new-users"]], "Getting Help": [[6, "getting-help"]], "Getting Started with v2.0": [[8, "getting-started-with-v2-0"]], "Have question or feedback?": [[5, "have-question-or-feedback"]], "How to Skip Author Name Check": [[7, "how-to-skip-author-name-check"]], "How to build the docs": [[0, null]], "Installation": [[5, "installation"]], "Integration Tips": [[4, "integration-tips"]], "Invalid Commit Message Examples": [[4, "invalid-commit-message-examples"]], "License": [[5, "license"]], "Message Validation Examples": [[4, "message-validation-examples"]], "Migration Guide": [[6, null]], "Module Organization": [[8, "module-organization"]], "New Validation Engine": [[8, "new-validation-engine"]], "Options Table Description": [[3, "options-table-description"]], "Overview": [[5, "overview"], [6, "overview"], [8, "overview"]], "Pre-commit Validation Examples": [[4, "pre-commit-validation-examples"]], "Quick Migration Steps": [[6, "quick-migration-steps"]], "Running as CLI": [[4, "running-as-cli"]], "Running as GitHub Action": [[4, "running-as-github-action"]], "Running as pre-commit hook": [[4, "running-as-pre-commit-hook"]], "Scripting": [[4, "scripting"]], "Signed-off-by Requirements": [[8, "signed-off-by-requirements"]], "Tip": [[3, null], [4, null], [4, null]], "Troubleshooting": [[6, "troubleshooting"], [7, null]], "Usage": [[5, "usage"]], "Usage Examples": [[4, null]], "Use Custom Configuration": [[5, "use-custom-configuration"]], "Use Default Configuration": [[5, "use-default-configuration"]], "Valid Commit Message Examples": [[4, "valid-commit-message-examples"]], "Validation and Testing": [[6, "validation-and-testing"]], "Version 2.0.0 - Major Release": [[8, "version-2-0-0-major-release"]], "Versioning": [[5, "versioning"]], "What\u2019s New": [[1, "what-s-new"], [8, null]], "What\u2019s New in v2.0.0": [[5, "whats-new-in-v2-0-0"]], "YAML (v1.x) vs TOML (v2.0+)": [[6, "yaml-v1-x-vs-toml-v2-0"]], "commit-check \u2013help": [[2, null]], "v0.1.0 (2022-11-02)": [[1, "v0-1-0-2022-11-02"]], "v0.10.2 (2025-08-26)": [[1, "v0-10-2-2025-08-26"]], "v2.0.0 (2025-10-01)": [[1, "v2-0-0-2025-10-01"]]}, "docurls": ["README.html", "changelog.html", "cli_args.html", "configuration.html", "example.html", "index.html", "migration.html", "troubleshoot.html", "what-is-new.html"], "envversion": {"sphinx": 64, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.viewcode": 1}, "indexentries": {"--author-email": [[2, "cmdoption-e", false]], "--author-name": [[2, "cmdoption-n", false]], "--branch": [[2, "cmdoption-b", false]], "--config": [[2, "cmdoption-c", false]], "--dry-run": [[2, "cmdoption-d", false]], "--help": [[2, "cmdoption-h", false]], "--message": [[2, "cmdoption-m", false]], "--version": [[2, "cmdoption-v", false]], "-b": [[2, "cmdoption-b", false]], "-c": [[2, "cmdoption-c", false]], "-d": [[2, "cmdoption-d", false]], "-e": [[2, "cmdoption-e", false]], "-h": [[2, "cmdoption-h", false]], "-m": [[2, "cmdoption-m", false]], "-n": [[2, "cmdoption-n", false]], "-v": [[2, "cmdoption-v", false]], "command line option": [[2, "cmdoption-b", false], [2, "cmdoption-c", false], [2, "cmdoption-d", false], [2, "cmdoption-e", false], [2, "cmdoption-h", false], [2, "cmdoption-m", false], [2, "cmdoption-n", false], [2, "cmdoption-v", false]]}, "objects": {"": [[2, 0, 1, "cmdoption-e", "--author-email", ""], [2, 0, 1, "cmdoption-n", "--author-name", ""], [2, 0, 1, "cmdoption-b", "--branch", ""], [2, 0, 1, "cmdoption-c", "--config", ""], [2, 0, 1, "cmdoption-d", "--dry-run", ""], [2, 0, 1, "cmdoption-h", "--help", ""], [2, 0, 1, "cmdoption-m", "--message", ""], [2, 0, 1, "cmdoption-v", "--version", ""], [2, 0, 1, "cmdoption-b", "-b", ""], [2, 0, 1, "cmdoption-c", "-c", ""], [2, 0, 1, "cmdoption-d", "-d", ""], [2, 0, 1, "cmdoption-e", "-e", ""], [2, 0, 1, "cmdoption-h", "-h", ""], [2, 0, 1, "cmdoption-m", "-m", ""], [2, 0, 1, "cmdoption-n", "-n", ""], [2, 0, 1, "cmdoption-v", "-v", ""]]}, "objnames": {"0": ["std", "cmdoption", "program option"]}, "objtypes": {"0": "std:cmdoption"}, "terms": {"": [0, 2, 4, 6], "0": [2, 4], "1": [4, 5, 6, 7, 8], "10": 4, "12": 7, "123": 4, "2": [4, 5, 6], "232c9ccd": 5, "280": 1, "5": [3, 6], "50": 3, "72": 8, "80": 6, "9": [4, 6, 8], "A": [4, 6, 7, 8], "As": 5, "By": 3, "For": [4, 5], "If": [2, 3], "In": [4, 7], "It": [4, 5, 7], "No": [3, 4, 8], "Not": 6, "Or": [4, 5, 6], "The": [1, 3, 4, 5, 6, 7, 8], "Then": 5, "There": 4, "To": [5, 7], "_": [4, 5], "__": [4, 5], "_build": 0, "abc1234": 4, "abov": [6, 8], "ad": [4, 6], "add": [4, 5, 6], "addit": 3, "after": [6, 8], "aka": 5, "alia": 5, "all": [1, 4], "allow": [3, 4, 5, 8], "allow_branch_nam": 3, "allow_branch_typ": [3, 6, 8], "allow_commit_typ": [3, 6, 8], "allow_empty_commit": [3, 6], "allow_fixup_commit": [3, 6], "allow_merge_commit": [3, 6], "allow_revert_commit": [3, 6], "allow_wip_commit": [3, 6], "along": 8, "alt": 5, "altern": [5, 7], "alwai": [2, 3], "amend": [4, 7], "an": [3, 5, 7], "ani": 1, "anoth": 5, "api": 4, "appli": 3, "ar": [3, 4, 8], "architectur": [1, 5, 6], "around": [1, 6], "arrai": 6, "auth": 4, "authent": 4, "author": [1, 2, 3, 6], "author_email": 6, "author_nam": [6, 7, 8], "automat": [4, 8], "avail": [1, 2, 4], "b": [2, 6, 8], "backup": 6, "bad": 4, "base": [1, 6], "bash": 4, "basic": 4, "been": [1, 6], "befor": [1, 8], "begin": [6, 8], "behavior": [3, 5, 8], "below": [6, 7, 8], "benefit": 8, "better": [6, 8], "big": 1, "bin": 4, "bitbucket": 5, "bodi": [3, 6, 8], "bool": 3, "boolean": [6, 8], "bot": [6, 7, 8], "both": 4, "box": 8, "branch": [1, 2, 3, 5, 6], "branch_nam": [6, 8], "break": 4, "brightgreen": 5, "brows": 0, "browser": 0, "bug": [4, 5], "bugfix": [3, 4, 5, 6, 8], "build": [6, 8], "built": 8, "bypass": [4, 5], "c": [2, 4, 5], "can": [3, 4, 5, 6, 7], "capit": [3, 4], "carefulli": 1, "case": 7, "cat": 4, "catalog": 8, "cchk": [1, 2, 3, 4, 5, 6, 8], "central": 8, "chang": [4, 8], "check": [1, 3, 4, 6, 8], "checker": 5, "checkout": [6, 8], "chore": [3, 4, 5, 6, 8], "ci": [5, 6, 8], "class": 8, "cleaner": [1, 5, 6], "clear": 8, "clearer": [1, 5, 8], "cli": [1, 5, 8], "code": [1, 4, 5, 7], "codebas": 8, "color": 5, "com": [3, 4, 5, 6, 7], "command": [1, 4, 5, 6, 7, 8], "commit": [1, 3, 6, 7], "commit_messag": 4, "commit_signoff": [6, 8], "committ": [4, 5, 6, 7, 8], "common": 8, "comparison": 8, "compat": 1, "complet": [1, 8], "complex": 8, "complianc": [5, 8], "comprehens": 8, "config": [2, 4, 5, 6, 7, 8], "configur": 1, "confirm": 6, "consist": [1, 5, 8], "content": 4, "convent": [3, 4, 5, 6, 8], "conventional_branch": [3, 6, 8], "conventional_commit": [3, 6, 8], "conventionalcommit": [3, 4, 5, 6, 8], "convert": 6, "copilot": 6, "core": 8, "correct": [6, 7], "cp": 6, "creat": [4, 5, 6], "current": [2, 4, 6], "custom": [4, 8], "d": 2, "dco": 8, "dedic": 8, "default": [3, 6, 8], "deliv": 5, "demonstr": 4, "depend": 0, "dependabot": [6, 8], "deploi": 8, "descript": [4, 5, 6, 8], "design": [6, 8], "detail": [5, 6, 8], "detect": 8, "devel": 6, "develop": [3, 6], "devop": 5, "differ": 4, "directli": [4, 5], "directori": [0, 2, 4, 5], "disallow": 4, "do": [0, 4, 5], "doc": [3, 4, 5, 6, 8], "document": [1, 4, 5, 6], "doesn": [4, 5, 7], "done": 4, "dry": [2, 6], "due": 7, "dure": 4, "dynam": 8, "e": [2, 3, 4, 5, 6, 8], "each": 8, "easier": 8, "echo": [4, 6], "edit": 7, "either": 7, "email": [2, 3, 4, 5, 6, 8], "empti": 3, "enabl": 5, "endpoint": 4, "enforc": [3, 5], "engin": [1, 5, 6], "enhanc": [6, 8], "ensur": 6, "enterpris": 5, "environ": 7, "eof": 4, "error": [1, 6, 8], "etc": 6, "everyth": 6, "exampl": 6, "exist": [3, 6], "exit": [2, 4, 7], "expect": 6, "experi": 5, "experienc": 4, "extens": 8, "fail": [2, 4, 5, 7], "failur": 4, "fals": [3, 6], "favor": 1, "feat": [3, 4, 5, 6, 8], "featur": [3, 4, 5, 6, 8], "fi": 4, "file": [0, 1, 2, 3, 4, 5, 6], "fix": [3, 4, 5, 6, 7, 8], "fixup": [3, 4, 5, 6, 8], "flag": [1, 6, 7, 8], "flexibl": [1, 5, 6, 8], "follow": [0, 1, 4, 5, 6, 7, 8], "footer": [3, 6, 8], "forc": 7, "form": 3, "format": [1, 3, 4, 5], "found": [3, 4, 6, 8], "from": [0, 1, 2, 4, 5, 6, 8], "full": [1, 5], "fulli": 5, "function": [4, 6], "g": [3, 4, 5, 6, 8], "get": 4, "git": [2, 4, 5, 6, 7, 8], "github": [1, 3, 5, 6], "gmail": 7, "greater": 5, "guid": [1, 4, 8], "h": [2, 4, 5], "ha": [1, 6, 8], "handl": [4, 8], "have": 1, "head": [3, 4, 5, 6, 8], "help": [4, 5], "highlight": [5, 8], "hook": [1, 5], "hotfix": [3, 4, 5, 6, 8], "how": [4, 8], "html": 0, "http": [3, 4, 5, 6, 8], "i": [3, 4, 5, 6, 8], "iac": 5, "id": [4, 7], "ignor": [3, 8], "ignore_author": [3, 4, 5, 6, 8], "imag": 5, "img": 5, "imper": [1, 3, 4, 6], "implement": 4, "improv": [1, 4, 5], "includ": [5, 6], "incorrect": 6, "increas": 4, "inform": [4, 5], "infrastructur": 5, "initi": 1, "instal": [0, 4, 8], "instruct": [1, 5, 8], "int": 3, "integr": [1, 5], "interfac": [1, 5, 6, 8], "internet": 0, "introduc": [1, 6, 8], "intuit": 8, "invalid": [6, 7, 8], "io": [3, 4, 5, 6], "issu": [4, 5], "just": 4, "k": [4, 5], "kei": 8, "last": [1, 4], "latest": [4, 6, 8], "leak": 4, "legaci": [1, 5], "length": 3, "lenient": 5, "letter": 3, "lightweight": 5, "like": [6, 7], "limit": 3, "line": [1, 3, 4, 5, 6, 8], "list": [3, 5, 8], "load": 8, "log": 4, "login": 4, "logo": 5, "logocolor": 5, "m": [2, 4, 6, 8], "mai": 7, "main": [3, 4, 5, 6, 8], "maintain": [1, 5, 8], "mainten": 8, "major": [1, 5], "make": 4, "manual": 8, "markdown": 5, "master": [3, 4, 5, 6, 8], "match": [4, 5, 6, 7, 8], "maximum": 3, "memori": 4, "merg": [1, 3, 4, 5, 6, 8], "merge_bas": 6, "messag": [2, 3, 5, 6], "metadata": 5, "method": 7, "migrat": 1, "minim": 3, "minimum": 3, "miss": [4, 6], "mit": 5, "modern": 5, "modul": 1, "modular": 8, "mood": [3, 4, 6], "more": [1, 2, 4, 5, 6, 8], "most": 8, "msg": 4, "must": [1, 3, 6, 8], "my": 4, "n": [2, 4, 6, 8], "name": [2, 3, 4, 5, 6], "need": [6, 8], "nest": 8, "new": [4, 6], "non": 4, "none": 3, "notabl": 1, "nox": 0, "number": 2, "o": [4, 5], "oauth2": 4, "off": [3, 4, 6], "old": [1, 6], "one": 7, "onli": [3, 5], "onto": 6, "onward": 1, "open": 5, "option": [1, 2, 4, 5, 6, 8], "orchestr": 8, "org": [3, 4, 5, 6, 8], "otherwis": 2, "out": 8, "output": 0, "overhaul": 8, "page": 5, "paid": 5, "pair": 8, "parser": 4, "pass": 4, "patch": 4, "path": [2, 4], "pattern": 8, "perf": [6, 8], "perform": [2, 3, 5], "pip": [0, 4, 5, 8], "pipe": 4, "pipelin": 4, "place": [3, 6], "pleas": [1, 4, 5, 6, 8], "plugin": 5, "post": 5, "pr": [1, 3, 4, 5, 6, 8], "practic": 5, "pre": [1, 5, 7], "prefix": 4, "principl": [5, 8], "problem": 6, "program": 2, "programmat": 4, "progress": 3, "project": [1, 5, 6], "provid": [4, 5, 8], "pull": 4, "purpos": 8, "py": [1, 3, 8], "quot": 6, "r": [4, 5], "read": [2, 4], "readabl": 8, "rebas": [3, 6], "redesign": [1, 4, 5, 8], "refactor": [3, 4, 5, 6, 8], "refer": [6, 8], "regex": [4, 5, 6, 7, 8], "registr": 4, "reject": [4, 5, 7], "releas": [1, 3, 4, 5, 6], "reli": 1, "remov": [1, 5, 6], "render": 0, "renov": 8, "replac": [1, 5], "repo": 4, "report": [5, 6], "repositori": [0, 3, 6], "repres": 8, "request": [4, 5], "requir": 3, "require_bodi": [3, 6], "require_rebase_target": [3, 6], "require_signed_off_bi": [3, 4, 6, 8], "required_signoff_email": 3, "required_signoff_nam": 3, "resolv": 4, "restrict": [3, 5], "restructur": 1, "restructuredtext": 5, "return": 2, "rev": 4, "revert": [3, 6, 8], "review": 1, "revis": 4, "rm": 6, "root": [0, 3, 5, 6], "rule": [6, 8], "rule_build": 8, "rules_catalog": 8, "run": [2, 5, 6, 7, 8], "scenario": 4, "scope": [4, 5, 6, 8], "search": 2, "section": [3, 4, 5], "secur": 4, "see": [0, 1, 3, 4, 5, 6, 8], "seem": [6, 7, 8], "semant": 5, "sensibl": [3, 8], "session": 4, "set": [3, 7], "sever": [1, 4], "sh": 4, "shen": 7, "shield": 5, "short": 4, "should": [3, 4, 5, 6, 8], "show": [2, 5, 8], "shown": 7, "side": 8, "sign": [3, 4, 6], "signatur": 4, "signific": [1, 6, 8], "signoff": [1, 4, 5, 6, 8], "simpl": 8, "simplifi": [1, 5, 6, 8], "skip": 4, "solid": 8, "solut": 6, "some": [4, 7], "sourc": 5, "special": 8, "specif": [3, 5, 8], "specifi": [2, 7], "stage": [3, 4], "standalon": 3, "standard": [5, 8], "start": 3, "stdin": [2, 4, 5], "step": [0, 1, 8], "str": 3, "streamlin": 5, "string": 6, "structur": [1, 6, 8], "style": [3, 4, 5, 6, 8], "subject": [3, 4], "subject_capit": [3, 6], "subject_imp": [3, 6], "subject_max_length": [3, 6, 8], "subject_min_length": [3, 6], "success": 4, "suggest": [4, 5, 6, 7, 8], "support": [3, 8], "sure": 4, "syntax": [1, 5, 6, 8], "system": [1, 4], "t": [4, 5, 7], "tag": 4, "target": [3, 5, 6], "task": [6, 8], "team": 5, "temporarili": 7, "test": [3, 4, 5, 8], "them": 4, "thi": [1, 2, 4, 5, 6, 8], "thoroughli": 8, "through": 4, "timeout": 4, "toml": [1, 2, 3, 4, 5, 8], "too": 4, "tool": 5, "touch": 6, "transform": 8, "transit": 8, "translat": 8, "trigger": 4, "true": [3, 6, 8], "txt": 4, "type": [3, 4, 5, 6, 7, 8], "u0100": [6, 7, 8], "u017f": [6, 7, 8], "u0180": [6, 7, 8], "u024f": [6, 7, 8], "under": 5, "unknown": 4, "updat": [1, 4, 5, 6, 7, 8], "upgrad": [1, 8], "us": [3, 4, 6, 7, 8], "usabl": 8, "usag": 2, "user": [4, 5, 6, 7], "v": 2, "v1": [4, 8], "valid": [1, 2, 3, 5], "validationengin": 1, "valu": [6, 8], "variabl": 7, "verb": 3, "verifi": 7, "version": [1, 2, 6], "via": [3, 4], "visit": 5, "w": [4, 5, 6, 8], "wai": 4, "were": 4, "when": 3, "whether": [5, 6, 8], "while": 7, "white": 5, "wip": 3, "without": [2, 7], "work": [3, 6], "workflow": 5, "www": [3, 4, 5, 6, 8], "x": 8, "xianpeng": 7, "yaml": [1, 4, 8], "yet": 5, "yml": [1, 5, 6, 8], "you": [4, 5, 6, 7], "your": [0, 3, 4, 6, 7, 8], "yournam": 6, "z0": [4, 6, 8], "za": [4, 6, 7, 8], "z\u00e0": [6, 7, 8], "\u00f6\u00f8": [6, 7, 8], "\u00ff": [6, 7, 8]}, "titles": ["How to build the docs", "Changelog", "commit-check \u2013help", "Configuration", "Usage Examples", "Commit Check", "Migration Guide", "Troubleshooting", "What\u2019s New"], "titleterms": {"": [1, 5, 8], "0": [1, 5, 6, 8], "01": 1, "02": 1, "08": 1, "1": 1, "10": 1, "11": 1, "2": [1, 8], "2022": 1, "2025": 1, "26": 1, "For": 8, "action": 4, "addit": 8, "all": 7, "architectur": 8, "attent": 1, "author": [4, 7, 8], "badg": 5, "branch": [4, 8], "break": 1, "build": 0, "bypass": 7, "cd": 4, "chang": [1, 6], "changelog": 1, "check": [2, 5, 7], "ci": 4, "cli": [4, 6], "commit": [2, 4, 5, 8], "common": 6, "configur": [3, 4, 5, 6, 8], "custom": 5, "default": 5, "descript": 3, "doc": 0, "document": 8, "engin": 8, "error": 4, "exampl": [3, 4, 5, 8], "exist": 8, "feedback": 5, "format": [6, 8], "get": [6, 8], "github": 4, "guid": 6, "have": 5, "help": [2, 6], "hook": [4, 7], "how": [0, 7], "improv": 8, "instal": 5, "integr": 4, "invalid": 4, "issu": 6, "licens": 5, "major": 8, "messag": [4, 8], "migrat": [6, 8], "modul": 8, "name": [7, 8], "new": [1, 5, 8], "off": 8, "option": 3, "organ": 8, "output": 4, "overview": [5, 6, 8], "pre": 4, "question": 5, "quick": 6, "releas": 8, "repositori": 5, "requir": 8, "resourc": 8, "run": 4, "script": 4, "sign": 8, "skip": 7, "specif": 7, "start": 8, "step": 6, "tabl": 3, "test": 6, "tip": [3, 4], "toml": 6, "troubleshoot": [6, 7], "us": 5, "usag": [4, 5], "user": 8, "v": 6, "v0": 1, "v1": 6, "v2": [1, 5, 6, 8], "valid": [4, 6, 8], "version": [5, 8], "what": [1, 5, 8], "x": 6, "yaml": 6, "your": 5}}) \ No newline at end of file diff --git a/tests/config_edge_test.py b/tests/config_edge_test.py deleted file mode 100644 index ccafb4df..00000000 --- a/tests/config_edge_test.py +++ /dev/null @@ -1,80 +0,0 @@ -"""Test for TOML parsing errors and exception handling.""" - -import pytest -import tempfile -import os -from commit_check.config import load_config - - -@pytest.mark.benchmark -def test_load_config_invalid_toml(): - """Test handling of invalid TOML syntax.""" - invalid_toml = b""" -[incomplete -missing closing bracket -""" - with tempfile.NamedTemporaryFile(mode="wb", suffix=".toml", delete=False) as f: - f.write(invalid_toml) - f.flush() - - try: - with pytest.raises(Exception): # Should raise a TOML parsing error - load_config(f.name) - finally: - os.unlink(f.name) - - -@pytest.mark.benchmark -def test_load_config_file_permission_error(): - """Test handling of file permission errors.""" - config_content = b""" -[checks] -test = true -""" - with tempfile.NamedTemporaryFile(mode="wb", suffix=".toml", delete=False) as f: - f.write(config_content) - f.flush() - - try: - # Remove read permissions to simulate permission error - os.chmod(f.name, 0o000) - - with pytest.raises(PermissionError): - load_config(f.name) - finally: - # Restore permissions and clean up - os.chmod(f.name, 0o644) - os.unlink(f.name) - - -@pytest.mark.benchmark -def test_tomli_import_fallback(): - """Test the tomli import fallback when tomllib is not available.""" - # We need to test the import fallback behavior - # This is complex because the imports happen at module load time - - # Create a minimal test by importing the config module's behavior - config_content = b""" -[test] -fallback = true -""" - - with tempfile.NamedTemporaryFile(mode="wb", suffix=".toml", delete=False) as f: - f.write(config_content) - f.flush() - - try: - # Test that we can load config regardless of which TOML library is used - config = load_config(f.name) - assert config["test"]["fallback"] is True - - # Since we can't easily test the import fallback on Python 3.11+, - # let's at least verify that the toml_load function works - from commit_check.config import toml_load - - with open(f.name, "rb") as config_file: - result = toml_load(config_file) - assert result["test"]["fallback"] is True - - finally: - os.unlink(f.name) diff --git a/tests/config_fallback_test.py b/tests/config_fallback_test.py deleted file mode 100644 index 0c6a8e24..00000000 --- a/tests/config_fallback_test.py +++ /dev/null @@ -1,65 +0,0 @@ -"""Direct test of the config import fallback using module manipulation.""" - -import sys -import tempfile -import os -import pytest -from unittest.mock import patch - - -@pytest.mark.benchmark -def test_config_tomli_fallback_direct(): - """Test config.py fallback to tomli by manipulating imports.""" - - # Save original state - original_modules = sys.modules.copy() - - try: - # Remove config module if already imported - if "commit_check.config" in sys.modules: - del sys.modules["commit_check.config"] - - # Make tomllib unavailable by raising ImportError - original_import = __import__ - - def mock_import(name, globals=None, locals=None, fromlist=(), level=0): - if name == "tomllib": - raise ImportError("No module named 'tomllib'") - # For tomli, return a working mock - if name == "tomli": - - class MockTomli: - @staticmethod - def load(f): - content = f.read().decode("utf-8") - # Simple parser for test - if 'test_key = "test_value"' in content: - return {"test_key": "test_value"} - return {} - - return MockTomli() - return original_import(name, globals, locals, fromlist, level) - - with patch("builtins.__import__", side_effect=mock_import): - # Now import config - should use tomli fallback - import commit_check.config as config - - # Test that it works - config_content = b'test_key = "test_value"' - with tempfile.NamedTemporaryFile( - mode="wb", suffix=".toml", delete=False - ) as f: - f.write(config_content) - f.flush() - - try: - with open(f.name, "rb") as config_file: - result = config.toml_load(config_file) - assert result == {"test_key": "test_value"} - finally: - os.unlink(f.name) - - finally: - # Restore original modules - sys.modules.clear() - sys.modules.update(original_modules) diff --git a/tests/config_import_test.py b/tests/config_import_test.py deleted file mode 100644 index 083e84fb..00000000 --- a/tests/config_import_test.py +++ /dev/null @@ -1,94 +0,0 @@ -"""Test import fallback by creating a test version of config.py.""" - -import tempfile -import os -from unittest.mock import patch -import pytest - - -@pytest.mark.benchmark -def test_tomli_import_fallback_simulation(): - """Test tomli import fallback by simulating the ImportError condition.""" - - # Create test code that simulates the config.py import logic - test_code = """ -try: - import tomllib - toml_load = tomllib.load - used_tomllib = True -except ImportError: - import tomli - toml_load = tomli.load - used_tomllib = False -""" - - # Test case 1: Normal case (tomllib available) - namespace1 = {} - exec(test_code, namespace1) - assert namespace1["used_tomllib"] is True - assert callable(namespace1["toml_load"]) - - # Test case 2: Simulate ImportError for tomllib - with patch.dict("sys.modules", {"tomllib": None}): - with patch( - "builtins.__import__", - side_effect=lambda name, *args, **kwargs: _mock_import_error( - name, *args, **kwargs - ), - ): - namespace2 = {} - exec(test_code, namespace2) - assert namespace2["used_tomllib"] is False - assert callable(namespace2["toml_load"]) - - -def _mock_import_error(name, *args, **kwargs): - """Mock import function that raises ImportError for tomllib.""" - if name == "tomllib": - raise ImportError("No module named 'tomllib'") - - # For tomli, we need to mock it since it might not be installed - if name == "tomli": - # Create a mock tomli module - class MockTomli: - @staticmethod - def load(f): - # Simple TOML parser for testing - content = f.read().decode("utf-8") - if "[test]" in content and 'value = "test"' in content: - return {"test": {"value": "test"}} - return {} - - return MockTomli() - - # For all other imports, use the real import - return __import__(name, *args, **kwargs) - - -@pytest.mark.benchmark -def test_import_paths_coverage(): - """Ensure both import paths are conceptually tested.""" - # This test verifies that both the tomllib and tomli code paths - # would work in their respective environments - - # Test the function signature matches expectation - config_content = b""" -[test] -value = "test" -""" - - with tempfile.NamedTemporaryFile(mode="wb", suffix=".toml", delete=False) as f: - f.write(config_content) - f.flush() - - try: - # Test using the actual config module (uses tomllib on Python 3.11+) - from commit_check.config import toml_load - - with open(f.name, "rb") as config_file: - result = toml_load(config_file) - - assert result == {"test": {"value": "test"}} - - finally: - os.unlink(f.name) diff --git a/tests/config_test.py b/tests/config_test.py deleted file mode 100644 index fb2d5259..00000000 --- a/tests/config_test.py +++ /dev/null @@ -1,206 +0,0 @@ -"""Tests for commit_check.config module.""" - -import pytest -import tempfile -import os -from pathlib import Path -from unittest.mock import patch -from commit_check.config import load_config, DEFAULT_CONFIG_PATHS - - -class TestConfig: - @pytest.mark.benchmark - def test_load_config_with_path_hint(self): - """Test loading config with explicit path hint.""" - config_content = b""" -[checks] -message = true -branch = true -""" - with tempfile.NamedTemporaryFile(mode="wb", suffix=".toml", delete=False) as f: - f.write(config_content) - f.flush() - - try: - config = load_config(f.name) - assert "checks" in config - assert config["checks"]["message"] is True - assert config["checks"]["branch"] is True - finally: - os.unlink(f.name) - - @pytest.mark.benchmark - def test_load_config_with_nonexistent_path_hint(self): - """Test loading config when path hint doesn't exist - should raise FileNotFoundError.""" - # Test that specifying a nonexistent config file raises an error - with pytest.raises( - FileNotFoundError, match="Specified config file not found: nonexistent.toml" - ): - load_config("nonexistent.toml") - - @pytest.mark.benchmark - def test_load_config_default_cchk_toml(self): - """Test loading config from default cchk.toml path.""" - config_content = b""" -[checks] -default_cchk = true -""" - original_cwd = os.getcwd() - with tempfile.TemporaryDirectory() as tmpdir: - os.chdir(tmpdir) - try: - with open("cchk.toml", "wb") as f: - f.write(config_content) - - config = load_config() - assert "checks" in config - assert config["checks"]["default_cchk"] is True - finally: - os.chdir(original_cwd) - - @pytest.mark.benchmark - def test_load_config_default_commit_check_toml(self): - """Test loading config from default commit-check.toml path.""" - config_content = b""" -[checks] -commit_check_toml = true -""" - original_cwd = os.getcwd() - with tempfile.TemporaryDirectory() as tmpdir: - os.chdir(tmpdir) - try: - with open("commit-check.toml", "wb") as f: - f.write(config_content) - - config = load_config() - assert "checks" in config - assert config["checks"]["commit_check_toml"] is True - finally: - os.chdir(original_cwd) - - @pytest.mark.benchmark - def test_load_config_file_not_found(self): - """Test returning empty config when no default config files exist.""" - original_cwd = os.getcwd() - with tempfile.TemporaryDirectory() as tmpdir: - os.chdir(tmpdir) - try: - # Should return empty config when no default files exist - config = load_config() - assert config == {} - finally: - os.chdir(original_cwd) - - @pytest.mark.benchmark - def test_load_config_file_not_found_with_invalid_path_hint(self): - """Test FileNotFoundError when specified path hint doesn't exist.""" - original_cwd = os.getcwd() - with tempfile.TemporaryDirectory() as tmpdir: - os.chdir(tmpdir) - try: - with pytest.raises( - FileNotFoundError, - match="Specified config file not found: nonexistent.toml", - ): - load_config("nonexistent.toml") - finally: - os.chdir(original_cwd) - - @pytest.mark.benchmark - def test_default_config_paths_constant(self): - """Test that DEFAULT_CONFIG_PATHS contains expected paths.""" - assert len(DEFAULT_CONFIG_PATHS) == 2 - assert Path("cchk.toml") in DEFAULT_CONFIG_PATHS - assert Path("commit-check.toml") in DEFAULT_CONFIG_PATHS - - @pytest.mark.benchmark - def test_toml_load_function_exists(self): - """Test that toml_load function is properly set up.""" - from commit_check.config import toml_load - - assert callable(toml_load) - - # Test that it can actually parse TOML content - config_content = b""" -[test] -value = "works" -""" - with tempfile.NamedTemporaryFile(mode="wb", suffix=".toml", delete=False) as f: - f.write(config_content) - f.flush() - - try: - with open(f.name, "rb") as config_file: - result = toml_load(config_file) - assert result == {"test": {"value": "works"}} - finally: - os.unlink(f.name) - - @pytest.mark.benchmark - def test_tomli_import_fallback(self): - """Test that tomli is imported when tomllib is not available (lines 10-13).""" - import sys - - # Save original modules - original_tomllib = sys.modules.get("tomllib") - original_config = sys.modules.get("commit_check.config") - - try: - # Remove modules from cache to force fresh import - if "tomllib" in sys.modules: - del sys.modules["tomllib"] - if "commit_check.config" in sys.modules: - del sys.modules["commit_check.config"] - - # Mock tomllib module to not exist - with patch.dict("sys.modules", {"tomllib": None}): - # Force import error by patching __import__ for tomllib specifically - original_import = __builtins__["__import__"] - - def mock_import(name, *args, **kwargs): - if name == "tomllib": - raise ImportError("No module named 'tomllib'") - # For tomli, return a working mock - if name == "tomli": - - class MockTomli: - @staticmethod - def load(f): - content = f.read().decode("utf-8") - # Simple parser for test - if '[test]\nvalue = "tomli_works"' in content: - return {"test": {"value": "tomli_works"}} - return {} - - return MockTomli() - return original_import(name, *args, **kwargs) - - with patch("builtins.__import__", side_effect=mock_import): - # Import the config module - should use tomli fallback - import commit_check.config as config_module - - # Verify that the module loaded successfully - assert hasattr(config_module, "toml_load") - assert callable(config_module.toml_load) - - # Test that it can actually parse TOML content - config_content = b'[test]\nvalue = "tomli_works"\n' - with tempfile.NamedTemporaryFile( - mode="wb", suffix=".toml", delete=False - ) as f: - f.write(config_content) - f.flush() - - try: - with open(f.name, "rb") as config_file: - result = config_module.toml_load(config_file) - assert result == {"test": {"value": "tomli_works"}} - finally: - os.unlink(f.name) - - finally: - # Restore original modules - if original_tomllib is not None: - sys.modules["tomllib"] = original_tomllib - if original_config is not None: - sys.modules["commit_check.config"] = original_config diff --git a/tests/engine_comprehensive_test.py b/tests/engine_comprehensive_test.py deleted file mode 100644 index b01a8951..00000000 --- a/tests/engine_comprehensive_test.py +++ /dev/null @@ -1,322 +0,0 @@ -"""Comprehensive tests for commit_check.engine module.""" - -from unittest.mock import patch -from commit_check.engine import ( - ValidationResult, - ValidationContext, - ValidationEngine, - CommitMessageValidator, - SubjectCapitalizationValidator, - SubjectImperativeValidator, - SubjectLengthValidator, - AuthorValidator, - BranchValidator, - MergeBaseValidator, - SignoffValidator, - BodyValidator, - CommitTypeValidator, -) -from commit_check.rule_builder import ValidationRule -import pytest - - -class TestValidationResult: - @pytest.mark.benchmark - def test_validation_result_values(self): - """Test ValidationResult enum values.""" - assert ValidationResult.PASS == 0 - assert ValidationResult.FAIL == 1 - - -class TestValidationContext: - @pytest.mark.benchmark - def test_validation_context_creation(self): - """Test ValidationContext creation.""" - context = ValidationContext() - assert context.stdin_text is None - assert context.commit_file is None - - context_with_data = ValidationContext( - stdin_text="test commit", commit_file="commit.txt" - ) - assert context_with_data.stdin_text == "test commit" - assert context_with_data.commit_file == "commit.txt" - - -class TestCommitMessageValidator: - @pytest.mark.benchmark - def test_commit_message_validator_creation(self): - """Test CommitMessageValidator creation.""" - rule = ValidationRule( - check="message", - regex="^(feat|fix):", - error="Invalid commit message", - suggest="Use conventional format", - ) - validator = CommitMessageValidator(rule) - assert validator.rule == rule - - @patch("commit_check.engine.has_commits") - @pytest.mark.benchmark - def test_commit_message_validator_with_stdin(self, mock_has_commits): - """Test CommitMessageValidator with stdin text.""" - mock_has_commits.return_value = True - - rule = ValidationRule( - check="message", - regex="^(feat|fix):", - error="Invalid commit message", - suggest="Use conventional format", - ) - validator = CommitMessageValidator(rule) - context = ValidationContext(stdin_text="feat: add new feature") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @patch("commit_check.engine.get_commit_info") - @patch("commit_check.engine.has_commits") - @pytest.mark.benchmark - def test_commit_message_validator_failure( - self, mock_has_commits, mock_get_commit_info - ): - """Test CommitMessageValidator failure case.""" - mock_has_commits.return_value = True - - rule = ValidationRule( - check="message", - regex="^(feat|fix):", - error="Invalid commit message", - suggest="Use conventional format", - ) - validator = CommitMessageValidator(rule) - context = ValidationContext(stdin_text="bad commit message") - - with patch.object(validator, "_print_failure") as mock_print: - result = validator.validate(context) - assert result == ValidationResult.FAIL - mock_print.assert_called_once() - - @patch("commit_check.engine.has_commits") - @pytest.mark.benchmark - def test_commit_message_validator_skip_validation(self, mock_has_commits): - """Test CommitMessageValidator skips when no commits and no stdin.""" - mock_has_commits.return_value = False - - rule = ValidationRule( - check="message", - regex="^(feat|fix):", - error="Invalid commit message", - suggest="Use conventional format", - ) - validator = CommitMessageValidator(rule) - context = ValidationContext() # No stdin_text - - result = validator.validate(context) - assert result == ValidationResult.PASS - - -class TestSubjectCapitalizationValidator: - @pytest.mark.benchmark - def test_subject_capitalization_pass(self): - """Test SubjectCapitalizationValidator pass case.""" - rule = ValidationRule( - check="subject_capitalized", - regex="^[A-Z]", - error="Subject must be capitalized", - suggest="Capitalize first letter", - ) - validator = SubjectCapitalizationValidator(rule) - # Use conventional commit format with capitalized description - context = ValidationContext(stdin_text="feat: Add new feature") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_subject_capitalization_fail(self): - """Test SubjectCapitalizationValidator fail case.""" - rule = ValidationRule( - check="subject_capitalized", - regex="^[A-Z]", - error="Subject must be capitalized", - suggest="Capitalize first letter", - ) - validator = SubjectCapitalizationValidator(rule) - # Use conventional commit format with lowercase description - context = ValidationContext(stdin_text="feat: add new feature") - - with patch.object(validator, "_print_failure") as mock_print: - result = validator.validate(context) - assert result == ValidationResult.FAIL - mock_print.assert_called_once() - - -class TestSubjectImperativeValidator: - @pytest.mark.benchmark - def test_subject_imperative_pass(self): - """Test SubjectImperativeValidator pass case.""" - rule = ValidationRule( - check="subject_imperative", - regex="", - error="Subject must be imperative", - suggest="Use imperative mood", - ) - validator = SubjectImperativeValidator(rule) - # Use conventional commit with imperative verb "add" - context = ValidationContext(stdin_text="feat: add new feature") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_subject_imperative_fail(self): - """Test SubjectImperativeValidator fail case.""" - rule = ValidationRule( - check="subject_imperative", - regex="", - error="Subject must be imperative", - suggest="Use imperative mood", - ) - validator = SubjectImperativeValidator(rule) - # Use past tense "added" which is not imperative - context = ValidationContext(stdin_text="feat: added new feature") - - with patch.object(validator, "_print_failure") as mock_print: - result = validator.validate(context) - assert result == ValidationResult.FAIL - mock_print.assert_called_once() - - -class TestSubjectLengthValidator: - @pytest.mark.benchmark - def test_subject_length_pass(self): - """Test SubjectLengthValidator pass case.""" - rule = ValidationRule( - check="subject_max_length", - regex="", - error="Subject too long", - suggest="Keep subject short", - value=50, - ) - validator = SubjectLengthValidator(rule) - context = ValidationContext(stdin_text="Add feature") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_subject_length_fail(self): - """Test SubjectLengthValidator fail case.""" - rule = ValidationRule( - check="subject_max_length", - regex="", - error="Subject too long: max 10 characters", - suggest="Keep subject short", - value=10, - ) - validator = SubjectLengthValidator(rule) - context = ValidationContext(stdin_text="This is a very long subject line") - - with patch.object(validator, "_print_failure") as mock_print: - result = validator.validate(context) - assert result == ValidationResult.FAIL - mock_print.assert_called_once() - - -class TestValidationEngine: - @pytest.mark.benchmark - def test_validation_engine_creation(self): - """Test ValidationEngine creation.""" - rules = [ - ValidationRule( - check="message", - regex="^(feat|fix):", - error="Invalid commit message", - suggest="Use conventional format", - ) - ] - engine = ValidationEngine(rules) - assert engine.rules == rules - - @pytest.mark.benchmark - def test_validation_engine_validator_map(self): - """Test ValidationEngine VALIDATOR_MAP contains expected mappings.""" - engine = ValidationEngine([]) - - expected_mappings = { - "message": CommitMessageValidator, - "subject_capitalized": SubjectCapitalizationValidator, - "subject_imperative": SubjectImperativeValidator, - "subject_max_length": SubjectLengthValidator, - "subject_min_length": SubjectLengthValidator, - "author_name": AuthorValidator, - "author_email": AuthorValidator, - "branch": BranchValidator, - "merge_base": MergeBaseValidator, - "require_signed_off_by": SignoffValidator, - "require_body": BodyValidator, - "allow_merge_commits": CommitTypeValidator, - "allow_revert_commits": CommitTypeValidator, - "allow_empty_commits": CommitTypeValidator, - "allow_fixup_commits": CommitTypeValidator, - "allow_wip_commits": CommitTypeValidator, - "ignore_authors": CommitTypeValidator, - } - - for check, validator_class in expected_mappings.items(): - assert engine.VALIDATOR_MAP[check] == validator_class - - @pytest.mark.benchmark - def test_validation_engine_validate_all_pass(self): - """Test ValidationEngine validate_all with all passing rules.""" - rules = [ - ValidationRule( - check="message", - regex="^(feat|fix):", - error="Invalid commit message", - suggest="Use conventional format", - ) - ] - engine = ValidationEngine(rules) - context = ValidationContext(stdin_text="feat: add new feature") - - with patch("commit_check.engine.has_commits", return_value=True): - result = engine.validate_all(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validation_engine_validate_all_fail(self): - """Test ValidationEngine validate_all with failing rule.""" - rules = [ - ValidationRule( - check="message", - regex="^(feat|fix):", - error="Invalid commit message", - suggest="Use conventional format", - ) - ] - engine = ValidationEngine(rules) - context = ValidationContext(stdin_text="bad commit message") - - with patch("commit_check.engine.has_commits", return_value=True): - result = engine.validate_all(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validation_engine_unknown_validator(self): - """Test ValidationEngine with unknown validator type.""" - rules = [ - ValidationRule( - check="unknown_check", - regex="", - error="Unknown error", - suggest="Unknown suggest", - ) - ] - engine = ValidationEngine(rules) - context = ValidationContext(stdin_text="test") - - # Should skip unknown validators and continue - result = engine.validate_all(context) - assert result == ValidationResult.PASS diff --git a/tests/engine_test.py b/tests/engine_test.py deleted file mode 100644 index 416b5785..00000000 --- a/tests/engine_test.py +++ /dev/null @@ -1,923 +0,0 @@ -"""Tests for commit_check.engine module.""" - -import pytest -import tempfile -import os -from unittest.mock import mock_open, patch -from commit_check.engine import ( - ValidationResult, - ValidationContext, - BaseValidator, - ValidationEngine, - CommitMessageValidator, - BranchValidator, - AuthorValidator, - CommitTypeValidator, - SubjectImperativeValidator, - SubjectLengthValidator, - SignoffValidator, - SubjectCapitalizationValidator, - BodyValidator, - MergeBaseValidator, -) -from commit_check.rule_builder import ValidationRule - - -class TestValidationResult: - @pytest.mark.benchmark - def test_validation_result_enum(self): - """Test ValidationResult enum values.""" - assert ValidationResult.PASS.value == 0 - assert ValidationResult.FAIL.value == 1 - - -class TestValidationContext: - @pytest.mark.benchmark - def test_validation_context_creation(self): - """Test ValidationContext creation and properties.""" - context = ValidationContext( - stdin_text="test message", commit_file="/path/to/commit" - ) - assert context.stdin_text == "test message" - assert context.commit_file == "/path/to/commit" - - @pytest.mark.benchmark - def test_validation_context_defaults(self): - """Test ValidationContext with default values.""" - context = ValidationContext() - assert context.stdin_text is None - assert context.commit_file is None - - -class TestBaseValidator: - @pytest.mark.benchmark - def test_base_validator_is_abstract(self): - """Test that BaseValidator cannot be instantiated directly.""" - with pytest.raises(TypeError): - BaseValidator() - - -class TestCommitMessageValidator: - @pytest.mark.benchmark - def test_commit_message_validator_valid_conventional_commit(self): - """Test CommitMessageValidator with valid conventional commit.""" - rule = ValidationRule( - check="message", - regex=r"^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .+", - ) - validator = CommitMessageValidator(rule) - context = ValidationContext(stdin_text="feat: add new feature") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_commit_message_validator_invalid_commit(self): - """Test CommitMessageValidator with invalid commit message.""" - rule = ValidationRule( - check="message", - regex=r"^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .+", - ) - validator = CommitMessageValidator(rule) - context = ValidationContext(stdin_text="invalid commit message") - - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_commit_message_validator_with_file(self): - """Test CommitMessageValidator reading from file.""" - rule = ValidationRule(check="message", regex=r"^(feat|fix):") - validator = CommitMessageValidator(rule) - - with tempfile.NamedTemporaryFile(mode="w", delete=False) as f: - f.write("fix: resolve issue") - f.flush() - - try: - context = ValidationContext(commit_file=f.name) - result = validator.validate(context) - assert result == ValidationResult.PASS - finally: - os.unlink(f.name) - - @patch("commit_check.engine.get_commit_info") - @pytest.mark.benchmark - def test_commit_message_validator_file_not_found(self, mock_get_commit_info): - """Test CommitMessageValidator with non-existent file.""" - # Mock git fallback to return a message that doesn't match regex - mock_get_commit_info.side_effect = lambda format_str: { - "s": "invalid commit message", - "b": "", - "an": "author", - }[format_str] - - rule = ValidationRule(check="message", regex=r"^feat:") - validator = CommitMessageValidator(rule) - context = ValidationContext(commit_file="/nonexistent/file") - - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @patch("commit_check.engine.get_commit_info") - @pytest.mark.benchmark - def test_commit_message_validator_from_git(self, mock_get_commit_info): - """Test CommitMessageValidator reading from git.""" - # Mock both subject ("s") and body ("b") calls - mock_get_commit_info.side_effect = lambda format_str: { - "s": "feat: add feature from git", - "b": "", - }.get(format_str, "") - - rule = ValidationRule(check="message", regex=r"^feat:") - validator = CommitMessageValidator(rule) - context = ValidationContext() - - result = validator.validate(context) - assert result == ValidationResult.PASS - # Should call get_commit_info three times: subject, body, and author - assert mock_get_commit_info.call_count == 3 - - -class TestBranchValidator: - @patch("commit_check.engine.has_commits") - @patch("commit_check.engine.get_branch_name") - @pytest.mark.benchmark - def test_branch_validator_valid_branch( - self, mock_get_branch_name, mock_has_commits - ): - """Test BranchValidator with valid branch name.""" - mock_has_commits.return_value = True - mock_get_branch_name.return_value = "feature/new-feature" - rule = ValidationRule(check="branch", regex=r"^(feature|bugfix|hotfix)/.+") - validator = BranchValidator(rule) - config = {"branch": {"ignore_authors": ["ignored"]}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.PASS - assert result == ValidationResult.PASS - assert result == ValidationResult.PASS - - @patch("commit_check.engine.has_commits") - @patch("commit_check.engine.get_branch_name") - @pytest.mark.benchmark - def test_branch_validator_invalid_branch( - self, mock_get_branch_name, mock_has_commits - ): - """Test BranchValidator with invalid branch name.""" - mock_has_commits.return_value = True - mock_get_branch_name.return_value = "invalid-branch-name" - rule = ValidationRule(check="branch", regex=r"^(feature|bugfix|hotfix)/.+") - validator = BranchValidator(rule) - config = {"branch": {"ignore_authors": ["ignored"]}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @patch("commit_check.engine.get_branch_name") - @patch("commit_check.engine.get_commit_info") - @pytest.mark.benchmark - def test_branch_validator_ignored_author( - self, mock_get_commit_info, mock_get_branch_name - ): - """Test BranchValidator skips validation for ignored author.""" - mock_get_branch_name.return_value = "invalid-branch-name" - mock_get_commit_info.return_value = "ignored" - rule = ValidationRule(check="branch", regex=r"^(feature|bugfix|hotfix)/.+") - validator = BranchValidator(rule) - config = {"branch": {"ignore_authors": ["ignored"]}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_with_stdin_text(self): - """Test branch validation with stdin_text.""" - rule = ValidationRule(check="branch", regex=r"^feature/") - validator = BranchValidator(rule) - context = ValidationContext(stdin_text="feature/new-feature") - - validator.validate(context) - - @patch("commit_check.engine.has_commits") - @patch("commit_check.engine.get_branch_name") - @pytest.mark.benchmark - def test_branch_validator_develop_branch_allowed( - self, mock_get_branch_name, mock_has_commits - ): - """Test BranchValidator with develop branch when it's in allow_branch_names.""" - mock_has_commits.return_value = True - mock_get_branch_name.return_value = "develop" - # Regex pattern that includes develop as an allowed branch name - rule = ValidationRule( - check="branch", - regex=r"^(feature|bugfix|hotfix)\/.+|(master)|(main)|(HEAD)|(PR-.+)|(develop)", - ) - validator = BranchValidator(rule) - config = {"branch": {"ignore_authors": []}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.PASS - - @patch("commit_check.engine.has_commits") - @patch("commit_check.engine.get_branch_name") - @pytest.mark.benchmark - def test_branch_validator_staging_branch_allowed( - self, mock_get_branch_name, mock_has_commits - ): - """Test BranchValidator with staging branch when it's in allow_branch_names.""" - mock_has_commits.return_value = True - mock_get_branch_name.return_value = "staging" - # Regex pattern that includes staging as an allowed branch name - rule = ValidationRule( - check="branch", - regex=r"^(feature|bugfix|hotfix)\/.+|(master)|(main)|(HEAD)|(PR-.+)|(staging)|(develop)", - ) - validator = BranchValidator(rule) - config = {"branch": {"ignore_authors": []}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.PASS - - @patch("commit_check.engine.has_commits") - @patch("commit_check.engine.get_branch_name") - @pytest.mark.benchmark - def test_branch_validator_develop_branch_not_allowed( - self, mock_get_branch_name, mock_has_commits - ): - """Test BranchValidator with develop branch when it's NOT in allow_branch_names.""" - mock_has_commits.return_value = True - mock_get_branch_name.return_value = "develop" - # Regex pattern that does NOT include develop as an allowed branch name - rule = ValidationRule( - check="branch", - regex=r"^(feature|bugfix|hotfix)\/.+|(master)|(main)|(HEAD)|(PR-.+)", - ) - validator = BranchValidator(rule) - config = {"branch": {"ignore_authors": []}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validate_without_regex(self): - """Test branch validation without regex (should pass).""" - rule = ValidationRule(check="branch") - validator = BranchValidator(rule) - context = ValidationContext() - - result = validator.validate(context) - assert result == ValidationResult.PASS - - -class TestAuthorValidator: - @patch("commit_check.engine.has_commits") - @patch("commit_check.engine.get_commit_info") - @pytest.mark.benchmark - def test_author_validator_name_valid(self, mock_get_commit_info, mock_has_commits): - """Test AuthorValidator for author name.""" - mock_has_commits.return_value = True - mock_get_commit_info.return_value = "John Doe" - rule = ValidationRule(check="author_name", regex=r"^[A-Z][a-z]+ [A-Z][a-z]+$") - validator = AuthorValidator(rule) - config = {"commit": {"ignore_authors": ["ignored"]}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.PASS - - @patch("commit_check.engine.has_commits") - @patch("commit_check.engine.get_commit_info") - @pytest.mark.benchmark - def test_author_validator_email_valid(self, mock_get_commit_info, mock_has_commits): - """Test AuthorValidator for author email.""" - mock_has_commits.return_value = True - mock_get_commit_info.return_value = "john.doe@example.com" - rule = ValidationRule( - check="author_email", - regex=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", - ) - validator = AuthorValidator(rule) - config = {"commit": {"ignore_authors": ["ignored"]}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.PASS - # Called once for skip logic ("an"), once for value ("ae") - assert mock_get_commit_info.call_count == 2 - assert mock_get_commit_info.call_args_list[0][0][0] == "an" - assert mock_get_commit_info.call_args_list[1][0][0] == "ae" - assert result == ValidationResult.PASS - # Called once for skip logic ("an"), once for value ("ae") - assert mock_get_commit_info.call_count == 2 - assert mock_get_commit_info.call_args_list[0][0][0] == "an" - assert mock_get_commit_info.call_args_list[1][0][0] == "ae" - - @patch("commit_check.engine.get_commit_info") - @pytest.mark.benchmark - def test_author_validator_ignored_author(self, mock_get_commit_info): - """Test AuthorValidator skips validation for ignored author.""" - mock_get_commit_info.return_value = "ignored" - rule = ValidationRule(check="author_name", regex=r"^[A-Z][a-z]+ [A-Z][a-z]+$") - validator = AuthorValidator(rule) - config = {"commit": {"ignore_authors": ["ignored"]}} - context = ValidationContext(config=config) - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_author_with_allowed_list(self): - """Test author validation with allowed list.""" - rule = ValidationRule(check="author_name", allowed=["John Doe", "Jane Smith"]) - validator = AuthorValidator(rule) - - # Mock author value - with patch.object(validator, "_get_author_value", return_value="John Doe"): - context = ValidationContext() - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_author_not_in_allowed_list(self): - """Test author validation with name not in allowed list.""" - rule = ValidationRule(check="author_name", allowed=["John Doe", "Jane Smith"]) - validator = AuthorValidator(rule) - - # Mock author value and print function - with patch.object(validator, "_get_author_value", return_value="Unknown User"): - with patch("commit_check.util._print_failure"): - context = ValidationContext() - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validate_author_in_ignored_list(self): - """Test author validation with ignored authors.""" - rule = ValidationRule(check="author_name", ignored=["Bot User", "CI User"]) - validator = AuthorValidator(rule) - - # Mock author value - with patch.object(validator, "_get_author_value", return_value="Bot User"): - context = ValidationContext() - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_get_author_value_with_email_format(self): - """Test _get_author_value with email format.""" - rule = ValidationRule(check="author_email") - validator = AuthorValidator(rule) - context = ValidationContext() - - with patch( - "commit_check.engine.get_commit_info", return_value="test@example.com" - ): - author_value = validator._get_author_value(context) - assert author_value == "test@example.com" - - -class TestCommitTypeValidator: - @pytest.mark.benchmark - def test_commit_type_validator_merge_commits(self): - """Test CommitTypeValidator with merge commits.""" - rule = ValidationRule(check="allow_merge_commits", value=True) - validator = CommitTypeValidator(rule) - context = ValidationContext(stdin_text="Merge branch 'feature' into main") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_commit_type_validator_revert_commits(self): - """Test CommitTypeValidator with revert commits.""" - rule = ValidationRule(check="allow_revert_commits", value=True) - validator = CommitTypeValidator(rule) - context = ValidationContext(stdin_text='Revert "feat: add feature"') - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_merge_commit_allowed(self): - """Test merge commit validation when allowed.""" - rule = ValidationRule(check="allow_merge_commits", value=True) - validator = CommitTypeValidator(rule) - context = ValidationContext() - - with patch("commit_check.engine.get_commit_info") as mock_get_info: - mock_get_info.side_effect = lambda x: { - "s": "Merge branch 'feature'", - "b": "", - "an": "test-author", - }[x] - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_merge_commit_not_allowed(self): - """Test merge commit validation when not allowed.""" - rule = ValidationRule(check="allow_merge_commits", value=False) - validator = CommitTypeValidator(rule) - context = ValidationContext() - - with patch("commit_check.engine.get_commit_info") as mock_get_info: - mock_get_info.side_effect = lambda x: { - "s": "Merge branch 'feature'", - "b": "", - "an": "test-author", - }[x] - - with patch("commit_check.util._print_failure"): - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validate_revert_commit_allowed(self): - """Test revert commit validation when allowed.""" - rule = ValidationRule(check="allow_revert_commits", value=True) - validator = CommitTypeValidator(rule) - context = ValidationContext() - - with patch("commit_check.engine.get_commit_info") as mock_get_info: - mock_get_info.side_effect = lambda x: { - "s": "Revert 'bad commit'", - "b": "", - "an": "test-author", - }[x] - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_fixup_commit_not_allowed(self): - """Test fixup commit validation when not allowed.""" - rule = ValidationRule(check="allow_fixup_commits", value=False) - validator = CommitTypeValidator(rule) - context = ValidationContext() - - with patch("commit_check.engine.get_commit_info") as mock_get_info: - mock_get_info.side_effect = lambda x: { - "s": "fixup! fix bug", - "b": "", - "an": "test-author", - }[x] - - with patch("commit_check.util._print_failure"): - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validate_wip_commit_allowed(self): - """Test WIP commit validation when allowed.""" - rule = ValidationRule(check="allow_wip_commits", value=True) - validator = CommitTypeValidator(rule) - context = ValidationContext() - - with patch("commit_check.engine.get_commit_info") as mock_get_info: - mock_get_info.side_effect = lambda x: { - "s": "WIP: work in progress", - "b": "", - "an": "test-author", - }[x] - - result = validator.validate(context) - assert result == ValidationResult.PASS - - -class TestSubjectLengthValidator: - @pytest.mark.benchmark - def test_subject_length_validator_max_valid(self): - """Test SubjectLengthValidator with valid max length.""" - rule = ValidationRule(check="subject_max_length", value=50) - validator = SubjectLengthValidator(rule) - context = ValidationContext(stdin_text="feat: short message") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_subject_length_validator_max_too_long(self): - """Test SubjectLengthValidator with message too long.""" - rule = ValidationRule(check="subject_max_length", value=20) - validator = SubjectLengthValidator(rule) - context = ValidationContext( - stdin_text="feat: this is a very long commit message that exceeds the limit" - ) - - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_subject_length_validator_min_valid(self): - """Test SubjectLengthValidator with valid min length.""" - rule = ValidationRule(check="subject_min_length", value=10) - validator = SubjectLengthValidator(rule) - context = ValidationContext(stdin_text="feat: add feature") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_subject_length_validator_min_too_short(self): - """Test SubjectLengthValidator with message too short.""" - rule = ValidationRule(check="subject_min_length", value=20) - validator = SubjectLengthValidator(rule) - context = ValidationContext(stdin_text="feat: fix") - - result = validator.validate(context) - assert result == ValidationResult.FAIL - - -class TestSignoffValidator: - @pytest.mark.benchmark - def test_signoff_validator_valid(self): - """Test SignoffValidator with valid signoff.""" - rule = ValidationRule( - check="require_signed_off_by", regex=r"Signed-off-by: .+ <.+@.+\..+>" - ) - validator = SignoffValidator(rule) - context = ValidationContext( - stdin_text="feat: add feature\n\nSigned-off-by: John Doe " - ) - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_signoff_validator_missing_signoff(self): - """Test SignoffValidator with missing signoff.""" - rule = ValidationRule(check="require_signed_off_by") - validator = SignoffValidator(rule) - context = ValidationContext(stdin_text="feat: add feature") - - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validate_with_signoff_in_stdin(self): - """Test signoff validation with stdin message containing signoff.""" - rule = ValidationRule(check="require_signed_off_by", regex=r".*Signed-off-by.*") - validator = SignoffValidator(rule) - context = ValidationContext( - stdin_text="feat: add feature\n\nSigned-off-by: John Doe " - ) - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_without_signoff(self): - """Test signoff validation without signoff.""" - rule = ValidationRule(check="require_signed_off_by") - validator = SignoffValidator(rule) - context = ValidationContext(stdin_text="feat: add feature") - - with patch("commit_check.util._print_failure"): - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_get_commit_message_from_context_file(self): - """Test _get_commit_message with commit_file.""" - rule = ValidationRule(check="require_signed_off_by") - validator = SignoffValidator(rule) - context = ValidationContext(commit_file="dummy") - - with patch("commit_check.engine.get_commit_info") as mock_get_info: - mock_get_info.side_effect = lambda x: {"s": "test message", "b": ""}[x] - message = validator._get_commit_message(context) - assert message == "test message" - - -class TestSubjectCapitalizationValidator: - @pytest.mark.benchmark - def test_subject_capitalization_validator_valid(self): - """Test SubjectCapitalizationValidator with capitalized subject.""" - rule = ValidationRule(check="subject_capitalized") - validator = SubjectCapitalizationValidator(rule) - context = ValidationContext(stdin_text="feat: Add new feature") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_subject_capitalization_validator_not_capitalized(self): - """Test SubjectCapitalizationValidator with non-capitalized subject.""" - rule = ValidationRule(check="subject_capitalized") - validator = SubjectCapitalizationValidator(rule) - context = ValidationContext(stdin_text="feat: add new feature") - - result = validator.validate(context) - assert result == ValidationResult.FAIL - - -class TestBodyValidator: - @pytest.mark.benchmark - def test_body_validator_with_body(self): - """Test BodyValidator with commit body.""" - rule = ValidationRule(check="require_body") - validator = BodyValidator(rule) - context = ValidationContext( - stdin_text="feat: add feature\n\nThis is the commit body" - ) - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_body_validator_no_body(self): - """Test BodyValidator without commit body.""" - rule = ValidationRule(check="require_body") - validator = BodyValidator(rule) - context = ValidationContext(stdin_text="feat: add feature") - - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validate_with_body_present(self): - """Test body validation with body present.""" - rule = ValidationRule(check="require_body") - validator = BodyValidator(rule) - context = ValidationContext(stdin_text="feat: add feature\n\nThis is the body") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_with_empty_lines_and_body(self): - """Test body validation with empty lines before body.""" - rule = ValidationRule(check="require_body") - validator = BodyValidator(rule) - context = ValidationContext( - stdin_text="feat: add feature\n\n\nThis is the body" - ) - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_without_body(self): - """Test body validation without body.""" - rule = ValidationRule(check="require_body") - validator = BodyValidator(rule) - context = ValidationContext(stdin_text="feat: add feature") - - with patch("commit_check.util._print_failure"): - result = validator.validate(context) - assert result == ValidationResult.FAIL - - -class TestMergeBaseValidator: - @patch("commit_check.util.git_merge_base") - @pytest.mark.benchmark - def test_merge_base_validator_valid(self, mock_git_merge_base): - """Test MergeBaseValidator with valid merge base.""" - mock_git_merge_base.return_value = 0 - - rule = ValidationRule(check="merge_base") - validator = MergeBaseValidator(rule) - context = ValidationContext() - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @patch("commit_check.engine.has_commits") - @patch("commit_check.engine.get_branch_name") - @patch("commit_check.util.git_merge_base") - @pytest.mark.benchmark - def test_merge_base_validator_invalid( - self, mock_git_merge_base, mock_get_branch_name, mock_has_commits - ): - """Test MergeBaseValidator with invalid merge base.""" - mock_has_commits.return_value = True - mock_get_branch_name.return_value = "feature/test" - mock_git_merge_base.return_value = 1 - - rule = ValidationRule(check="merge_base", regex=r"^main$") - validator = MergeBaseValidator(rule) - context = ValidationContext() - - # Mock _find_target_branch to return a target branch - with patch.object(validator, "_find_target_branch", return_value="main"): - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validate_with_merge_base_ahead(self): - """Test merge base validation when branch is ahead.""" - rule = ValidationRule(check="merge_base") - validator = MergeBaseValidator(rule) - context = ValidationContext() - - with patch("commit_check.engine.git_merge_base", return_value=0): - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_with_merge_base_skip_conditions(self): - """Test merge base validation skip conditions.""" - rule = ValidationRule(check="merge_base") - validator = MergeBaseValidator(rule) - context = ValidationContext() # No stdin, should skip if no commits - - with patch("commit_check.engine.has_commits", return_value=False): - result = validator.validate(context) - assert result == ValidationResult.PASS # Skipped - - -class TestValidationEngine: - @pytest.mark.benchmark - def test_validation_engine_creation(self): - """Test ValidationEngine creation.""" - rules = [ - ValidationRule(check="message", regex=r"^feat:"), - ValidationRule(check="branch", regex=r"^feature/"), - ] - engine = ValidationEngine(rules) - - assert len(engine.rules) == 2 - assert engine.rules == rules - - @pytest.mark.benchmark - def test_validation_engine_validate_all_pass(self): - """Test ValidationEngine with all validations passing.""" - rules = [ValidationRule(check="message", regex=r"^feat:")] - engine = ValidationEngine(rules) - context = ValidationContext(stdin_text="feat: add feature") - - result = engine.validate_all(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validation_engine_validate_all_fail(self): - """Test ValidationEngine with some validations failing.""" - rules = [ - ValidationRule(check="message", regex=r"^feat:"), - ValidationRule(check="message", regex=r"^fix:"), # This will fail - ] - engine = ValidationEngine(rules) - context = ValidationContext(stdin_text="feat: add feature") - - result = engine.validate_all(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validation_engine_empty_rules(self): - """Test ValidationEngine with no rules.""" - engine = ValidationEngine([]) - context = ValidationContext() - - result = engine.validate_all(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validation_engine_unknown_validator_type(self): - """Test ValidationEngine with unknown validator type.""" - rules = [ValidationRule(check="unknown_check", regex=r".*")] - engine = ValidationEngine(rules) - context = ValidationContext() - - # Should not raise an error, just skip unknown validators - result = engine.validate_all(context) - assert result == ValidationResult.PASS # No validation performed = PASS - - @pytest.mark.benchmark - def test_validate_all_with_unknown_validator(self): - """Test validation engine with unknown validator type.""" - rules = [ - ValidationRule(check="unknown_check_type", regex=r".*"), - ValidationRule(check="message", regex=r"^feat:"), - ] - engine = ValidationEngine(rules) - context = ValidationContext(stdin_text="feat: add feature") - - result = engine.validate_all(context) - assert ( - result == ValidationResult.PASS - ) # Unknown validator skipped, remaining passes - - @pytest.mark.benchmark - def test_validate_all_mixed_results(self): - """Test validation engine with mixed pass/fail results.""" - rules = [ - ValidationRule(check="message", regex=r"^feat:"), # Will pass - ValidationRule(check="subject_max_length", value=5), # Will fail - ] - engine = ValidationEngine(rules) - context = ValidationContext(stdin_text="feat: add new feature") - - with patch("commit_check.util._print_failure"): - result = engine.validate_all(context) - assert result == ValidationResult.FAIL # Any failure = overall failure - - -class TestSubjectValidator: - """Test SubjectValidator base class.""" - - @pytest.mark.benchmark - def test_get_subject_with_context_stdin(self): - """Test _get_subject with stdin_text.""" - rule = ValidationRule(check="subject_capitalized") - validator = SubjectCapitalizationValidator(rule) - context = ValidationContext(stdin_text="feat: add new feature") - - subject = validator._get_subject(context) - assert subject == "feat: add new feature" - - @pytest.mark.benchmark - def test_get_subject_with_context_file(self): - """Test _get_subject with commit_file.""" - rule = ValidationRule(check="subject_capitalized") - validator = SubjectCapitalizationValidator(rule) - context = ValidationContext(commit_file="dummy") - - with patch( - "builtins.open", mock_open(read_data="fix: resolve bug\n\nBody text") - ): - subject = validator._get_subject(context) - assert subject == "fix: resolve bug" - - @pytest.mark.benchmark - def test_get_subject_fallback_to_git(self): - """Test _get_subject fallback to git.""" - rule = ValidationRule(check="subject_capitalized") - validator = SubjectCapitalizationValidator(rule) - context = ValidationContext() - - with patch( - "commit_check.engine.get_commit_info", return_value="chore: update deps" - ): - subject = validator._get_subject(context) - assert subject == "chore: update deps" - - @pytest.mark.benchmark - def test_get_subject_with_file_not_found(self): - """Test _get_subject when commit file not found.""" - rule = ValidationRule(check="subject_capitalized") - validator = SubjectCapitalizationValidator(rule) - context = ValidationContext(commit_file="/nonexistent/file") - - with patch( - "commit_check.engine.get_commit_info", return_value="fallback message" - ): - subject = validator._get_subject(context) - assert subject == "fallback message" - - -class TestSubjectImperativeValidator: - """Test SubjectImperativeValidator edge cases.""" - - @pytest.mark.benchmark - def test_validate_with_imperative_subject(self): - """Test validation with proper imperative subject.""" - rule = ValidationRule(check="subject_imperative") - validator = SubjectImperativeValidator(rule) - context = ValidationContext(stdin_text="fix: resolve the issue") - - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_with_non_imperative_subject(self): - """Test validation with non-imperative subject.""" - rule = ValidationRule(check="subject_imperative") - validator = SubjectImperativeValidator(rule) - context = ValidationContext(stdin_text="fix: resolved the issue") - - # Mock the print function to avoid output during tests - with patch("commit_check.util._print_failure"): - result = validator.validate(context) - assert result == ValidationResult.FAIL - - @pytest.mark.benchmark - def test_validate_short_subject(self): - """Test validation with very short subject (edge case).""" - rule = ValidationRule(check="subject_imperative") - validator = SubjectImperativeValidator(rule) - context = ValidationContext(stdin_text="feat: add") - - # "add" is a valid imperative word with conventional prefix - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_with_breaking_change(self): - """Test validation with breaking change notation.""" - rule = ValidationRule(check="subject_imperative") - validator = SubjectImperativeValidator(rule) - context = ValidationContext(stdin_text="feat!: update authentication system") - - # "update" is a valid imperative word with breaking change notation - result = validator.validate(context) - assert result == ValidationResult.PASS - - @pytest.mark.benchmark - def test_validate_with_scoped_breaking_change(self): - """Test validation with scoped breaking change notation.""" - rule = ValidationRule(check="subject_imperative") - validator = SubjectImperativeValidator(rule) - context = ValidationContext(stdin_text="fix(auth)!: resolve login bug") - - # "resolve" is a valid imperative word with scope and breaking change notation - result = validator.validate(context) - assert result == ValidationResult.PASS diff --git a/tests/main_test.py b/tests/main_test.py deleted file mode 100644 index b03ab76c..00000000 --- a/tests/main_test.py +++ /dev/null @@ -1,321 +0,0 @@ -import sys -import pytest -import tempfile -import os -from commit_check.main import StdinReader, _get_message_content, main - -CMD = "commit-check" - - -class TestMain: - @pytest.mark.benchmark - def test_help(self, capfd): - sys.argv = [CMD, "--help"] - with pytest.raises(SystemExit): - main() - out, _ = capfd.readouterr() - assert "usage:" in out - - @pytest.mark.benchmark - def test_version(self): - # argparse defines --version - sys.argv = [CMD, "--version"] - with pytest.raises(SystemExit): - main() - - @pytest.mark.benchmark - def test_no_args_shows_help(self, capfd): - """When no arguments are provided, should show help and exit 0.""" - sys.argv = [CMD] - assert main() == 0 - - @pytest.mark.benchmark - def test_message_validation_with_valid_commit(self, mocker): - """Test that a valid commit message passes validation.""" - # Mock stdin to provide a valid commit message - mocker.patch("sys.stdin.isatty", return_value=False) - mocker.patch("sys.stdin.read", return_value="feat: add new feature\n") - - sys.argv = [CMD, "-m"] - assert main() == 0 - - @pytest.mark.benchmark - def test_message_validation_with_invalid_commit(self, mocker): - """Test that an invalid commit message fails validation.""" - # Mock stdin to provide an invalid commit message - mocker.patch("sys.stdin.isatty", return_value=False) - mocker.patch("sys.stdin.read", return_value="invalid commit message\n") - - # Mock git author to ensure it's not in any ignore list - mocker.patch("commit_check.engine.get_commit_info", return_value="test-author") - - sys.argv = [CMD, "-m"] - assert main() == 1 - - @pytest.mark.benchmark - def test_message_validation_from_file(self): - """Test validation of commit message from a file.""" - with tempfile.NamedTemporaryFile(mode="w", delete=False) as f: - f.write("fix: resolve bug") - f.flush() - - try: - sys.argv = [CMD, "-m", f.name] - assert main() == 0 - finally: - os.unlink(f.name) - - @pytest.mark.benchmark - def test_branch_validation(self, mocker): - """Test branch name validation.""" - # Mock git command to return a valid branch name - mocker.patch( - "subprocess.run", - return_value=type( - "MockResult", (), {"stdout": "feature/test-branch", "returncode": 0} - )(), - ) - - sys.argv = [CMD, "-b"] - assert main() == 0 - - @pytest.mark.benchmark - def test_author_name_validation(self, mocker): - """Test author name validation.""" - # Mock git command to return a valid author name - mocker.patch( - "subprocess.run", - return_value=type( - "MockResult", (), {"stdout": "John Doe", "returncode": 0} - )(), - ) - - sys.argv = [CMD, "-n"] - assert main() == 0 - - @pytest.mark.benchmark - def test_author_email_validation(self, mocker): - """Test author email validation.""" - # Mock git command to return a valid author email - mocker.patch( - "subprocess.run", - return_value=type( - "MockResult", (), {"stdout": "john.doe@example.com", "returncode": 0} - )(), - ) - - sys.argv = [CMD, "-e"] - assert main() == 0 - - @pytest.mark.benchmark - def test_dry_run_always_passes(self, mocker): - """Test that dry run mode always returns 0.""" - # Mock stdin to provide an invalid commit message - mocker.patch("sys.stdin.isatty", return_value=False) - mocker.patch("sys.stdin.read", return_value="invalid commit message\n") - - sys.argv = [CMD, "-m", "--dry-run"] - assert main() == 0 - - -class TestStdinReader: - """Test StdinReader edge cases.""" - - @pytest.mark.benchmark - def test_read_piped_input_with_exception(self, mocker): - """Test StdinReader when stdin raises exception.""" - reader = StdinReader() - - mocker.patch("sys.stdin.isatty", return_value=False) - mocker.patch("sys.stdin.read", side_effect=OSError("Broken pipe")) - result = reader.read_piped_input() - assert result is None - - @pytest.mark.benchmark - def test_read_piped_input_with_ioerror(self, mocker): - """Test StdinReader when stdin raises IOError.""" - reader = StdinReader() - - mocker.patch("sys.stdin.isatty", return_value=False) - mocker.patch("sys.stdin.read", side_effect=IOError("Input error")) - result = reader.read_piped_input() - assert result is None - - -class TestGetMessageContent: - """Test _get_message_content function edge cases.""" - - @pytest.mark.benchmark - def test_get_message_content_empty_string_with_stdin(self, mocker): - """Test _get_message_content with empty string and stdin available.""" - reader = StdinReader() - - mocker.patch.object(reader, "read_piped_input", return_value="piped message") - result = _get_message_content("", reader) - assert result == "piped message" - - @pytest.mark.benchmark - def test_get_message_content_empty_string_no_stdin_with_git(self, mocker): - """Test _get_message_content with empty string, no stdin, fallback to git.""" - reader = StdinReader() - - mocker.patch.object(reader, "read_piped_input", return_value=None) - mocker.patch( - "commit_check.util.get_commit_info", return_value="git commit message" - ) - result = _get_message_content("", reader) - assert result == "git commit message" - - @pytest.mark.benchmark - def test_get_message_content_empty_string_no_stdin_git_fails(self, capsys, mocker): - """Test _get_message_content with empty string, no stdin, git fails.""" - reader = StdinReader() - - mocker.patch.object(reader, "read_piped_input", return_value=None) - mocker.patch( - "commit_check.util.get_commit_info", side_effect=Exception("Git error") - ) - result = _get_message_content("", reader) - assert result is None - - captured = capsys.readouterr() - assert "Error: No commit message provided" in captured.err - - @pytest.mark.benchmark - def test_get_message_content_file_read_error(self, capsys): - """Test _get_message_content with file read error.""" - reader = StdinReader() - - result = _get_message_content("/nonexistent/file.txt", reader) - assert result is None - - captured = capsys.readouterr() - assert "Error reading message file" in captured.err - - @pytest.mark.benchmark - def test_get_message_content_file_permission_error(self, capsys, mocker): - """Test _get_message_content with file permission error.""" - reader = StdinReader() - - mocker.patch("builtins.open", side_effect=PermissionError("Permission denied")) - result = _get_message_content("protected_file.txt", reader) - assert result is None - - captured = capsys.readouterr() - assert "Error reading message file" in captured.err - - -class TestMainFunctionEdgeCases: - """Test main function edge cases for better coverage.""" - - @pytest.mark.benchmark - def test_main_with_message_file_argument(self): - """Test main function with --message pointing to a file.""" - with tempfile.NamedTemporaryFile(mode="w", delete=False) as f: - f.write("feat: add new feature") - f.flush() - - try: - sys.argv = ["commit-check", "--message", f.name] - result = main() - assert result == 0 - finally: - os.unlink(f.name) - - @pytest.mark.benchmark - def test_main_with_message_empty_string_and_stdin(self, mocker): - """Test main function with --message (empty) and stdin input.""" - mocker.patch("sys.stdin.isatty", return_value=False) - mocker.patch("sys.stdin.read", return_value="feat: Add new feature\n") - - sys.argv = ["commit-check", "--message"] - result = main() - assert result == 0 - - @pytest.mark.benchmark - def test_main_with_message_empty_string_no_stdin_with_git(self, mocker): - """Test main function with --message (empty), no stdin, git fallback.""" - mocker.patch("sys.stdin.isatty", return_value=True) - mocker.patch( - "commit_check.util.get_commit_info", return_value="feat: Git commit message" - ) - - sys.argv = ["commit-check", "--message"] - result = main() - assert result == 0 - - # Removed problematic config and multi-check tests due to complex validation dependencies - - @pytest.mark.benchmark - def test_main_with_invalid_config_file(self, mocker): - """Test main function with invalid config file.""" - mocker.patch("sys.stdin.isatty", return_value=False) - mocker.patch("sys.stdin.read", return_value="feat: Test feature\n") - sys.argv = [ - "commit-check", - "--config", - "/nonexistent/config.toml", - "--message", # empty -> read from stdin - ] - - # This should fail with proper error message when config file doesn't exist - result = main() - assert result == 1 - - # Removed problematic tests that had configuration dependency issues - - @pytest.mark.benchmark - def test_main_with_dry_run_all_checks(self, mocker): - """Test main function with dry run and all checks.""" - # Mock git operations - mocker.patch( - "subprocess.run", - return_value=mocker.MagicMock(stdout="invalid-branch-name", returncode=0), - ) - mocker.patch("commit_check.util.has_commits", return_value=True) - mocker.patch("commit_check.util.get_commit_info", return_value="Invalid Name") - - sys.argv = [ - "commit-check", - "--message", - "invalid commit message", - "--branch", - "--author-name", - "--author-email", - "--dry-run", - ] - result = main() - assert result == 0 # Dry run always returns 0 - - @pytest.mark.benchmark - def test_main_error_handling_subprocess_failure(self, mocker, capsys): - """Test main function when subprocess operations fail.""" - # Mock subprocess to fail - mocker.patch("subprocess.run", side_effect=Exception("Git command failed")) - - sys.argv = ["commit-check", "--branch"] - - # Should handle the error gracefully - result = main() - # Even if subprocess fails, main should not crash - assert result in [0, 1] # Either passes or fails gracefully - - @pytest.mark.benchmark - def test_nonexistent_config_file_error(self, capsys): - """Test that specifying a non-existent config file returns error.""" - sys.argv = [ - "commit-check", - "--config", - "/nonexistent/config.toml", - "--message", - "feat: test", - ] - - result = main() - assert result == 1 - - captured = capsys.readouterr() - assert ( - "Error: Specified config file not found: /nonexistent/config.toml" - in captured.err - ) diff --git a/tests/rule_builder_test.py b/tests/rule_builder_test.py deleted file mode 100644 index 460e4719..00000000 --- a/tests/rule_builder_test.py +++ /dev/null @@ -1,228 +0,0 @@ -"""Tests for commit_check.rule_builder module.""" - -from commit_check.rule_builder import ValidationRule, RuleBuilder -from commit_check.rules_catalog import RuleCatalogEntry -import pytest - - -class TestValidationRule: - @pytest.mark.benchmark - def test_validation_rule_to_dict_with_ignored(self): - """Test ValidationRule.to_dict() method with ignored field.""" - rule = ValidationRule(check="test_check", ignored=["ignored1", "ignored2"]) - - result = rule.to_dict() - assert result["ignored"] == ["ignored1", "ignored2"] - - -class TestRuleBuilder: - @pytest.mark.benchmark - def test_rule_builder_conventional_commits_disabled(self): - """Test RuleBuilder when conventional_commits is disabled (line 115).""" - config = {"commit": {"conventional_commits": False}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry( - check="message", regex="", error="", suggest="" - ) - - # This should return None when conventional_commits is False - rule = builder._build_conventional_commit_rule(catalog_entry) - assert rule is None - - @pytest.mark.benchmark - def test_rule_builder_conventional_branch_disabled(self): - """Test RuleBuilder when conventional_branch is disabled (line 133).""" - config = {"branch": {"conventional_branch": False}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry(check="branch", regex="", error="", suggest="") - - # This should return None when conventional_branch is False - rule = builder._build_conventional_branch_rule(catalog_entry) - assert rule is None - - @pytest.mark.benchmark - def test_rule_builder_ignore_authors_list(self): - """Test RuleBuilder with ignore_authors list.""" - config = {"commit": {"ignore_authors": ["spam@example.com", "bot@example.com"]}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry( - check="ignore_authors", - regex="", - error="Author ignored", - suggest="Use different author", - ) - - # This should create a rule with ignored authors - rule = builder._build_author_list_rule(catalog_entry, "ignore_authors") - assert rule is not None - assert rule.check == "ignore_authors" - assert rule.ignored == ["spam@example.com", "bot@example.com"] - - @pytest.mark.benchmark - def test_rule_builder_invalid_author_list_type(self): - """Test RuleBuilder with invalid author list type returns None.""" - config = {"commit": {"ignore_authors": "not_a_list"}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry( - check="ignore_authors", regex="", error="", suggest="" - ) - - # This should return None for invalid type - rule = builder._build_author_list_rule(catalog_entry, "ignore_authors") - assert rule is None - - @pytest.mark.benchmark - def test_rule_builder_length_rule_with_format(self): - """Test RuleBuilder length rule with formatted error message (lines 154-160).""" - config = {"commit": {"max_length": 50}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry( - check="max_length", - regex="", - error="Message too long: max {max_len} characters", - suggest="Keep message short", - ) - - # This should create a rule with formatted error - rule = builder._build_length_rule(catalog_entry, "max_length") - assert rule is not None - assert rule.check == "max_length" - assert rule.error == "Message too long: max 50 characters" - assert rule.suggest == "Keep message short" - assert rule.value == 50 - - @pytest.mark.benchmark - def test_rule_builder_merge_base_rule_valid_target(self): - """Test RuleBuilder merge base rule with valid target (line 193).""" - config = {"branch": {"require_rebase_target": "main"}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry( - check="require_rebase_target", - regex="", - error="Branch must be rebased on target", - suggest="Rebase on target branch", - ) - - # This should create a rule with regex target - rule = builder._build_merge_base_rule(catalog_entry) - assert rule is not None - assert rule.check == "require_rebase_target" - assert rule.regex == "main" - assert rule.error == "Branch must be rebased on target" - assert rule.suggest == "Rebase on target branch" - - @pytest.mark.benchmark - def test_rule_builder_boolean_rule_enabled(self): - """Test RuleBuilder boolean rule when enabled (line 236).""" - config = {"commit": {"require_signed_off_by": True}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry( - check="require_signed_off_by", - regex="^Signed-off-by:", - error="Missing signoff", - suggest="Add Signed-off-by line", - ) - - # This should create a rule when boolean is True - rule = builder._build_boolean_rule(catalog_entry, builder.commit_config) - assert rule is not None - assert rule.check == "require_signed_off_by" - assert rule.regex == "^Signed-off-by:" - assert rule.error == "Missing signoff" - assert rule.suggest == "Add Signed-off-by line" - assert rule.value is True - - @pytest.mark.benchmark - def test_rule_builder_boolean_rule_subject_disabled(self): - """Test RuleBuilder boolean rule for subject checks when disabled (line 232).""" - config = {"commit": {"subject_capitalized": False}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry( - check="subject_capitalized", - regex="^[A-Z]", - error="Subject must be capitalized", - suggest="Capitalize first letter", - ) - - # This should return None when subject_capitalized is False (line 232) - rule = builder._build_boolean_rule(catalog_entry, builder.commit_config) - assert rule is None - - @pytest.mark.benchmark - def test_rule_builder_allow_branch_names_default(self): - """Test RuleBuilder with default branch names (no allow_branch_names configured).""" - config = {"branch": {"conventional_branch": True}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry(check="branch", regex="", error="", suggest="") - - rule = builder._build_conventional_branch_rule(catalog_entry) - assert rule is not None - # Should include default branch names: master, main, HEAD, PR-* - assert "(master)" in rule.regex - assert "(main)" in rule.regex - assert "(HEAD)" in rule.regex - assert "(PR-.+)" in rule.regex - - @pytest.mark.benchmark - def test_rule_builder_allow_branch_names_custom(self): - """Test RuleBuilder with custom branch names (allow_branch_names configured).""" - config = { - "branch": { - "conventional_branch": True, - "allow_branch_names": ["develop", "staging", "production"], - } - } - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry(check="branch", regex="", error="", suggest="") - - rule = builder._build_conventional_branch_rule(catalog_entry) - assert rule is not None - # Should include both default and custom branch names - assert "(master)" in rule.regex - assert "(main)" in rule.regex - assert "(HEAD)" in rule.regex - assert "(PR-.+)" in rule.regex - assert "(develop)" in rule.regex - assert "(staging)" in rule.regex - assert "(production)" in rule.regex - - @pytest.mark.benchmark - def test_rule_builder_allow_branch_names_empty_list(self): - """Test RuleBuilder with empty allow_branch_names list.""" - config = {"branch": {"conventional_branch": True, "allow_branch_names": []}} - - builder = RuleBuilder(config) - catalog_entry = RuleCatalogEntry(check="branch", regex="", error="", suggest="") - - rule = builder._build_conventional_branch_rule(catalog_entry) - assert rule is not None - # Should only include default branch names - assert "(master)" in rule.regex - assert "(main)" in rule.regex - assert "(HEAD)" in rule.regex - assert "(PR-.+)" in rule.regex - - @pytest.mark.benchmark - def test_rule_builder_allow_branch_names_with_duplicates(self): - """Test RuleBuilder with duplicate branch names in allow_branch_names.""" - config = { - "branch": { - "conventional_branch": True, - "allow_branch_names": ["develop", "develop", "staging", "develop"], - } - } - - builder = RuleBuilder(config) - allowed_names = builder._get_allowed_branch_names() - # Should deduplicate while preserving order - assert allowed_names == ["develop", "staging"] diff --git a/tests/util_test.py b/tests/util_test.py deleted file mode 100644 index 4e34dfc3..00000000 --- a/tests/util_test.py +++ /dev/null @@ -1,341 +0,0 @@ -import pytest -import subprocess -from commit_check.util import get_branch_name -from commit_check.util import has_commits -from commit_check.util import git_merge_base -from commit_check.util import get_commit_info -from commit_check.util import cmd_output -from commit_check.util import print_error_header -from commit_check.util import print_error_message -from commit_check.util import print_suggestion -from subprocess import CalledProcessError, PIPE -from unittest.mock import MagicMock - - -class TestUtil: - class TestGetBranchName: - @pytest.mark.benchmark - def test_get_branch_name(self, mocker): - # Must call cmd_output with given argument. - m_cmd_output = mocker.patch( - "commit_check.util.cmd_output", return_value=" fake_branch_name " - ) - retval = get_branch_name() - assert m_cmd_output.call_count == 1 - assert m_cmd_output.call_args[0][0] == ["git", "branch", "--show-current"] - assert retval == "fake_branch_name" - - @pytest.mark.benchmark - def test_get_branch_name_with_exception(self, mocker): - mock_cmd_output = mocker.patch( - "commit_check.util.cmd_output", - side_effect=CalledProcessError( - returncode=1, cmd="git branch --show-current" - ), - ) - retval = get_branch_name() - assert mock_cmd_output.call_count == 1 - mock_cmd_output.assert_called_once_with(["git", "branch", "--show-current"]) - assert retval == "HEAD" or retval # depending on env vars - - @pytest.mark.benchmark - def test_get_branch_name_fallback_github_head_ref(self, mocker): - """Test fallback to GITHUB_HEAD_REF.""" - mocker.patch("commit_check.util.cmd_output", return_value="") - mocker.patch( - "commit_check.util.os.getenv", - lambda key: "feature-branch" if key == "GITHUB_HEAD_REF" else None, - ) - assert get_branch_name() == "feature-branch" - - @pytest.mark.benchmark - def test_get_branch_name_fallback_github_ref_name(self, mocker): - """Test fallback to GITHUB_REF_NAME.""" - mocker.patch("commit_check.util.cmd_output", return_value="") - mocker.patch( - "commit_check.util.os.getenv", - lambda key: "develop" if key == "GITHUB_REF_NAME" else None, - ) - assert get_branch_name() == "develop" - - @pytest.mark.benchmark - def test_get_branch_name_fallback_head(self, mocker): - """Test fallback to HEAD.""" - mocker.patch("commit_check.util.cmd_output", return_value="") - mocker.patch("commit_check.util.os.getenv", return_value=None) - assert get_branch_name() == "HEAD" - - @pytest.mark.benchmark - def test_get_branch_name_fallback_priority(self, mocker): - """Test fallback priority.""" - mocker.patch("commit_check.util.cmd_output", return_value="") - mocker.patch( - "commit_check.util.os.getenv", - lambda key: { - "GITHUB_HEAD_REF": "feature-branch", - "GITHUB_REF_NAME": "develop", - }.get(key), - ) - assert get_branch_name() == "feature-branch" - - class TestHasCommits: - @pytest.mark.benchmark - def test_has_commits_true(self, mocker): - # Must return True when git rev-parse HEAD succeeds - m_subprocess_run = mocker.patch("subprocess.run", return_value=None) - retval = has_commits() - assert m_subprocess_run.call_count == 1 - assert m_subprocess_run.call_args[0][0] == [ - "git", - "rev-parse", - "--verify", - "HEAD", - ] - assert m_subprocess_run.call_args[1] == { - "stdout": subprocess.DEVNULL, - "stderr": subprocess.DEVNULL, - "check": True, - } - assert retval is True - - @pytest.mark.benchmark - def test_has_commits_false(self, mocker): - # Must return False when git rev-parse HEAD fails - m_subprocess_run = mocker.patch( - "subprocess.run", - side_effect=subprocess.CalledProcessError(128, "git rev-parse"), - ) - retval = has_commits() - assert m_subprocess_run.call_count == 1 - assert m_subprocess_run.call_args[0][0] == [ - "git", - "rev-parse", - "--verify", - "HEAD", - ] - assert m_subprocess_run.call_args[1] == { - "stdout": subprocess.DEVNULL, - "stderr": subprocess.DEVNULL, - "check": True, - } - assert retval is False - - class TestGitMergeBase: - @pytest.mark.benchmark - @pytest.mark.parametrize( - "returncode,expected", - [ - (0, 0), # ancestor exists - (1, 1), # no ancestor - (128, 128), # error case - ], - ) - @pytest.mark.benchmark - def test_git_merge_base(self, mocker, returncode, expected): - mock_run = mocker.patch("subprocess.run") - if returncode == 128: - mock_run.side_effect = CalledProcessError(returncode, "git merge-base") - else: - mock_result = MagicMock() - mock_result.returncode = returncode - mock_run.return_value = mock_result - - result = git_merge_base("main", "feature") - - mock_run.assert_called_once_with( - ["git", "merge-base", "--is-ancestor", "main", "feature"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - encoding="utf-8", - ) - - assert result == expected - - class TestGetCommitInfo: - @pytest.mark.benchmark - @pytest.mark.parametrize( - "format_string", - [ - ("s"), - ("an"), - ("ae"), - ], - ) - @pytest.mark.benchmark - def test_get_commit_info(self, mocker, format_string): - # Must call get_commit_info with given argument when there are commits. - mocker.patch("commit_check.util.has_commits", return_value=True) - m_cmd_output = mocker.patch( - "commit_check.util.cmd_output", return_value=" fake commit message " - ) - retval = get_commit_info(format_string) - assert m_cmd_output.call_count == 1 - assert m_cmd_output.call_args[0][0] == [ - "git", - "log", - "-n", - "1", - f"--pretty=format:%{format_string}", - "HEAD", - ] - assert retval == " fake commit message " - - @pytest.mark.benchmark - def test_get_commit_info_no_commits(self, mocker): - # Must return 'Repo has no commits yet.' when there are no commits. - mocker.patch("commit_check.util.has_commits", return_value=False) - mocker.patch( - "commit_check.util.cmd_output", return_value=" fake commit message " - ) - format_string = "s" - retval = get_commit_info(format_string) - assert retval == " fake commit message " - - @pytest.mark.benchmark - def test_get_commit_info_with_exception(self, mocker): - # Must return empty string when exception raises in cmd_output. - mocker.patch("commit_check.util.has_commits", return_value=True) - m_cmd_output = mocker.patch( - "commit_check.util.cmd_output", return_value=" fake commit message " - ) - # CalledProcessError's args also dummy - dummy_ret_code, dummy_cmd_name = 1, "dcmd" - m_cmd_output.side_effect = CalledProcessError( - dummy_ret_code, dummy_cmd_name - ) - format_string = "s" - retval = get_commit_info(format_string) - assert m_cmd_output.call_count == 1 - assert m_cmd_output.call_args[0][0] == [ - "git", - "log", - "-n", - "1", - f"--pretty=format:%{format_string}", - "HEAD", - ] - assert retval == "" - - class TestCmdOutput: - # use DummyProcessResult in this test to access returncode, stdout and stderr attribute - class DummyProcessResult: - def __init__(self, returncode, stdout, stderr): - self.returncode = returncode - self.stdout = stdout - self.stderr = stderr - - @pytest.mark.benchmark - def test_cmd_output(self, mocker): - # Must subprocess.run with given argument. - m_subprocess_run = mocker.patch( - "subprocess.run", return_value=self.DummyProcessResult(0, "ok", "") - ) - retval = cmd_output(["dummy_cmd"]) - assert m_subprocess_run.call_count == 1 - assert retval == "ok" - - @pytest.mark.benchmark - @pytest.mark.parametrize( - "returncode, stdout, stderr", - [ - (1, "ok", "err"), - (0, None, "err"), - (1, None, "err"), - ], - ) - @pytest.mark.benchmark - def test_cmd_output_err(self, mocker, returncode, stdout, stderr): - # Must return stderr when subprocess.run returns not empty stderr. - m_subprocess_run = mocker.patch( - "subprocess.run", - return_value=self.DummyProcessResult(returncode, stdout, stderr), - ) - dummy_cmd = ["dummy_cmd"] - retval = cmd_output(dummy_cmd) - assert m_subprocess_run.call_count == 1 - assert retval == stderr - assert m_subprocess_run.call_args[0][0] == dummy_cmd - assert m_subprocess_run.call_args[1] == { - "encoding": "utf-8", - "stderr": PIPE, - "stdout": PIPE, - } - - @pytest.mark.benchmark - @pytest.mark.parametrize( - "returncode, stdout, stderr", - [ - (1, "ok", ""), - (0, None, ""), - (1, None, ""), - ], - ) - @pytest.mark.benchmark - def test_cmd_output_err_with_len0_stderr( - self, mocker, returncode, stdout, stderr - ): - # Must return empty string when subprocess.run returns empty stderr. - m_subprocess_run = mocker.patch( - "subprocess.run", - return_value=self.DummyProcessResult(returncode, stdout, stderr), - ) - dummy_cmd = ["dummy_cmd"] - retval = cmd_output(dummy_cmd) - assert m_subprocess_run.call_count == 1 - assert retval == "" - assert m_subprocess_run.call_args[0][0] == dummy_cmd - assert m_subprocess_run.call_args[1] == { - "encoding": "utf-8", - "stderr": PIPE, - "stdout": PIPE, - } - - class TestPrintErrorMessage: - @pytest.mark.benchmark - def test_print_error_header(self, capfd): - # Must print on stdout with given argument. - print_error_header() - stdout, _ = capfd.readouterr() - assert "Commit rejected by Commit-Check" in stdout - assert "Commit rejected." in stdout - - @pytest.mark.benchmark - @pytest.mark.parametrize( - "check_type, type_failed_msg", - [ - ("message", "check failed ==>"), - ("branch", "check failed ==>"), - ("author_name", "check failed ==>"), - ("author_email", "check failed ==>"), - ("signoff", "check failed ==>"), - ], - ) - @pytest.mark.benchmark - def test_print_error_message(self, capfd, check_type, type_failed_msg): - # Must print on stdout with given argument. - dummy_regex = "dummy regex" - dummy_reason = "failure reason" - dummy_error = "dummy error" - print_error_message(check_type, dummy_regex, dummy_error, dummy_reason) - stdout, _ = capfd.readouterr() - assert check_type in stdout - assert type_failed_msg in stdout - assert f"It doesn't match regex: {dummy_regex}" in stdout - assert dummy_error in stdout - - class TestPrintSuggestion: - @pytest.mark.benchmark - def test_print_suggestion(self, capfd): - # Must print on stdout with given argument. - print_suggestion("dummy suggest") - stdout, _ = capfd.readouterr() - assert "Suggest:" in stdout - - @pytest.mark.benchmark - def test_print_suggestion_exit1(self, capfd): - # Must exit with 1 when "" passed - with pytest.raises(SystemExit) as e: - print_suggestion("") - assert e.value.code == 1 - stdout, _ = capfd.readouterr() - assert "commit-check does not support" in stdout diff --git a/troubleshoot.html b/troubleshoot.html new file mode 100644 index 00000000..81047cd8 --- /dev/null +++ b/troubleshoot.html @@ -0,0 +1,857 @@ + + + + + + + + + + + + + + + + + + + + + + + + Troubleshooting - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Troubleshooting

+

How to Skip Author Name Check

+

In some cases, Commit Check may fail due to an invalid author_name, as shown below:

+
check committer name.....................................................Failed
+- hook id: check-author-name
+- exit code: 1
+
+Commit rejected by Commit-Check.
+
+Type author_name check failed => 12
+It doesn't match regex: ^[A-Za-zÀ-ÖØ-öø-ÿ\u0100-\u017F\u0180-\u024F ,.\'-]+$|.*(\[bot])
+The committer name seems invalid
+Suggest: run command `git config user.name "Your Name"`
+
+
+

To fix it, you can either update your Git config or temporarily skip the check using one of the following methods.

+

Bypass Specific Hook

+

Use the --no-verify flag to skip the pre-commit hook:

+
# Amend the commit without running hooks
+git commit --amend --author="Xianpeng Shen <xianpeng.shen@gmail.com>" --no-edit --no-verify
+
+
+

Bypass All Hooks

+

Alternatively, use the SKIP=your-hook-name environment variable, like below:

+
# Set the correct Git author name
+git config user.name "Xianpeng Shen"
+
+# Force amend while skipping the specified hook
+SKIP=check-author-name git commit --amend --author="Xianpeng Shen <xianpeng.shen@gmail.com>" --no-edit
+
+
+ + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/what-is-new.html b/what-is-new.html new file mode 100644 index 00000000..1f049a44 --- /dev/null +++ b/what-is-new.html @@ -0,0 +1,1326 @@ + + + + + + + + + + + + + + + + + + + + + + + + What’s New - Commit Check + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + + + + + + + + + +
+
+ + + + + +

What’s New

+

This document highlights the major changes and improvements in each version of commit-check.

+

Version 2.0.0 - Major Release

+

Version 2.0.0 represents a complete architectural overhaul of commit-check, introducing significant improvements in configuration, usability, and maintainability.

+

Overview

+

The most significant change in v2.0.0 is the transition from YAML to TOML configuration format, along with a complete redesign of the validation engine using SOLID principles.

+

Key Benefits:

+
    +
  • Simplified Configuration: More intuitive TOML syntax

  • +
  • Better Defaults: Sensible out-of-the-box behavior

  • +
  • Enhanced Validation: Built-in support for Conventional Commits and Conventional Branches

  • +
  • Improved Architecture: Modular, maintainable codebase

  • +
  • Better Documentation: Comprehensive guides and examples

  • +
+

Documentation & Migration

+ +

Configuration Format Migration

+

The configuration format has changed from YAML to TOML, providing better readability and easier maintenance.

+

Format Comparison:

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +

Feature

YAML (v1.x)

TOML (v2.0+)

Syntax

Complex nested structure

Simple key-value pairs

Validation

Custom regex patterns

Built-in conventional standards

Configuration

.commit-check.yml

cchk.toml or commit-check.toml

Maintainability

Manual regex maintenance

Standardized patterns

+

Configuration Examples

+

Below are side-by-side comparisons showing how common configurations translate from v1.x to v2.0+.

+

Commit Message Validation

+

Transform complex regex patterns into simple, standardized configuration.

+

Before (YAML v1.x):

+
checks:
+  - check: message
+    regex: '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)|(Merge).*|(fixup!.*)'
+    error: "The commit message should be structured as follows:\n\n
+    <type>[optional scope]: <description>\n
+    [optional body]\n
+    [optional footer(s)]\n\n
+    More details please refer to https://www.conventionalcommits.org"
+    suggest: please check your commit message whether matches above regex
+
+
+

After (TOML v2.0+):

+
[commit]
+conventional_commits = true
+allow_commit_types = ["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "style", "test"]
+
+
+

Benefits: No more complex regex patterns, built-in Conventional Commits support, clearer configuration.

+

Branch Naming Validation

+

Standardize branch naming with conventional patterns.

+

Before (YAML v1.x):

+
checks:
+  - check: branch
+    regex: ^(bugfix|feature|release|hotfix|task|chore)\/.+|(master)|(main)|(HEAD)|(PR-.+)
+    error: "Branches must begin with these types: bugfix/ feature/ release/ hotfix/ task/ chore/"
+    suggest: run command `git checkout -b type/branch_name`
+
+
+

After (TOML v2.0+):

+
[branch]
+conventional_branch = true
+allow_branch_types = ["bugfix", "feature", "release", "hotfix", "task", "chore"]
+
+
+

Benefits: Built-in Conventional Branch support, automatic handling of special branches (main, master, HEAD, PR-*).

+

Author Validation

+

Flexible author validation with allow/ignore lists.

+

Before (YAML v1.x):

+
checks:
+  - check: author_name
+    regex: ^[A-Za-zÀ-ÖØ-öø-ÿ\u0100-\u017F\u0180-\u024F ,.\'-]+$|.*(\[bot])
+    error: The committer name seems invalid
+    suggest: run command `git config user.name "Your Name"`
+
+
+

After (TOML v2.0+):

+
[commit]
+# Built-in validation with sensible defaults for author name/email
+# Optional: ignore specific authors (e.g., bots)
+ignore_authors = ["dependabot[bot]", "renovate[bot]"]
+
+
+

Benefits: Built-in validation patterns, flexible ignore lists, automatic bot detection.

+

Signed-off-by Requirements

+

Simple boolean flag for DCO compliance.

+

Before (YAML v1.x):

+
checks:
+  - check: commit_signoff
+    regex: Signed-off-by:.*[A-Za-z0-9]\s+<.+@.+>
+    error: Signed-off-by not found in latest commit
+    suggest: run command `git commit -m "conventional commit message" --signoff`
+
+
+

After (TOML v2.0+):

+
[commit]
+require_signed_off_by = true
+
+
+

Benefits: Simple boolean configuration, built-in DCO validation, clear error messages.

+

Architecture Improvements

+

New Validation Engine

+
    +
  • SOLID Principles: Maintainable, extensible design

  • +
  • Specialized Validators: Dedicated classes for each validation type

  • +
  • Centralized Rules: Rule catalog with consistent error messages

  • +
  • Flexible Configuration: Dynamic rule building from configuration

  • +
+

Module Organization

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Module

Purpose

config.py

TOML configuration loading and validation

engine.py

Core validation engine and specialized validators

rule_builder.py

Builds validation rules from configuration

rules_catalog.py

Centralized catalog of validation rules and messages

main.py

CLI interface and orchestration

+

Getting Started with v2.0

+

For New Users:

+
    +
  1. Install commit-check v2.0+:

    +
    pip install commit-check>=2.0.0
    +
    +
    +
  2. +
  3. Start with defaults (no configuration needed):

    +
    commit-check --message --branch
    +
    +
    +
  4. +
  5. Customize as needed with cchk.toml:

    +
    [commit]
    +conventional_commits = true
    +subject_max_length = 72
    +
    +
    +
  6. +
+

For Existing Users

+
    +
  1. Follow the Migration Guide: See Migration Guide

  2. +
  3. Test thoroughly: Validate your new configuration before deploying

  4. +
+

Additional Resources

+ + + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file