From 6d3b3e8a8ad82c1067876b8ed6bc2bda527cf9a3 Mon Sep 17 00:00:00 2001 From: tisimst Date: Sat, 18 Apr 2026 14:54:53 +0500 Subject: [PATCH 1/2] Upgrade package --- .github/dependabot.yml | 14 + .github/workflows/code_style.yml | 36 + .github/workflows/code_test.yml | 99 + .github/workflows/codeql.yml | 101 + .github/workflows/dist_build.yml | 40 + .github/workflows/docs_build.yml | 52 + .github/workflows/publish_dist.yml | 56 + .gitignore | 211 +- .python-version | 1 + LICENSE | 29 + README.md | 58 + README.rst | 55 - doc/Makefile | 90 - doc/_build/doctrees/environment.pickle | Bin 7991 -> 0 bytes doc/_build/doctrees/index.doctree | Bin 69352 -> 0 bytes doc/_build/html/.buildinfo | 4 - doc/_build/html/_sources/index.txt | 444 - doc/_build/html/_static/ajax-loader.gif | Bin 673 -> 0 bytes doc/_build/html/_static/basic.css | 540 - doc/_build/html/_static/comment-bright.png | Bin 3500 -> 0 bytes doc/_build/html/_static/comment-close.png | Bin 3578 -> 0 bytes doc/_build/html/_static/comment.png | Bin 3445 -> 0 bytes doc/_build/html/_static/contents.png | Bin 202 -> 0 bytes doc/_build/html/_static/doctools.js | 247 - doc/_build/html/_static/down-pressed.png | Bin 368 -> 0 bytes doc/_build/html/_static/down.png | Bin 363 -> 0 bytes doc/_build/html/_static/file.png | Bin 392 -> 0 bytes doc/_build/html/_static/jquery.js | 9404 ----------------- doc/_build/html/_static/minus.png | Bin 199 -> 0 bytes doc/_build/html/_static/navigation.png | Bin 218 -> 0 bytes doc/_build/html/_static/plus.png | Bin 199 -> 0 bytes doc/_build/html/_static/pygments.css | 62 - doc/_build/html/_static/searchtools.js | 567 - doc/_build/html/_static/sphinxdoc.css | 339 - doc/_build/html/_static/underscore.js | 1226 --- doc/_build/html/_static/up-pressed.png | Bin 372 -> 0 bytes doc/_build/html/_static/up.png | Bin 363 -> 0 bytes doc/_build/html/_static/websupport.js | 808 -- doc/_build/html/genindex.html | 149 - doc/_build/html/index.html | 516 - doc/_build/html/objects.inv | Bin 201 -> 0 bytes doc/_build/html/search.html | 122 - doc/_build/html/searchindex.js | 1 - doc/_static/_default.css | 507 - doc/_static/favicon.ico | Bin 11513 -> 0 bytes doc/_static/logo.png | Bin 9937 -> 0 bytes doc/_static/logo.svg | 71 - doc/_templates/layout.html | 89 - doc/conf.py | 203 - doc/index.rst | 440 - doc/pyswarm_doc.zip | Bin 156739 -> 0 bytes .../_build/html => docs}/_static/_default.css | 0 {doc/_build/html => docs}/_static/favicon.ico | Bin {doc/_build/html => docs}/_static/logo.png | Bin {doc/_build/html => docs}/_static/logo.svg | 0 docs/api.md | 146 + docs/index.md | 61 + docs/installation.md | 115 + docs/quickstart.md | 155 + docs/references.md | 24 + docs/theory.md | 134 + mkdocs.yml | 51 + pso_examples.py | 90 - pyproject.toml | 128 + pyswarm/__init__.py | 25 +- pyswarm/pso.py | 182 +- setup.py | 47 - tests/test_banana_no_constraints.py | 22 + tests/test_banana_with_constraints.py | 34 + tests/test_twobar_truss.py | 64 + uv.lock | 959 ++ 71 files changed, 2720 insertions(+), 16098 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/code_style.yml create mode 100644 .github/workflows/code_test.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dist_build.yml create mode 100644 .github/workflows/docs_build.yml create mode 100644 .github/workflows/publish_dist.yml create mode 100644 .python-version create mode 100644 LICENSE create mode 100644 README.md delete mode 100644 README.rst delete mode 100644 doc/Makefile delete mode 100644 doc/_build/doctrees/environment.pickle delete mode 100644 doc/_build/doctrees/index.doctree delete mode 100644 doc/_build/html/.buildinfo delete mode 100644 doc/_build/html/_sources/index.txt delete mode 100644 doc/_build/html/_static/ajax-loader.gif delete mode 100644 doc/_build/html/_static/basic.css delete mode 100644 doc/_build/html/_static/comment-bright.png delete mode 100644 doc/_build/html/_static/comment-close.png delete mode 100644 doc/_build/html/_static/comment.png delete mode 100644 doc/_build/html/_static/contents.png delete mode 100644 doc/_build/html/_static/doctools.js delete mode 100644 doc/_build/html/_static/down-pressed.png delete mode 100644 doc/_build/html/_static/down.png delete mode 100644 doc/_build/html/_static/file.png delete mode 100644 doc/_build/html/_static/jquery.js delete mode 100644 doc/_build/html/_static/minus.png delete mode 100644 doc/_build/html/_static/navigation.png delete mode 100644 doc/_build/html/_static/plus.png delete mode 100644 doc/_build/html/_static/pygments.css delete mode 100644 doc/_build/html/_static/searchtools.js delete mode 100644 doc/_build/html/_static/sphinxdoc.css delete mode 100644 doc/_build/html/_static/underscore.js delete mode 100644 doc/_build/html/_static/up-pressed.png delete mode 100644 doc/_build/html/_static/up.png delete mode 100644 doc/_build/html/_static/websupport.js delete mode 100644 doc/_build/html/genindex.html delete mode 100644 doc/_build/html/index.html delete mode 100644 doc/_build/html/objects.inv delete mode 100644 doc/_build/html/search.html delete mode 100644 doc/_build/html/searchindex.js delete mode 100644 doc/_static/_default.css delete mode 100644 doc/_static/favicon.ico delete mode 100644 doc/_static/logo.png delete mode 100644 doc/_static/logo.svg delete mode 100644 doc/_templates/layout.html delete mode 100644 doc/conf.py delete mode 100644 doc/index.rst delete mode 100644 doc/pyswarm_doc.zip rename {doc/_build/html => docs}/_static/_default.css (100%) mode change 100644 => 100755 rename {doc/_build/html => docs}/_static/favicon.ico (100%) mode change 100644 => 100755 rename {doc/_build/html => docs}/_static/logo.png (100%) mode change 100644 => 100755 rename {doc/_build/html => docs}/_static/logo.svg (100%) mode change 100644 => 100755 create mode 100644 docs/api.md create mode 100644 docs/index.md create mode 100644 docs/installation.md create mode 100644 docs/quickstart.md create mode 100644 docs/references.md create mode 100644 docs/theory.md create mode 100644 mkdocs.yml delete mode 100644 pso_examples.py create mode 100644 pyproject.toml delete mode 100644 setup.py create mode 100644 tests/test_banana_no_constraints.py create mode 100644 tests/test_banana_with_constraints.py create mode 100644 tests/test_twobar_truss.py create mode 100644 uv.lock diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7e6c742 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "friday" + + - package-ecosystem: "uv" + directory: "/" + schedule: + interval: "weekly" + day: "friday" diff --git a/.github/workflows/code_style.yml b/.github/workflows/code_style.yml new file mode 100644 index 0000000..6c33f35 --- /dev/null +++ b/.github/workflows/code_style.yml @@ -0,0 +1,36 @@ +name: Lint and Format + +on: + push: + branches: [ master ] + + pull_request: + branches: [ master ] + paths: [ '**/*.py' ] + + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}/${{ github.ref }} + cancel-in-progress: true + +jobs: + python-format: + name: Ruff Lint and Format + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + + - name: Setup Ruff + uses: astral-sh/ruff-action@v3 + with: + args: --version + + - name: Enforce Lint + run: ruff check pyswarm + + - name: Enforce Format + run: | + ruff format --diff pyswarm diff --git a/.github/workflows/code_test.yml b/.github/workflows/code_test.yml new file mode 100644 index 0000000..5bddf4f --- /dev/null +++ b/.github/workflows/code_test.yml @@ -0,0 +1,99 @@ +name: Code Test + +on: + push: + branches: [ master ] + + pull_request: + branches: [ master ] + + schedule: + - cron: "0 0 * * 0" # Runs every Sunday at midnight UTC + + workflow_dispatch: + workflow_call: + outputs: + artifact_name: + value: ${{ jobs.fresh_build.outputs.artifact_name }} + artifact_run_id: + value: ${{ jobs.fresh_build.outputs.run_id }} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + + setup: + runs-on: ubuntu-latest + + steps: + - name: Fetch Supported Python + id: fetch-versions + run: | + versions=$(curl -fsSL https://endoflife.date/api/v1/products/python/ \ + | jq '[ .result.releases[] | select(.isEol == false) | .label ]') + + echo "supported_versions=$(echo $versions |jq -c '.')" >> $GITHUB_OUTPUT + echo "bound_versions=$(echo $versions |jq -c '[.[0],.[-1]]')" >> $GITHUB_OUTPUT + + outputs: + supported_versions: ${{ steps.fetch-versions.outputs.supported_versions }} + bound_versions: ${{ steps.fetch-versions.outputs.bound_versions }} + + fresh_build: + uses: ./.github/workflows/dist_build.yml + + testing: + runs-on: ${{ matrix.os }} + + permissions: + id-token: write # for working of oidc of codecov + + strategy: + matrix: + os: [ ubuntu-latest ] + py-version: ${{ fromJson(needs.setup.outputs.supported_versions) }} + include: + - os: windows-latest + py-version: ${{ fromJson(needs.setup.outputs.bound_versions)[0] }} + - os: windows-latest + py-version: ${{ fromJson(needs.setup.outputs.bound_versions)[1] }} + - os: macos-latest + py-version: ${{ fromJson(needs.setup.outputs.bound_versions)[0] }} + - os: macos-latest + py-version: ${{ fromJson(needs.setup.outputs.bound_versions)[1] }} + + needs: + - fresh_build + - setup + + steps: + - uses: actions/checkout@v6 + + - name: Download Build Artifacts + uses: actions/download-artifact@v8 + with: + name: ${{ needs.fresh_build.outputs.artifact_name }} + run-id: ${{ needs.fresh_build.outputs.run_id }} + path: ./dist + + - uses: astral-sh/setup-uv@v7 + with: + python-version: ${{ matrix.py-version }} + + - name: Install Packages + shell: bash + run: | + uv sync --no-dev --group test + uv pip install -v ./dist/*.whl + + - name: Run Tests + run: uv run --no-sync pytest -v -n auto --cov --cov-report=xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v6 + with: + fail_ci_if_error: true + use_oidc: true + verbose: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..36471e6 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,101 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + schedule: + - cron: '33 5 * * 2' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: python + build-mode: none + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + # Add any setup steps before running the `github/codeql-action/init` action. + # This includes steps like installing compilers or runtimes (`actions/setup-node` + # or others). This is typically only required for manual builds. + # - name: Setup runtime (example) + # uses: actions/setup-example@v1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - name: Run manual build steps + if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dist_build.yml b/.github/workflows/dist_build.yml new file mode 100644 index 0000000..acc7c2c --- /dev/null +++ b/.github/workflows/dist_build.yml @@ -0,0 +1,40 @@ +name: Build Distribution + +on: + workflow_call: + outputs: + artifact_name: + value: ${{ jobs.build.outputs.artifact_name }} + run_id: + value: ${{ github.run_id }} + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Setup uv + uses: astral-sh/setup-uv@v7 + + - name: Build distribution + run: uv build -v --clear . + + - name: Set Artifact Name + id: artifact-name + run: | + echo "artifact_name=${{ github.run_id }}[${{ github.run_attempt }}]--build-artifacts" \ + | tee -a $GITHUB_OUTPUT + + - name: Upload Build Artifacts + uses: actions/upload-artifact@v7 + with: + name: ${{ steps.artifact-name.outputs.artifact_name }} + path: dist + if-no-files-found: error + + outputs: + artifact_name: ${{ steps.artifact-name.outputs.artifact_name }} diff --git a/.github/workflows/docs_build.yml b/.github/workflows/docs_build.yml new file mode 100644 index 0000000..6d41b2d --- /dev/null +++ b/.github/workflows/docs_build.yml @@ -0,0 +1,52 @@ +name: Build Documentation +permissions: + pages: write + id-token: write + +on: + pull_request: + branches: [ master ] + workflow_call: + inputs: &build-docs-inputs + deploy: + type: boolean + required: false + default: false + + workflow_dispatch: + inputs: *build-docs-inputs + +concurrency: + group: docs-build + +jobs: + + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + + - name: Setup uv + uses: astral-sh/setup-uv@v7 + + - name: Build Documentation + run: uv run --no-dev --group docs zensical build --clean --strict + + - name: Set Artifact Name + id: artifact-name + run: | + echo "artifact_name=${{ github.run_id }}[${{ github.run_attempt }}]--docs-artifacts" \ + | tee -a $GITHUB_OUTPUT + + - name: Upload Pages Artifacts + uses: actions/upload-pages-artifact@v5 + with: + name: ${{ steps.artifact-name.outputs.artifact_name }} + path: site/ + + - name: Deploy to GitHub Pages + if: ${{ inputs.deploy }} + uses: actions/deploy-pages@v5 + with: + artifact_name: ${{ steps.artifact-name.outputs.artifact_name }} diff --git a/.github/workflows/publish_dist.yml b/.github/workflows/publish_dist.yml new file mode 100644 index 0000000..590785f --- /dev/null +++ b/.github/workflows/publish_dist.yml @@ -0,0 +1,56 @@ +name: Publish to PyPI + +on: + release: + types: [published] + +permissions: + id-token: write + +concurrency: + group: ${{ github.workflow }} + +jobs: + testing: + uses: ./.github/workflows/code_test.yml + + publish-to-pypi: + runs-on: ubuntu-latest + + environment: + name: pypi + + needs: testing + + steps: + + - &download_dist + name: Download Distributions + uses: actions/download-artifact@v8 + with: + name: ${{ needs.testing.outputs.artifact_name }} + run-id: ${{ needs.testing.outputs.artifact_run_id }} + path: ./dist + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + verbose: true + + - name: Smoke Test on PyPI + shell: bash + run: | + sleep 60 + pip install -v --index-url https://pypi.org/simple/ pyswarm + python -c "import pyswarm;print(pyswarm.__version__)" + + publish_docs: + needs: publish-to-pypi + + permissions: + pages: write + id-token: write + + uses: ./.github/workflows/docs_build.yml + with: + deploy: true diff --git a/.gitignore b/.gitignore index 5fa8f85..b7faf40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,207 @@ -*.*~ -*.pyc -dist -build +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg MANIFEST -*.egg-info + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock +#poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +#pdm.lock +#pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +#pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Cursor +# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to +# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data +# refer to https://docs.cursor.com/context/ignore-files +.cursorignore +.cursorindexingignore + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..624a2c5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2013, Abraham D. Lee +Copyright (c) 2026, eggzec + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cc0b49d --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# PySwarm + +**Particle Swarm Optimization (PSO) for Python** + +[![Tests](https://github.com/eggzec/pyswarm/actions/workflows/code_test.yml/badge.svg)](https://github.com/eggzec/pyswarm/actions/workflows/code_test.yml) +[![Documentation](https://github.com/eggzec/pyswarm/actions/workflows/docs_build.yml/badge.svg)](https://github.com/eggzec/pyswarm/actions/workflows/docs_build.yml) +[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) + +[![codecov](https://codecov.io/github/eggzec/pyswarm/graph/badge.svg)](https://codecov.io/github/eggzec/pyswarm) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=eggzec_pyswarm&metric=alert_status)](https://sonarcloud.io/project/overview?id=eggzec_pyswarm) +[![License: BSD-3](https://img.shields.io/badge/License-BSD--3-blue.svg)](LICENSE) + +[![PyPI Downloads](https://img.shields.io/pypi/dm/pyswarm.svg?label=PyPI%20downloads)](https://pypi.org/project/pyswarm/) +[![Python versions](https://img.shields.io/pypi/pyversions/pyswarm.svg)](https://pypi.org/project/pyswarm/) + +`pyswarm` is a gradient-free, evolutionary optimization library for Python that implements [**Particle Swarm Optimization (PSO)**](https://en.wikipedia.org/wiki/Particle_swarm_optimization) with built-in support for constraints. It is lightweight, easy to use, and suitable for a wide range of optimization problems where gradient information is unavailable or impractical to compute. + +## Quick example + +```python +import numpy as np +from pyswarm import pso + + +def objective(x): + x1, x2 = x + return x1**4 - 2 * x2 * x1**2 + x2**2 + x1**2 - 2 * x1 + 5 + + +lb = [-3, -1] +ub = [2, 6] + +xopt, fopt = pso(objective, lb, ub) + +print("Optimal solution:", xopt) +print("Function value:", fopt) +``` + +## Installation + +```bash +pip install pyswarm +``` + +Requires Python 3.10+. No external runtime dependencies. See the +[full installation guide](https://eggzec.github.io/pyswarm/installation/) for +uv, poetry, and source builds. + +## Documentation + +- [Theory](https://eggzec.github.io/pyswarm/theory/) — mathematical background, hierarchical basis, algorithms +- [Quickstart](https://eggzec.github.io/pyswarm/quickstart/) — runnable examples +- [API Reference](https://eggzec.github.io/pyswarm/api/) — class and function signatures +- [References](https://eggzec.github.io/pyswarm/references/) — literature citations + +## License + +BSD-3-Clause — see [LICENSE](LICENSE). diff --git a/README.rst b/README.rst deleted file mode 100644 index 188257e..0000000 --- a/README.rst +++ /dev/null @@ -1,55 +0,0 @@ -========================================================= -Particle swarm optimization (PSO) with constraint support -========================================================= - -The ``pyswarm`` package is a gradient-free, evolutionary optimization package -for python that supports constraints. - -What's New -========== - -This release features multiprocessing support. - -Requirements -============ - -- NumPy - -Installation and download -========================= - -See the `package homepage`_ for helpful hints relating to downloading -and installing pyswarm. - - -Source Code -=========== - -The latest, bleeding-edge, but working, `code -`_ -and `documentation source -`_ are -available `on GitHub `_. - -Contact -======= - -Any feedback, questions, bug reports, or success stores should -be sent to the `author`_. I'd love to hear from you! - -License -======= - -This package is provided under two licenses: - -1. The *BSD License* -2. Any other that the author approves (just ask!) - -References -========== - -- `Particle swarm optimization`_ on Wikipedia - -.. _author: mailto:tisimst@gmail.com -.. _Particle swarm optimization: http://en.wikipedia.org/wiki/Particle_swarm_optimization -.. _package homepage: http://pythonhosted.org/pyswarm diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 544991e..0000000 --- a/doc/Makefile +++ /dev/null @@ -1,90 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml pickle json htmlhelp qthelp changes linkcheck doctest # latex - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" -# @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf _build/* - -# The HTML needs latex because the PDF version is linked to: -html: # latex -# (cd _build/latex; make all-pdf) - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html - @echo - @echo "Build finished. The HTML pages are in _build/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml - @echo - @echo "Build finished. The HTML pages are in _build/dirhtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in _build/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in _build/qthelp, like this:" - @echo "# qcollectiongenerator _build/qthelp/uncertaintiesPythonpackage.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile _build/qthelp/uncertaintiesPythonpackage.qhc" - -# latex: -# $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex -# @echo -# @echo "Build finished; the LaTeX files are in _build/latex." -# @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ -# "run these through (pdf)latex." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes - @echo - @echo "The overview file is in _build/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in _build/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in _build/doctest/output.txt." diff --git a/doc/_build/doctrees/environment.pickle b/doc/_build/doctrees/environment.pickle deleted file mode 100644 index 04d78790bf937cf9c98e11869e4b4d9edbe415ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7991 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 diff --git a/doc/_build/html/.buildinfo b/doc/_build/html/.buildinfo deleted file mode 100644 index de72327..0000000 --- a/doc/_build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 5fba493304ebfe42e711637b4f913192 -tags: fbb0d17656682115ca4d033fb2f83ba1 diff --git a/doc/_build/html/_sources/index.txt b/doc/_build/html/_sources/index.txt deleted file mode 100644 index cf985ab..0000000 --- a/doc/_build/html/_sources/index.txt +++ /dev/null @@ -1,444 +0,0 @@ -.. meta:: - :description: Particle swarm optimization (PSO) with constraint support - :keywords: particle swarm optimization, pso, optimization, constraints - -====================================================================== -Particle swarm optimization (PSO) with constraint support -====================================================================== - -The ``pyswarm`` package is a gradient-free, evolutionary optimization package -for python that supports constraints. - -Table of Contents -================= - -.. toctree:: - :maxdepth: 1 - -Overview -============ - -The package currently includes a single function for performing PSO: ``pso``. - -Requirements -============ - -- NumPy - -.. index:: installation - -Installation and download -========================= - -Important note --------------- - -The installation commands below should be **run in a DOS or Unix -command shell** (*not* in a Python shell). - -Under Windows (version 7 and earlier), a command shell can be obtained -by running ``cmd.exe`` (through the Runâ€Ļ menu item from the Start -menu). Under Unix (Linux, Mac OS X,â€Ļ), a Unix shell is available when -opening a terminal (in Mac OS X, the Terminal program is found in the -Utilities folder, which can be accessed through the Go menu in the -Finder). - -Automatic install or upgrade ----------------------------- - -One of the automatic installation or upgrade procedures below might work -on your system, if you have a Python package installer or use certain -Linux distributions. - -Under Unix, it may be necessary to prefix the commands below with -``sudo``, so that the installation program has **sufficient access -rights to the system**. - -If you have `pip `_, you can try to install -the latest version with - -.. code-block:: sh - - pip install --upgrade pyswarm - -If you have setuptools_, you can try to automatically install or -upgrade this package with - -.. code-block:: sh - - easy_install --upgrade pyswarm - -Manual download and install ---------------------------- - -Alternatively, you can simply download_ the package archive from the -Python Package Index (PyPI) and unpack it. The package can then be -installed by **going into the unpacked directory** -(:file:`pyswarm-...`), and running the provided :file:`setup.py` -program with - -.. code-block:: sh - - python setup.py install - -or, for an installation in the user Python library (no additional access -rights needed): - -.. code-block:: sh - - python setup.py install --user - -or, for an installation in a custom directory :file:`my_directory`: - -.. code-block:: sh - - python setup.py install --install-lib my_directory - -or, if additional access rights are needed (Unix): - -.. code-block:: sh - - sudo python setup.py install - -You can also simply **move** the :file:`pyswarm-py*` directory -that corresponds best to your version of Python to a location that -Python can import from (directory in which scripts using -:mod:`pyswarm` are run, etc.); the chosen -:file:`pyswarm-py*` directory should then be renamed -:file:`pyswarm`. Python 3 users should then run ``2to3 -w .`` -from inside this directory so as to automatically adapt the code to -Python 3. - -Source code ------------ - -The latest, bleeding-edge but working `code -`_ -and `documentation source -`_ are -available `on GitHub `_. - -.. index:: examples - -Example Usage -============= - -An Interesting Math Problem ---------------------------- - -To illustrate how ``pyswarm`` is to be best utilized, we'll start with a -complete example, which will be explained step-by-step afterwards: - -.. code-block:: python - - from pyswarm import pso - - def banana(x): - x1 = x[0] - x2 = x[1] - return x1**4 - 2*x2*x1**2 + x2**2 + x1**2 - 2*x1 + 5 - - def con(x): - x1 = x[0] - x2 = x[1] - return [-(x1 + 0.25)**2 + 0.75*x2] - - lb = [-3, -1] - ub = [2, 6] - - xopt, fopt = pso(banana, lb, ub, f_ieqcons=con) - - # Optimum should be around x=[0.5, 0.76] with banana(x)=4.5 and con(x)=0 - -Now let's walk through each section of code. We start off with any necessary -imports, in this case it's just the optimizer function ``pso``: - -.. code-block:: python - - from pyswarm import pso - -Then we define the objective function to be minimized, which should be defined -like ``myfunction(x, *args, **kwargs)``. In other words, it takes as its first -argument an 1-d array-like object, followed by any other (optional) arguments -and (again, optional) keyword arguments. The function should return a single -scalar value that is minimized. In this example, the ``banana`` -function: - -.. code-block:: python - - def banana(x): - x1 = x[0] - x2 = x[1] - return x1**4 - 2*x2*x1**2 + x2**2 + x1**2 - 2*x1 + 5 - -Optimizing with constraints is optional, but we include one here to illustrate -how it might be done in the ``con`` function which has the same call -syntax as the objective, but returns an array of values (even if it only has a -single value in it): - -.. code-block:: python - - def con(x): - x1 = x[0] - x2 = x[1] - return [-(x1 + 0.25)**2 + 0.75*x2] - -Rather than specify a starting point for the algorithm, we define the limits -of the input variables that the optimizer is allowed to search within. For the -sake of clarity, we have defined them prior to calling the optimizer in the -objects ``lb`` and ``ub``, which stand for *lower-bound* and *upper-bound*, -respectively: - -.. code-block:: python - - lb = [-3, -1] - ub = [2, 6] - -That is really all that *needs* to be defined to run ``pso``, so we then -call the optimizer: - -.. code-block:: python - - xopt, fopt = pso(banana, lb, ub, f_ieqcons=con) - -Using the kwarg ``f_ieqcons`` tells the routine that there's a single -constraint function that returns an array object. - -Once complete, ``pso`` returns two objects: 1) the optimal input values -and 2) the optimal objective value. - -The full call syntax for ``pso`` is highly customizable and is defined as -follows: - -.. code-block:: python - - pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, - swarmsize=100, omega=0.5, phip=0.5, phig=0.5, maxiter=100, minstep=1e-8, - minfunc=1e-8, debug=False) - -where the minimum required input arguments are: - - func : function - The function to be minimized - lb : array - The lower bounds of the design variable(s) - ub : array - The upper bounds of the design variable(s) - -and the optional input keyword-arguments are defined as: - - ieqcons : list - A list of functions of length n such that ieqcons[j](x,*args) >= 0.0 - in a successfully optimized problem (Default: empty list, []) - f_ieqcons : function - Returns a 1-D array in which each element must be greater or equal to - 0.0 in a successfully optimized problem. If f_ieqcons is specified, - ieqcons is ignored (Default: None) - args : tuple - Additional arguments passed to objective and constraint functions - (Default: empty tuple, ()) - kwargs : dict - Additional keyword arguments passed to objective and constraint - functions (Default: empty dict, {}) - swarmsize : int - The number of particles in the swarm (Default: 100) - omega : scalar - Particle velocity scaling factor (Default: 0.5) - phip : scalar - Scaling factor to search away from the particle's best known position - (Default: 0.5) - phig : scalar - Scaling factor to search away from the swarm's best known position - (Default: 0.5) - maxiter : int - The maximum number of iterations for the swarm to search (Default: 100) - minstep : scalar - The minimum stepsize of swarm's best position before the search - terminates (Default: 1e-8) - minfunc : scalar - The minimum change of swarm's best objective value before the search - terminates (Default: 1e-8) - debug : boolean - If True, progress statements will be displayed every iteration - (Default: False) - -We could have written the constraint function to return a scalar value instead -of an array-like object, like: - -.. code-block:: python - - def con(x): - x1 = x[0] - x2 = x[1] - return -(x1 + 0.25)**2 + 0.75*x2 - -In which case, we would have utilized the keyword-argument ``ieqcons``, which -takes an array of function handles, like: - -.. code-block:: python - - xopt, fopt = pso(banana, lb, ub, ieqcons=[con]) - -The parameters ``args`` and ``kwargs`` are used to pass any additional -parameters to the objective and constraint functions and are not changed during -the optimization process. - -The parameters ``omega``, ``phig`` and ``phip`` are a way of controlling how -closely the particles move away from their own best known position and the best -known position of all the particles in the swarm. These can take any scalar -value, but values between 0 and 1 seem to work best. - -Finally, the parameters ``maxiter``, ``minstep`` and ``minfunc`` are used to -tell the swarm when to stop searching. The last parameter ``debug`` can be -used to print out progress statements about the swarm. - -An Engineering Example ----------------------- - -Another useful example is in the design of a two-bar truss in the shape of an -A-frame. The objective of the problem is to minimize the weight of the truss -while satisfying three design constraints: - -- Yield Stress <= 100 kpsi -- Yield Stress <= Buckling Stress -- Deflection <= 0.25 in - -The design variables are: - -- ``H``: the height of the truss, in inches -- ``d``: the diameter of the truss tubes, in inches -- ``t``: the wall thickness of the tubes, in inches - -Other parameters that will be held constant are: - -- ``B``: the base separation distance, in inches -- ``rho``: the density of the truss material, in lb/in^3 -- ``E``: the modulus of elasticity of the truss material, in kpsi (1000-psi) -- ``P``: the downward vertical load on the top of the truss, in kip (1000-lbf) - -This example shows how the optional ``args`` parameter may be used to pass -other needed values to the objective and constraint functions. The complete -code is as follows: - -.. code-block:: python - - import numpy as np - from pyswarm import pso - - # Define the objective (to be minimize) - def weight(x, *args): - H, d, t = x - B, rho, E, P = args - return rho*2*np.pi*d*t*np.sqrt((B/2)**2 + H**2) - - # Setup the constraint functions - def yield_stress(x, *args): - H, d, t = x - B, rho, E, P = args - return (P*np.sqrt((B/2)**2 + H**2))/(2*t*np.pi*d*H) - - def buckling_stress(x, *args): - H, d, t = x - B, rho, E, P = args - return (np.pi**2*E*(d**2 + t**2))/(8*((B/2)**2 + H**2)) - - def deflection(x, *args): - H, d, t = x - B, rho, E, P = args - return (P*np.sqrt((B/2)**2 + H**2)**3)/(2*t*np.pi*d*H**2*E) - - def constraints(x, *args): - strs = yield_stress(x, *args) - buck = buckling_stress(x, *args) - defl = deflection(x, *args) - return [100 - strs, buck - strs, 0.25 - defl] - - # Define the other parameters - B = 60 # inches - rho = 0.3 # lb/in^3 - E = 30000 # kpsi (1000-psi) - P = 66 # kip (1000-lbs, force) - args = (B, rho, E, P) - - # Define the lower and upper bounds for H, d, t, respectively - lb = [10, 1, 0.01] - ub = [30, 3, 0.25] - - xopt, fopt = pso(weight, lb, ub, f_ieqcons=constraints, args=args) - - # The optimal input values are approximately - # xopt = [29, 2.4, 0.06] - # with function values approximately - # weight = 12 lbs - # yield stress = 100 kpsi (binding constraint) - # buckling stress = 150 kpsi - # deflection = 0.2 in - -Because there's an aspect of randomness in the algorithm, it is common to get a -slightly different result each time it is run. *This is to be expected.* - -Keeping everything else the same, we could have also defined the constraints -using ``ieqcons`` like this: - -.. code-block:: python - - ... - - # Setup the constraint functions - def yield_stress(x, *args): - H, d, t = x - B, rho, E, P = args - strs = (P*np.sqrt((B/2)**2 + H**2))/(2*t*np.pi*d*H) - return 100 - strs - - def buckling_stress(x, *args): - H, d, t = x - B, rho, E, P = args - buck = (np.pi**2*E*(d**2 + t**2))/(8*((B/2)**2 + H**2)) - strs = yield_stress(x, *args) - return buck - strs - - def deflection(x, *args): - H, d, t = x - B, rho, E, P = args - defl = (P*np.sqrt((B/2)**2 + H**2)**3)/(2*t*np.pi*d*H**2*E) - return 0.25 - defl - - ... - - cons = [yield_stress, buckling_stress, deflection] - - ... - - xopt, fopt = pso(weight, lb, ub, ieqcons=cons, args=args) - -And this would function the same way as the prior formulation. Use whichever -way works best for your application! - -.. index:: support - -Contact -======= - -Any feedback, questions, bug reports, or success stores should -be sent to the `author`_. I'd love to hear from you! - -License -======= - -This package is provided under two licenses: - -1. The *BSD License* -2. Any other that the author approves (just ask!) - -References -========== - -- `Particle swarm optimization`_ on Wikipedia - -.. _author: mailto:tisimst@gmail.com -.. _setuptools: http://pypi.python.org/pypi/setuptools -.. _download: http://pypi.python.org/pypi/pyswarm/#downloads -.. _Particle swarm optimization: http://en.wikipedia.org/wiki/Particle_swarm_optimization - - diff --git a/doc/_build/html/_static/ajax-loader.gif b/doc/_build/html/_static/ajax-loader.gif deleted file mode 100644 index 61faf8cab23993bd3e1560bff0668bd628642330..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN diff --git a/doc/_build/html/_static/basic.css b/doc/_build/html/_static/basic.css deleted file mode 100644 index 43e8baf..0000000 --- a/doc/_build/html/_static/basic.css +++ /dev/null @@ -1,540 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -/* -- 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%; -} - -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 input[type="text"] { - width: 170px; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - width: 30px; -} - -img { - border: 0; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.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%; -} - -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 dl, table.indextable dd { - margin-top: 0; - margin-bottom: 0; -} - -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; -} - -/* -- general body styles --------------------------------------------------- */ - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.field-list ul { - padding-left: 1em; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px 7px 0 7px; - background-color: #ffe; - width: 40%; - float: right; -} - -p.sidebar-title { - font-weight: bold; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px 7px 0 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; -} - -div.admonition dl { - margin-bottom: 0; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - border: 0; - border-collapse: collapse; -} - -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; -} - -table.field-list td, table.field-list th { - border: 0 !important; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -/* -- 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; -} - -dl { - margin-bottom: 15px; -} - -dd p { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dt:target, .highlighted { - background-color: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.refcount { - color: #060; -} - -.optional { - font-size: 1.3em; -} - -.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; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -td.linenos pre { - padding: 5px 0px; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -tt.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -tt.descclassname { - background-color: transparent; -} - -tt.xref, a tt { - background-color: transparent; - font-weight: bold; -} - -h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { - 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; -} - -/* -- 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/doc/_build/html/_static/comment-bright.png b/doc/_build/html/_static/comment-bright.png deleted file mode 100644 index 551517b8c83b76f734ff791f847829a760ad1903..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3500 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 A2LJ#7 diff --git a/doc/_build/html/_static/comment.png b/doc/_build/html/_static/comment.png deleted file mode 100644 index 92feb52b8824c6b0f59b658b1196c61de9162a95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3445 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 Xn!ZpXD%P(H00000NkvXXu0mjf;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^HyC+E#mt?nx10eANtU=qlsM<-=BDPAFgO>bCYGe8D3oWG zWGJ|M`UZqI@`(c#nR~i8hHzY8+H1+jpulh_>fir3VfEN66+L= 0 && !jQuery(node.parentNode).hasClass(className)) { - var span = document.createElement("span"); - span.className = className; - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this); - }); - } - } - return this.each(function() { - highlight(this); - }); -}; - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated == 'undefined') - return string; - return (typeof translated == 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated == 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) == 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this == '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/doc/_build/html/_static/down-pressed.png b/doc/_build/html/_static/down-pressed.png deleted file mode 100644 index 6f7ad782782e4f8e39b0c6e15c7344700cdd2527..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}Z23@f-Ava~9&<9T!#}JFtXD=!G zGdl{fK6ro2OGiOl+hKvH6i=D3%%Y^j`yIkRn!8O>@bG)IQR0{Kf+mxNd=_WScA8u_ z3;8(7x2){m9`nt+U(Nab&1G)!{`SPVpDX$w8McLTzAJ39wprG3p4XLq$06M`%}2Yk zRPPsbES*dnYm1wkGL;iioAUB*Or2kz6(-M_r_#Me-`{mj$Z%( diff --git a/doc/_build/html/_static/down.png b/doc/_build/html/_static/down.png deleted file mode 100644 index 3003a88770de3977d47a2ba69893436a2860f9e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}xaV3tUZ$qnrLa#kt978NlpS`ru z&)HFc^}^>{UOEce+71h5nn>6&w6A!ieNbu1wh)UGh{8~et^#oZ1# z>T7oM=FZ~xXWnTo{qnXm$ZLOlqGswI_m2{XwVK)IJmBjW{J3-B3x@C=M{ShWt#fYS9M?R;8K$~YwlIqwf>VA7q=YKcwf2DS4Zj5inDKXXB1zl=(YO3ST6~rDq)&z z*o>z)=hxrfG-cDBW0G$!?6{M<$@{_4{m1o%Ub!naEtn|@^frU1tDnm{r-UW|!^@B8 diff --git a/doc/_build/html/_static/file.png b/doc/_build/html/_static/file.png deleted file mode 100644 index d18082e397e7e54f20721af768c4c2983258f1b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$HyOL$D9)yc9|lc|nKf<9@eUiWd>3GuTC!a5vdfWYEazjncPj5ZQX%+1 zt8B*4=d)!cdDz4wr^#OMYfqGz$1LDFF>|#>*O?AGil(WEs?wLLy{Gj2J_@opDm%`dlax3yA*@*N$G&*ukFv>P8+2CBWO(qz zD0k1@kN>hhb1_6`&wrCswzINE(evt-5C1B^STi2@PmdKI;Vst0PQB6!2kdN diff --git a/doc/_build/html/_static/jquery.js b/doc/_build/html/_static/jquery.js deleted file mode 100644 index e2efc33..0000000 --- a/doc/_build/html/_static/jquery.js +++ /dev/null @@ -1,9404 +0,0 @@ -/*! - * jQuery JavaScript Library v1.7.2 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Fri Jul 5 14:07:58 UTC 2013 - */ -(function( window, undefined ) { - -// Use the correct document accordingly with window argument (sandbox) -var document = window.document, - navigator = window.navigator, - location = window.location; -var jQuery = (function() { - -// Define a local copy of jQuery -var jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // A central reference to the root jQuery(document) - rootjQuery, - - // A simple way to check for HTML strings or ID strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Check if a string has a non-whitespace character in it - rnotwhite = /\S/, - - // Used for trimming whitespace - trimLeft = /^\s+/, - trimRight = /\s+$/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, - rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - - // Useragent RegExp - rwebkit = /(webkit)[ \/]([\w.]+)/, - ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, - rmsie = /(msie) ([\w.]+)/, - rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, - - // Matches dashed string for camelizing - rdashAlpha = /-([a-z]|[0-9])/ig, - rmsPrefix = /^-ms-/, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // Keep a UserAgent string for use with jQuery.browser - userAgent = navigator.userAgent, - - // For matching the engine and version of the browser - browserMatch, - - // The deferred used on DOM ready - readyList, - - // The ready event handler - DOMContentLoaded, - - // Save a reference to some core methods - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - push = Array.prototype.push, - slice = Array.prototype.slice, - trim = String.prototype.trim, - indexOf = Array.prototype.indexOf, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), or $(undefined) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // The body element only exists once, optimize finding it - if ( selector === "body" && !context && document.body ) { - this.context = document; - this[0] = document.body; - this.selector = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = quickExpr.exec( selector ); - } - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context ? context.ownerDocument || context : document ); - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - ret = rsingleTag.exec( selector ); - - if ( ret ) { - if ( jQuery.isPlainObject( context ) ) { - selector = [ document.createElement( ret[1] ) ]; - jQuery.fn.attr.call( selector, context, true ); - - } else { - selector = [ doc.createElement( ret[1] ) ]; - } - - } else { - ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); - selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; - } - - return jQuery.merge( this, selector ); - - // HANDLE: $("#id") - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.7.2", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return slice.call( this, 0 ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - // Build a new jQuery matched element set - var ret = this.constructor(); - - if ( jQuery.isArray( elems ) ) { - push.apply( ret, elems ); - - } else { - jQuery.merge( ret, elems ); - } - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Attach the listeners - jQuery.bindReady(); - - // Add the callback - readyList.add( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ), - "slice", slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - // Either a released hold or an DOMready/load event and not yet ready - if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.fireWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger( "ready" ).off( "ready" ); - } - } - }, - - bindReady: function() { - if ( readyList ) { - return; - } - - readyList = jQuery.Callbacks( "once memory" ); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - return setTimeout( jQuery.ready, 1 ); - } - - // Mozilla, Opera and webkit nightlies currently support this event - if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else if ( document.attachEvent ) { - // ensure firing before onload, - // maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var toplevel = false; - - try { - toplevel = window.frameElement == null; - } catch(e) {} - - if ( document.documentElement.doScroll && toplevel ) { - doScrollCheck(); - } - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - for ( var name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - parseJSON: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - var xml, tmp; - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - var name, i = 0, - length = object.length, - isObj = length === undefined || jQuery.isFunction( object ); - - if ( args ) { - if ( isObj ) { - for ( name in object ) { - if ( callback.apply( object[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( object[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in object ) { - if ( callback.call( object[ name ], name, object[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { - break; - } - } - } - } - - return object; - }, - - // Use native String.trim function wherever possible - trim: trim ? - function( text ) { - return text == null ? - "" : - trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); - }, - - // results is for internal usage only - makeArray: function( array, results ) { - var ret = results || []; - - if ( array != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type( array ); - - if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { - push.call( ret, array ); - } else { - jQuery.merge( ret, array ); - } - } - - return ret; - }, - - inArray: function( elem, array, i ) { - var len; - - if ( array ) { - if ( indexOf ) { - return indexOf.call( array, elem, i ); - } - - len = array.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in array && array[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var i = first.length, - j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var ret = [], retVal; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( var i = 0, length = elems.length; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - if ( typeof context === "string" ) { - var tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - var args = slice.call( arguments, 2 ), - proxy = function() { - return fn.apply( context, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Mutifunctional method to get and set values to a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - }, - - // Use of jQuery.browser is frowned upon. - // More details: http://docs.jquery.com/Utilities/jQuery.browser - uaMatch: function( ua ) { - ua = ua.toLowerCase(); - - var match = rwebkit.exec( ua ) || - ropera.exec( ua ) || - rmsie.exec( ua ) || - ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || - []; - - return { browser: match[1] || "", version: match[2] || "0" }; - }, - - sub: function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; - }, - - browser: {} -}); - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -browserMatch = jQuery.uaMatch( userAgent ); -if ( browserMatch.browser ) { - jQuery.browser[ browserMatch.browser ] = true; - jQuery.browser.version = browserMatch.version; -} - -// Deprecated, use jQuery.browser.webkit instead -if ( jQuery.browser.webkit ) { - jQuery.browser.safari = true; -} - -// IE doesn't match non-breaking spaces with \s -if ( rnotwhite.test( "\xA0" ) ) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); - -// Cleanup functions for the document ready method -if ( document.addEventListener ) { - DOMContentLoaded = function() { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - }; - -} else if ( document.attachEvent ) { - DOMContentLoaded = function() { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }; -} - -// The DOM ready check for Internet Explorer -function doScrollCheck() { - if ( jQuery.isReady ) { - return; - } - - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); - } catch(e) { - setTimeout( doScrollCheck, 1 ); - return; - } - - // and execute any waiting functions - jQuery.ready(); -} - -return jQuery; - -})(); - - -// String to Object flags format cache -var flagsCache = {}; - -// Convert String-formatted flags into Object-formatted ones and store in cache -function createFlags( flags ) { - var object = flagsCache[ flags ] = {}, - i, length; - flags = flags.split( /\s+/ ); - for ( i = 0, length = flags.length; i < length; i++ ) { - object[ flags[i] ] = true; - } - return object; -} - -/* - * Create a callback list using the following parameters: - * - * flags: an optional list of space-separated flags that will change how - * the callback list behaves - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible flags: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( flags ) { - - // Convert flags from String-formatted to Object-formatted - // (we check in cache first) - flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; - - var // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = [], - // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Add one or several callbacks to the list - add = function( args ) { - var i, - length, - elem, - type, - actual; - for ( i = 0, length = args.length; i < length; i++ ) { - elem = args[ i ]; - type = jQuery.type( elem ); - if ( type === "array" ) { - // Inspect recursively - add( elem ); - } else if ( type === "function" ) { - // Add if not in unique mode and callback is not in - if ( !flags.unique || !self.has( elem ) ) { - list.push( elem ); - } - } - } - }, - // Fire callbacks - fire = function( context, args ) { - args = args || []; - memory = !flags.memory || [ context, args ]; - fired = true; - firing = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { - memory = true; // Mark as halted - break; - } - } - firing = false; - if ( list ) { - if ( !flags.once ) { - if ( stack && stack.length ) { - memory = stack.shift(); - self.fireWith( memory[ 0 ], memory[ 1 ] ); - } - } else if ( memory === true ) { - self.disable(); - } else { - list = []; - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - var length = list.length; - add( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away, unless previous - // firing was halted (stopOnFalse) - } else if ( memory && memory !== true ) { - firingStart = length; - fire( memory[ 0 ], memory[ 1 ] ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - var args = arguments, - argIndex = 0, - argLength = args.length; - for ( ; argIndex < argLength ; argIndex++ ) { - for ( var i = 0; i < list.length; i++ ) { - if ( args[ argIndex ] === list[ i ] ) { - // Handle firingIndex and firingLength - if ( firing ) { - if ( i <= firingLength ) { - firingLength--; - if ( i <= firingIndex ) { - firingIndex--; - } - } - } - // Remove the element - list.splice( i--, 1 ); - // If we have some unicity property then - // we only need to do this once - if ( flags.unique ) { - break; - } - } - } - } - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - if ( list ) { - var i = 0, - length = list.length; - for ( ; i < length; i++ ) { - if ( fn === list[ i ] ) { - return true; - } - } - } - return false; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory || memory === true ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( stack ) { - if ( firing ) { - if ( !flags.once ) { - stack.push( [ context, args ] ); - } - } else if ( !( flags.once && memory ) ) { - fire( context, args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - - - -var // Static reference to slice - sliceDeferred = [].slice; - -jQuery.extend({ - - Deferred: function( func ) { - var doneList = jQuery.Callbacks( "once memory" ), - failList = jQuery.Callbacks( "once memory" ), - progressList = jQuery.Callbacks( "memory" ), - state = "pending", - lists = { - resolve: doneList, - reject: failList, - notify: progressList - }, - promise = { - done: doneList.add, - fail: failList.add, - progress: progressList.add, - - state: function() { - return state; - }, - - // Deprecated - isResolved: doneList.fired, - isRejected: failList.fired, - - then: function( doneCallbacks, failCallbacks, progressCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); - return this; - }, - always: function() { - deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); - return this; - }, - pipe: function( fnDone, fnFail, fnProgress ) { - return jQuery.Deferred(function( newDefer ) { - jQuery.each( { - done: [ fnDone, "resolve" ], - fail: [ fnFail, "reject" ], - progress: [ fnProgress, "notify" ] - }, function( handler, data ) { - var fn = data[ 0 ], - action = data[ 1 ], - returned; - if ( jQuery.isFunction( fn ) ) { - deferred[ handler ](function() { - returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - }); - } else { - deferred[ handler ]( newDefer[ action ] ); - } - }); - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - obj = promise; - } else { - for ( var key in promise ) { - obj[ key ] = promise[ key ]; - } - } - return obj; - } - }, - deferred = promise.promise({}), - key; - - for ( key in lists ) { - deferred[ key ] = lists[ key ].fire; - deferred[ key + "With" ] = lists[ key ].fireWith; - } - - // Handle state - deferred.done( function() { - state = "resolved"; - }, failList.disable, progressList.lock ).fail( function() { - state = "rejected"; - }, doneList.disable, progressList.lock ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( firstParam ) { - var args = sliceDeferred.call( arguments, 0 ), - i = 0, - length = args.length, - pValues = new Array( length ), - count = length, - pCount = length, - deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? - firstParam : - jQuery.Deferred(), - promise = deferred.promise(); - function resolveFunc( i ) { - return function( value ) { - args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - if ( !( --count ) ) { - deferred.resolveWith( deferred, args ); - } - }; - } - function progressFunc( i ) { - return function( value ) { - pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - deferred.notifyWith( promise, pValues ); - }; - } - if ( length > 1 ) { - for ( ; i < length; i++ ) { - if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { - args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); - } else { - --count; - } - } - if ( !count ) { - deferred.resolveWith( deferred, args ); - } - } else if ( deferred !== firstParam ) { - deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); - } - return promise; - } -}); - - - - -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - tds, - events, - eventName, - i, - isSupported, - div = document.createElement( "div" ), - documentElement = document.documentElement; - - // Preliminary tests - div.setAttribute("className", "t"); - div.innerHTML = "
a"; - - all = div.getElementsByTagName( "*" ); - a = div.getElementsByTagName( "a" )[ 0 ]; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement( "select" ); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName( "input" )[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - pixelMargin: true - }; - - // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead - jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent( "onclick" ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute("type", "radio"); - support.radioValue = input.value === "t"; - - input.setAttribute("checked", "checked"); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: 1, - change: 1, - focusin: 1 - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - fragment.removeChild( div ); - - // Null elements to avoid leaks in IE - fragment = select = opt = div = input = null; - - // Run tests that need a body at doc ready - jQuery(function() { - var container, outer, inner, table, td, offsetSupport, - marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, - paddingMarginBorderVisibility, paddingMarginBorder, - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - conMarginTop = 1; - paddingMarginBorder = "padding:0;margin:0;border:"; - positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; - paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; - style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; - html = "
" + - "" + - "
"; - - container = document.createElement("div"); - container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
t
"; - tds = div.getElementsByTagName( "td" ); - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - if ( window.getComputedStyle ) { - div.innerHTML = ""; - marginDiv = document.createElement( "div" ); - marginDiv.style.width = "0"; - marginDiv.style.marginRight = "0"; - div.style.width = "2px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.width = div.style.padding = "1px"; - div.style.border = 0; - div.style.overflow = "hidden"; - div.style.display = "inline"; - div.style.zoom = 1; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - } - - div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; - div.innerHTML = html; - - outer = div.firstChild; - inner = outer.firstChild; - td = outer.nextSibling.firstChild.firstChild; - - offsetSupport = { - doesNotAddBorder: ( inner.offsetTop !== 5 ), - doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) - }; - - inner.style.position = "fixed"; - inner.style.top = "20px"; - - // safari subtracts parent border width here which is 5px - offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); - inner.style.position = inner.style.top = ""; - - outer.style.overflow = "hidden"; - outer.style.position = "relative"; - - offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); - offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); - - if ( window.getComputedStyle ) { - div.style.marginTop = "1%"; - support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; - } - - if ( typeof container.style.zoom !== "undefined" ) { - container.style.zoom = 1; - } - - body.removeChild( container ); - marginDiv = div = container = null; - - jQuery.extend( support, offsetSupport ); - }); - - return support; -})(); - - - - -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var privateCache, thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, - isEvents = name === "events"; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - privateCache = thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Users should not attempt to inspect the internal events object using jQuery.data, - // it is undocumented and subject to change. But does anyone listen? No. - if ( isEvents && !thisCache[ name ] ) { - return privateCache.events; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - // Reference to internal data cache key - internalKey = jQuery.expando, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - - // See jQuery.data for more information - id = isNode ? elem[ internalKey ] : internalKey; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split( " " ); - } - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject(cache[ id ]) ) { - return; - } - } - - // Browsers that fail expando deletion also refuse to delete expandos on - // the window, but it will allow it on all other JS objects; other browsers - // don't care - // Ensure that `cache` is not a window object #10080 - if ( jQuery.support.deleteExpando || !cache.setInterval ) { - delete cache[ id ]; - } else { - cache[ id ] = null; - } - - // We destroyed the cache and need to eliminate the expando on the node to avoid - // false lookups in the cache for entries that no longer exist - if ( isNode ) { - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( jQuery.support.deleteExpando ) { - delete elem[ internalKey ]; - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - } else { - elem[ internalKey ] = null; - } - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - if ( elem.nodeName ) { - var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; - - if ( match ) { - return !(match === true || elem.getAttribute("classid") !== match); - } - } - - return true; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - jQuery.isNumeric( data ) ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - for ( var name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} - - - - -function handleQueueMarkDefer( elem, type, src ) { - var deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - defer = jQuery._data( elem, deferDataKey ); - if ( defer && - ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && - ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { - // Give room for hard-coded callbacks to fire first - // and eventually mark/queue something else on the element - setTimeout( function() { - if ( !jQuery._data( elem, queueDataKey ) && - !jQuery._data( elem, markDataKey ) ) { - jQuery.removeData( elem, deferDataKey, true ); - defer.fire(); - } - }, 0 ); - } -} - -jQuery.extend({ - - _mark: function( elem, type ) { - if ( elem ) { - type = ( type || "fx" ) + "mark"; - jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); - } - }, - - _unmark: function( force, elem, type ) { - if ( force !== true ) { - type = elem; - elem = force; - force = false; - } - if ( elem ) { - type = type || "fx"; - var key = type + "mark", - count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); - if ( count ) { - jQuery._data( elem, key, count ); - } else { - jQuery.removeData( elem, key, true ); - handleQueueMarkDefer( elem, type, "mark" ); - } - } - }, - - queue: function( elem, type, data ) { - var q; - if ( elem ) { - type = ( type || "fx" ) + "queue"; - q = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !q || jQuery.isArray(data) ) { - q = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - q.push( data ); - } - } - return q || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = {}; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - jQuery._data( elem, type + ".run", hooks ); - fn.call( elem, function() { - jQuery.dequeue( elem, type ); - }, hooks ); - } - - if ( !queue.length ) { - jQuery.removeData( elem, type + "queue " + type + ".run", true ); - handleQueueMarkDefer( elem, type, "queue" ); - } - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, object ) { - if ( typeof type !== "string" ) { - object = type; - type = undefined; - } - type = type || "fx"; - var defer = jQuery.Deferred(), - elements = this, - i = elements.length, - count = 1, - deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - tmp; - function resolve() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - } - while( i-- ) { - if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || - ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || - jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && - jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { - count++; - tmp.add( resolve ); - } - } - resolve(); - return defer.promise( object ); - } -}); - - - - -var rclass = /[\n\t\r]/g, - rspace = /\s+/, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea)?$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute, - nodeHook, boolHook, fixSpecified; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classNames, i, l, elem, className, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - - if ( (value && typeof value === "string") || value === undefined ) { - classNames = ( value || "" ).split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 && elem.className ) { - if ( value ) { - className = (" " + elem.className + " ").replace( rclass, " " ); - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[ c ] + " ", " "); - } - elem.className = jQuery.trim( className ); - - } else { - elem.className = ""; - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space seperated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var self = jQuery(this), val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attrFn: { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true - }, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && name in jQuery.attrFn ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, l, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - attrNames = value.toLowerCase().split( rspace ); - l = attrNames.length; - - for ( ; i < l; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) -jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? - ret.nodeValue : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.nodeValue = value + "" ); - } - }; - - // Apply the nodeHook to tabindex - jQuery.attrHooks.tabindex.set = nodeHook.set; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); - - - - -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, - rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, - quickParse = function( selector ) { - var quick = rquickIs.exec( selector ); - if ( quick ) { - // 0 1 2 3 - // [ _, tag, id, class ] - quick[1] = ( quick[1] || "" ).toLowerCase(); - quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); - } - return quick; - }, - quickIs = function( elem, m ) { - var attrs = elem.attributes || {}; - return ( - (!m[1] || elem.nodeName.toLowerCase() === m[1]) && - (!m[2] || (attrs.id || {}).value === m[2]) && - (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) - ); - }, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, quick, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - quick: selector && quickParse( selector ), - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), - t, tns, type, origType, namespaces, origCount, - j, events, special, handle, eventType, handleObj; - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - handle = elemData.handle; - if ( handle ) { - handle.elem = null; - } - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, [ "events", "handle" ], true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var type = event.type || event, - namespaces = [], - cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - old = null; - for ( ; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old && old === elem.ownerDocument ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments, 0 ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = [], - i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this.ownerDocument || this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process events on disabled elements (#6911, #8165) - if ( cur.disabled !== true ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = ( - handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) - ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) - if ( event.metaKey === undefined ) { - event.metaKey = event.ctrlKey; - } - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - if ( elem.detachEvent ) { - elem.detachEvent( "on" + type, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector, - ret; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !form._submit_attached ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - form._submit_attached = true; - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - jQuery.event.simulate( "change", this, event, true ); - } - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - elem._change_attached = true; - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - var handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( var type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( jQuery.attrFn ) { - jQuery.attrFn[ name ] = true; - } - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); - - - -/*! - * Sizzle CSS Selector Engine - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - expando = "sizcache" + (Math.random() + '').replace('.', ''), - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true, - rBackslash = /\\/g, - rReturn = /\r\n/g, - rNonWord = /\W/; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - baseHasDuplicate = false; - return 0; -}); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - - var origContext = context; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var m, set, checkSet, extra, ret, cur, pop, i, - prune = true, - contextXML = Sizzle.isXML( context ), - parts = [], - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - do { - chunker.exec( "" ); - m = chunker.exec( soFar ); - - if ( m ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - } while ( m ); - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context, seed ); - - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) { - selector += parts.shift(); - } - - set = posProcess( selector, set, seed ); - } - } - - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - - ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? - Sizzle.filter( ret.expr, ret.set )[0] : - ret.set[0]; - } - - if ( context ) { - ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - - set = ret.expr ? - Sizzle.filter( ret.expr, ret.set ) : - ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray( set ); - - } else { - prune = false; - } - - while ( parts.length ) { - cur = parts.pop(); - pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - Sizzle.error( cur || selector ); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - - } else if ( context && context.nodeType === 1 ) { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - - } else { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function( results ) { - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -Sizzle.matches = function( expr, set ) { - return Sizzle( expr, null, null, set ); -}; - -Sizzle.matchesSelector = function( node, expr ) { - return Sizzle( expr, null, null, [node] ).length > 0; -}; - -Sizzle.find = function( expr, context, isXML ) { - var set, i, len, match, type, left; - - if ( !expr ) { - return []; - } - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - left = match[1]; - match.splice( 1, 1 ); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace( rBackslash, "" ); - set = Expr.find[ type ]( match, context, isXML ); - - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = typeof context.getElementsByTagName !== "undefined" ? - context.getElementsByTagName( "*" ) : - []; - } - - return { set: set, expr: expr }; -}; - -Sizzle.filter = function( expr, set, inplace, not ) { - var match, anyFound, - type, found, item, filter, left, - i, pass, - old = expr, - result = [], - curLoop = set, - isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); - - while ( expr && set.length ) { - for ( type in Expr.filter ) { - if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - filter = Expr.filter[ type ]; - left = match[1]; - - anyFound = false; - - match.splice(1,1); - - if ( left.substr( left.length - 1 ) === "\\" ) { - continue; - } - - if ( curLoop === result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - pass = not ^ found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - - } else { - curLoop[i] = false; - } - - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr === old ) { - if ( anyFound == null ) { - Sizzle.error( expr ); - - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Utility function for retreiving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var i, node, - nodeType = elem.nodeType, - ret = ""; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent || innerText for elements - if ( typeof elem.textContent === 'string' ) { - return elem.textContent; - } else if ( typeof elem.innerText === 'string' ) { - // Replace IE's carriage returns - return elem.innerText.replace( rReturn, '' ); - } else { - // Traverse it's children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - } else { - - // If no nodeType, this is expected to be an array - for ( i = 0; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - if ( node.nodeType !== 8 ) { - ret += getText( node ); - } - } - } - return ret; -}; - -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - - match: { - ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ - }, - - leftMatch: {}, - - attrMap: { - "class": "className", - "for": "htmlFor" - }, - - attrHandle: { - href: function( elem ) { - return elem.getAttribute( "href" ); - }, - type: function( elem ) { - return elem.getAttribute( "type" ); - } - }, - - relative: { - "+": function(checkSet, part){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !rNonWord.test( part ), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag ) { - part = part.toLowerCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - - ">": function( checkSet, part ) { - var elem, - isPartStr = typeof part === "string", - i = 0, - l = checkSet.length; - - if ( isPartStr && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; - } - } - - } else { - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - - "": function(checkSet, part, isXML){ - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); - }, - - "~": function( checkSet, part, isXML ) { - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); - } - }, - - find: { - ID: function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }, - - NAME: function( match, context ) { - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], - results = context.getElementsByName( match[1] ); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - - TAG: function( match, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( match[1] ); - } - } - }, - preFilter: { - CLASS: function( match, curLoop, inplace, result, not, isXML ) { - match = " " + match[1].replace( rBackslash, "" ) + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { - if ( !inplace ) { - result.push( elem ); - } - - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - - ID: function( match ) { - return match[1].replace( rBackslash, "" ); - }, - - TAG: function( match, curLoop ) { - return match[1].replace( rBackslash, "" ).toLowerCase(); - }, - - CHILD: function( match ) { - if ( match[1] === "nth" ) { - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - match[2] = match[2].replace(/^\+|\s*/g, ''); - - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( - match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - - ATTR: function( match, curLoop, inplace, result, not, isXML ) { - var name = match[1] = match[1].replace( rBackslash, "" ); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - // Handle if an un-quoted value was used - match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - - PSEUDO: function( match, curLoop, inplace, result, not ) { - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - - if ( !inplace ) { - result.push.apply( result, ret ); - } - - return false; - } - - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - - POS: function( match ) { - match.unshift( true ); - - return match; - } - }, - - filters: { - enabled: function( elem ) { - return elem.disabled === false && elem.type !== "hidden"; - }, - - disabled: function( elem ) { - return elem.disabled === true; - }, - - checked: function( elem ) { - return elem.checked === true; - }, - - selected: function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - parent: function( elem ) { - return !!elem.firstChild; - }, - - empty: function( elem ) { - return !elem.firstChild; - }, - - has: function( elem, i, match ) { - return !!Sizzle( match[3], elem ).length; - }, - - header: function( elem ) { - return (/h\d/i).test( elem.nodeName ); - }, - - text: function( elem ) { - var attr = elem.getAttribute( "type" ), type = elem.type; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); - }, - - radio: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; - }, - - checkbox: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; - }, - - file: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; - }, - - password: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; - }, - - submit: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "submit" === elem.type; - }, - - image: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; - }, - - reset: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "reset" === elem.type; - }, - - button: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && "button" === elem.type || name === "button"; - }, - - input: function( elem ) { - return (/input|select|textarea|button/i).test( elem.nodeName ); - }, - - focus: function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - setFilters: { - first: function( elem, i ) { - return i === 0; - }, - - last: function( elem, i, match, array ) { - return i === array.length - 1; - }, - - even: function( elem, i ) { - return i % 2 === 0; - }, - - odd: function( elem, i ) { - return i % 2 === 1; - }, - - lt: function( elem, i, match ) { - return i < match[3] - 0; - }, - - gt: function( elem, i, match ) { - return i > match[3] - 0; - }, - - nth: function( elem, i, match ) { - return match[3] - 0 === i; - }, - - eq: function( elem, i, match ) { - return match[3] - 0 === i; - } - }, - filter: { - PSEUDO: function( elem, match, i, array ) { - var name = match[1], - filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; - - } else if ( name === "not" ) { - var not = match[3]; - - for ( var j = 0, l = not.length; j < l; j++ ) { - if ( not[j] === elem ) { - return false; - } - } - - return true; - - } else { - Sizzle.error( name ); - } - }, - - CHILD: function( elem, match ) { - var first, last, - doneName, parent, cache, - count, diff, - type = match[1], - node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - - case "nth": - first = match[2]; - last = match[3]; - - if ( first === 1 && last === 0 ) { - return true; - } - - doneName = match[0]; - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { - count = 0; - - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - - parent[ expando ] = doneName; - } - - diff = elem.nodeIndex - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - } - }, - - ID: function( elem, match ) { - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - - TAG: function( elem, match ) { - return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; - }, - - CLASS: function( elem, match ) { - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - - ATTR: function( elem, match ) { - var name = match[1], - result = Sizzle.attr ? - Sizzle.attr( elem, name ) : - Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - !type && Sizzle.attr ? - result != null : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value !== check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - - POS: function( elem, match, i, array ) { - var name = match[2], - filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS, - fescape = function(all, num){ - return "\\" + (num - 0 + 1); - }; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); -} -// Expose origPOS -// "global" as in regardless of relation to brackets/parens -Expr.match.globalPOS = origPOS; - -var makeArray = function( array, results ) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -// Also verifies that the returned array holds DOM nodes -// (which is not the case in the Blackberry browser) -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; - -// Provide a fallback method if it does not work -} catch( e ) { - makeArray = function( array, results ) { - var i = 0, - ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - - } else { - if ( typeof array.length === "number" ) { - for ( var l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - - } else { - for ( ; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder, siblingCheck; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - return a.compareDocumentPosition ? -1 : 1; - } - - return a.compareDocumentPosition(b) & 4 ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - var form = document.createElement("div"), - id = "script" + (new Date()).getTime(), - root = document.documentElement; - - form.innerHTML = ""; - - // Inject it into the root element, check its status, and remove it quickly - root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - if ( document.getElementById( id ) ) { - Expr.find.ID = function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - - return m ? - m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? - [m] : - undefined : - []; - } - }; - - Expr.filter.ID = function( elem, match ) { - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } - - root.removeChild( form ); - - // release memory in IE - root = form = null; -})(); - -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); - - // Make sure no comments are found - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function( match, context ) { - var results = context.getElementsByTagName( match[1] ); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - } - - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - - Expr.attrHandle.href = function( elem ) { - return elem.getAttribute( "href", 2 ); - }; - } - - // release memory in IE - div = null; -})(); - -if ( document.querySelectorAll ) { - (function(){ - var oldSizzle = Sizzle, - div = document.createElement("div"), - id = "__sizzle__"; - - div.innerHTML = "

"; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function( query, context, extra, seed ) { - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && !Sizzle.isXML(context) ) { - // See if we find a selector to speed up - var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); - - if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { - // Speed-up: Sizzle("TAG") - if ( match[1] ) { - return makeArray( context.getElementsByTagName( query ), extra ); - - // Speed-up: Sizzle(".CLASS") - } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { - return makeArray( context.getElementsByClassName( match[2] ), extra ); - } - } - - if ( context.nodeType === 9 ) { - // Speed-up: Sizzle("body") - // The body element only exists once, optimize finding it - if ( query === "body" && context.body ) { - return makeArray( [ context.body ], extra ); - - // Speed-up: Sizzle("#ID") - } else if ( match && match[3] ) { - var elem = context.getElementById( match[3] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id === match[3] ) { - return makeArray( [ elem ], extra ); - } - - } else { - return makeArray( [], extra ); - } - } - - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(qsaError) {} - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var oldContext = context, - old = context.getAttribute( "id" ), - nid = old || id, - hasParent = context.parentNode, - relativeHierarchySelector = /^\s*[+~]/.test( query ); - - if ( !old ) { - context.setAttribute( "id", nid ); - } else { - nid = nid.replace( /'/g, "\\$&" ); - } - if ( relativeHierarchySelector && hasParent ) { - context = context.parentNode; - } - - try { - if ( !relativeHierarchySelector || hasParent ) { - return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); - } - - } catch(pseudoError) { - } finally { - if ( !old ) { - oldContext.removeAttribute( "id" ); - } - } - } - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - // release memory in IE - div = null; - })(); -} - -(function(){ - var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; - - if ( matches ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9 fails this) - var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), - pseudoWorks = false; - - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); - - } catch( pseudoError ) { - pseudoWorks = true; - } - - Sizzle.matchesSelector = function( node, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); - - if ( !Sizzle.isXML( node ) ) { - try { - if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - var ret = matches.call( node, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || !disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9, so check for that - node.document && node.document.nodeType !== 11 ) { - return ret; - } - } - } catch(e) {} - } - - return Sizzle(expr, null, null, [node]).length > 0; - }; - } -})(); - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
"; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function( match, context, isXML ) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - // release memory in IE - div = null; -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem[ expando ] === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem[ expando ] = doneName; - elem.sizset = i; - } - - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem[ expando ] === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem[ expando ] = doneName; - elem.sizset = i; - } - - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -if ( document.documentElement.contains ) { - Sizzle.contains = function( a, b ) { - return a !== b && (a.contains ? a.contains(b) : true); - }; - -} else if ( document.documentElement.compareDocumentPosition ) { - Sizzle.contains = function( a, b ) { - return !!(a.compareDocumentPosition(b) & 16); - }; - -} else { - Sizzle.contains = function() { - return false; - }; -} - -Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; - - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -var posProcess = function( selector, context, seed ) { - var match, - tmpSet = [], - later = "", - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet, seed ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -Sizzle.selectors.attrMap = {}; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})(); - - -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - isSimple = /^.[^:#\[\.,]*$/, - slice = Array.prototype.slice, - POS = jQuery.expr.match.globalPOS, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var self = this, - i, l; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - var ret = this.pushStack( "", "find", selector ), - length, n, r; - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - POS.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var ret = [], i, l, cur = this[0]; - - // Array (deprecated as of jQuery 1.7) - if ( jQuery.isArray( selectors ) ) { - var level = 1; - - while ( cur && cur.ownerDocument && cur !== context ) { - for ( i = 0; i < selectors.length; i++ ) { - - if ( jQuery( cur ).is( selectors[ i ] ) ) { - ret.push({ selector: selectors[ i ], elem: cur, level: level }); - } - } - - cur = cur.parentNode; - level++; - } - - return ret; - } - - // String - var pos = POS.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( i = 0, l = this.length; i < l; i++ ) { - cur = this[i]; - - while ( cur ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - - } else { - cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { - break; - } - } - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - andSelf: function() { - return this.add( this.prevObject ); - } -}); - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - nth: function( cur, result, dir, elem ) { - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; - } - } - - return cur; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} - - - - -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, - rtagName = /<([\w:]+)/, - rtbody = /]", "i"), - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*", "" ], - legend: [ 1, "
", "
" ], - thead: [ 1, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - col: [ 2, "", "
" ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE can't serialize and - - - - - - - - -
-ad -
- - - - - -
-
-

Table of contents

-
    -
- - - - - - -

Documentation license

-Creative Commons License -
-
- -
-
-
-
- - -

Index

- -
- E - | I - | S - -
-

E

- - -
- -
examples -
- -
- -

I

- - -
- -
installation -
- -
- -

S

- - -
- -
support -
- -
- - - -
-
-
-
-
- - - - \ No newline at end of file diff --git a/doc/_build/html/index.html b/doc/_build/html/index.html deleted file mode 100644 index 664dbe3..0000000 --- a/doc/_build/html/index.html +++ /dev/null @@ -1,516 +0,0 @@ - - - - - - - - - - - - Particle swarm optimization (PSO) with constraint support — pyswarm 0.5 documentation - - - - - - - - - - - - - -
-ad -
- - - - - -
-
-

Table of contents

-
    -
- -

Section contents

- - - - -

Documentation license

-Creative Commons License -
-
- -
-
-
-
- -
-

Particle swarm optimization (PSO) with constraint supportÂļ

-

The pyswarm package is a gradient-free, evolutionary optimization package -for python that supports constraints.

-
-

Table of ContentsÂļ

-
-
    -
-
-
-
-

OverviewÂļ

-

The package currently includes a single function for performing PSO: pso.

-
-
-

RequirementsÂļ

-
    -
  • NumPy
  • -
-
-
-

Installation and downloadÂļ

-
-

Important noteÂļ

-

The installation commands below should be run in a DOS or Unix -command shell (not in a Python shell).

-

Under Windows (version 7 and earlier), a command shell can be obtained -by running cmd.exe (through the Runâ€Ļ menu item from the Start -menu). Under Unix (Linux, Mac OS X,â€Ļ), a Unix shell is available when -opening a terminal (in Mac OS X, the Terminal program is found in the -Utilities folder, which can be accessed through the Go menu in the -Finder).

-
-
-

Automatic install or upgradeÂļ

-

One of the automatic installation or upgrade procedures below might work -on your system, if you have a Python package installer or use certain -Linux distributions.

-

Under Unix, it may be necessary to prefix the commands below with -sudo, so that the installation program has sufficient access -rights to the system.

-

If you have pip, you can try to install -the latest version with

-
pip install --upgrade pyswarm
-
-
-

If you have setuptools, you can try to automatically install or -upgrade this package with

-
easy_install --upgrade pyswarm
-
-
-
-
-

Manual download and installÂļ

-

Alternatively, you can simply download the package archive from the -Python Package Index (PyPI) and unpack it. The package can then be -installed by going into the unpacked directory -(pyswarm-...), and running the provided setup.py -program with

-
python setup.py install
-
-
-

or, for an installation in the user Python library (no additional access -rights needed):

-
python setup.py install --user
-
-
-

or, for an installation in a custom directory my_directory:

-
python setup.py install --install-lib my_directory
-
-
-

or, if additional access rights are needed (Unix):

-
sudo python setup.py install
-
-
-

You can also simply move the pyswarm-py* directory -that corresponds best to your version of Python to a location that -Python can import from (directory in which scripts using -pyswarm are run, etc.); the chosen -pyswarm-py* directory should then be renamed -pyswarm. Python 3 users should then run 2to3 -w . -from inside this directory so as to automatically adapt the code to -Python 3.

-
-
-

Source codeÂļ

-

The latest, bleeding-edge but working code -and documentation source are -available on GitHub.

-
-
-
-

Example UsageÂļ

-
-

An Interesting Math ProblemÂļ

-

To illustrate how pyswarm is to be best utilized, we’ll start with a -complete example, which will be explained step-by-step afterwards:

-
from pyswarm import pso
-
-def banana(x):
-    x1 = x[0]
-    x2 = x[1]
-    return x1**4 - 2*x2*x1**2 + x2**2 + x1**2 - 2*x1 + 5
-
-def con(x):
-    x1 = x[0]
-    x2 = x[1]
-    return [-(x1 + 0.25)**2 + 0.75*x2]
-
-lb = [-3, -1]
-ub = [2, 6]
-
-xopt, fopt = pso(banana, lb, ub, f_ieqcons=con)
-
-# Optimum should be around x=[0.5, 0.76] with banana(x)=4.5 and con(x)=0
-
-
-

Now let’s walk through each section of code. We start off with any necessary -imports, in this case it’s just the optimizer function pso:

-
from pyswarm import pso
-
-
-

Then we define the objective function to be minimized, which should be defined -like myfunction(x, *args, **kwargs). In other words, it takes as its first -argument an 1-d array-like object, followed by any other (optional) arguments -and (again, optional) keyword arguments. The function should return a single -scalar value that is minimized. In this example, the banana -function:

-
def banana(x):
-    x1 = x[0]
-    x2 = x[1]
-    return x1**4 - 2*x2*x1**2 + x2**2 + x1**2 - 2*x1 + 5
-
-
-

Optimizing with constraints is optional, but we include one here to illustrate -how it might be done in the con function which has the same call -syntax as the objective, but returns an array of values (even if it only has a -single value in it):

-
def con(x):
-    x1 = x[0]
-    x2 = x[1]
-    return [-(x1 + 0.25)**2 + 0.75*x2]
-
-
-

Rather than specify a starting point for the algorithm, we define the limits -of the input variables that the optimizer is allowed to search within. For the -sake of clarity, we have defined them prior to calling the optimizer in the -objects lb and ub, which stand for lower-bound and upper-bound, -respectively:

-
lb = [-3, -1]
-ub = [2, 6]
-
-
-

That is really all that needs to be defined to run pso, so we then -call the optimizer:

-
xopt, fopt = pso(banana, lb, ub, f_ieqcons=con)
-
-
-

Using the kwarg f_ieqcons tells the routine that there’s a single -constraint function that returns an array object.

-

Once complete, pso returns two objects: 1) the optimal input values -and 2) the optimal objective value.

-

The full call syntax for pso is highly customizable and is defined as -follows:

-
pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={},
-    swarmsize=100, omega=0.5, phip=0.5, phig=0.5, maxiter=100, minstep=1e-8,
-    minfunc=1e-8, debug=False)
-
-
-

where the minimum required input arguments are:

-
-
-
func : function
-
The function to be minimized
-
lb : array
-
The lower bounds of the design variable(s)
-
ub : array
-
The upper bounds of the design variable(s)
-
-
-

and the optional input keyword-arguments are defined as:

-
-
-
ieqcons : list
-
A list of functions of length n such that ieqcons[j](x,*args) >= 0.0 -in a successfully optimized problem (Default: empty list, [])
-
f_ieqcons : function
-
Returns a 1-D array in which each element must be greater or equal to -0.0 in a successfully optimized problem. If f_ieqcons is specified, -ieqcons is ignored (Default: None)
-
args : tuple
-
Additional arguments passed to objective and constraint functions -(Default: empty tuple, ())
-
kwargs : dict
-
Additional keyword arguments passed to objective and constraint -functions (Default: empty dict, {})
-
swarmsize : int
-
The number of particles in the swarm (Default: 100)
-
omega : scalar
-
Particle velocity scaling factor (Default: 0.5)
-
phip : scalar
-
Scaling factor to search away from the particle’s best known position -(Default: 0.5)
-
phig : scalar
-
Scaling factor to search away from the swarm’s best known position -(Default: 0.5)
-
maxiter : int
-
The maximum number of iterations for the swarm to search (Default: 100)
-
minstep : scalar
-
The minimum stepsize of swarm’s best position before the search -terminates (Default: 1e-8)
-
minfunc : scalar
-
The minimum change of swarm’s best objective value before the search -terminates (Default: 1e-8)
-
debug : boolean
-
If True, progress statements will be displayed every iteration -(Default: False)
-
-
-

We could have written the constraint function to return a scalar value instead -of an array-like object, like:

-
def con(x):
-    x1 = x[0]
-    x2 = x[1]
-    return -(x1 + 0.25)**2 + 0.75*x2
-
-
-

In which case, we would have utilized the keyword-argument ieqcons, which -takes an array of function handles, like:

-
xopt, fopt = pso(banana, lb, ub, ieqcons=[con])
-
-
-

The parameters args and kwargs are used to pass any additional -parameters to the objective and constraint functions and are not changed during -the optimization process.

-

The parameters omega, phig and phip are a way of controlling how -closely the particles move away from their own best known position and the best -known position of all the particles in the swarm. These can take any scalar -value, but values between 0 and 1 seem to work best.

-

Finally, the parameters maxiter, minstep and minfunc are used to -tell the swarm when to stop searching. The last parameter debug can be -used to print out progress statements about the swarm.

-
-
-

An Engineering ExampleÂļ

-

Another useful example is in the design of a two-bar truss in the shape of an -A-frame. The objective of the problem is to minimize the weight of the truss -while satisfying three design constraints:

-
    -
  • Yield Stress <= 100 kpsi
  • -
  • Yield Stress <= Buckling Stress
  • -
  • Deflection <= 0.25 in
  • -
-

The design variables are:

-
    -
  • H: the height of the truss, in inches
  • -
  • d: the diameter of the truss tubes, in inches
  • -
  • t: the wall thickness of the tubes, in inches
  • -
-

Other parameters that will be held constant are:

-
    -
  • B: the base separation distance, in inches
  • -
  • rho: the density of the truss material, in lb/in^3
  • -
  • E: the modulus of elasticity of the truss material, in kpsi (1000-psi)
  • -
  • P: the downward vertical load on the top of the truss, in kip (1000-lbf)
  • -
-

This example shows how the optional args parameter may be used to pass -other needed values to the objective and constraint functions. The complete -code is as follows:

-
import numpy as np
-from pyswarm import pso
-
-# Define the objective (to be minimize)
-def weight(x, *args):
-    H, d, t = x
-    B, rho, E, P = args
-    return rho*2*np.pi*d*t*np.sqrt((B/2)**2 + H**2)
-
-# Setup the constraint functions
-def yield_stress(x, *args):
-    H, d, t = x
-    B, rho, E, P = args
-    return (P*np.sqrt((B/2)**2 + H**2))/(2*t*np.pi*d*H)
-
-def buckling_stress(x, *args):
-    H, d, t = x
-    B, rho, E, P = args
-    return (np.pi**2*E*(d**2 + t**2))/(8*((B/2)**2 + H**2))
-
-def deflection(x, *args):
-    H, d, t = x
-    B, rho, E, P = args
-    return (P*np.sqrt((B/2)**2 + H**2)**3)/(2*t*np.pi*d*H**2*E)
-
-def constraints(x, *args):
-    strs = yield_stress(x, *args)
-    buck = buckling_stress(x, *args)
-    defl = deflection(x, *args)
-    return [100 - strs, buck - strs, 0.25 - defl]
-
-# Define the other parameters
-B = 60  # inches
-rho = 0.3  # lb/in^3
-E = 30000  # kpsi (1000-psi)
-P = 66  # kip (1000-lbs, force)
-args = (B, rho, E, P)
-
-# Define the lower and upper bounds for H, d, t, respectively
-lb = [10, 1, 0.01]
-ub = [30, 3, 0.25]
-
-xopt, fopt = pso(weight, lb, ub, f_ieqcons=constraints, args=args)
-
-# The optimal input values are approximately
-#     xopt = [29, 2.4, 0.06]
-# with function values approximately
-#     weight          = 12 lbs
-#     yield stress    = 100 kpsi (binding constraint)
-#     buckling stress = 150 kpsi
-#     deflection      = 0.2 in
-
-
-

Because there’s an aspect of randomness in the algorithm, it is common to get a -slightly different result each time it is run. This is to be expected.

-

Keeping everything else the same, we could have also defined the constraints -using ieqcons like this:

-
...
-
-# Setup the constraint functions
-def yield_stress(x, *args):
-    H, d, t = x
-    B, rho, E, P = args
-    strs = (P*np.sqrt((B/2)**2 + H**2))/(2*t*np.pi*d*H)
-    return 100 - strs
-
-def buckling_stress(x, *args):
-    H, d, t = x
-    B, rho, E, P = args
-    buck = (np.pi**2*E*(d**2 + t**2))/(8*((B/2)**2 + H**2))
-    strs = yield_stress(x, *args)
-    return buck - strs
-
-def deflection(x, *args):
-    H, d, t = x
-    B, rho, E, P = args
-    defl = (P*np.sqrt((B/2)**2 + H**2)**3)/(2*t*np.pi*d*H**2*E)
-    return 0.25 - defl
-
-...
-
-cons = [yield_stress, buckling_stress, deflection]
-
-...
-
-xopt, fopt = pso(weight, lb, ub, ieqcons=cons, args=args)
-
-
-

And this would function the same way as the prior formulation. Use whichever -way works best for your application!

-
-
-
-

ContactÂļ

-

Any feedback, questions, bug reports, or success stores should -be sent to the author. I’d love to hear from you!

-
-
-

LicenseÂļ

-

This package is provided under two licenses:

-
    -
  1. The BSD License
  2. -
  3. Any other that the author approves (just ask!)
  4. -
-
-
-

ReferencesÂļ

- -
-
- - -
-
-
-
-
- - - - \ No newline at end of file diff --git a/doc/_build/html/objects.inv b/doc/_build/html/objects.inv deleted file mode 100644 index 6428a8bd4d7bd22513c08a063484caea230e788b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201 zcmY#Z2rkIT%&Sny%qvUHE6FdaR47X=D$dN$Q!wIERtPA{&q_@$u~I0gEG|zh$^{CA zL8Pq|41t`Gj8ui9)ZE0(yp+@;h5R&yl8nq^g|y6^R0SZNoS$1zlv-SznxarzoSB!d zP?eLJq{mfp>-1UwlV`j=*9K_ld2T%A>Em@a@PcWG#)>OvTfJVSPI>Z7L;J_GNfO^M;J3PN!0bDPqgj#8lH4Xti`WPGxl#VNqGOyoizE{xd^K0LAT4UjP6A diff --git a/doc/_build/html/search.html b/doc/_build/html/search.html deleted file mode 100644 index b9b8293..0000000 --- a/doc/_build/html/search.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - - Search — pyswarm 0.5 documentation - - - - - - - - - - - - - - - - - - - -
-ad -
- - - - - -
-
-

Table of contents

-
    -
- -

Documentation license

-Creative Commons License -
-
- -
-
-
-
- -

Search

-
- -

- Please activate JavaScript to enable the search - functionality. -

-
-

- From here you can search these documents. Enter your search - words into the box below and click "search". Note that the search - function will automatically search for all of the words. Pages - containing fewer words won't appear in the result list. -

-
- - - -
- -
- -
- -
-
-
-
-
- - - - \ No newline at end of file diff --git a/doc/_build/html/searchindex.js b/doc/_build/html/searchindex.js deleted file mode 100644 index eec79d4..0000000 --- a/doc/_build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({objects:{},terms:{all:0,code:0,edg:0,illustr:0,scalar:0,stepsiz:0,follow:0,program:0,under:0,sent:0,sourc:0,everi:0,whichev:0,fals:0,util:0,cmd:0,list:0,prefix:0,iter:0,"try":0,item:0,refer:0,upper:0,design:0,pass:0,download:0,even:0,index:0,section:0,access:0,version:0,full:0,here:0,satisfi:0,let:0,vertic:0,valu:0,buck:0,search:0,prior:0,chang:0,diamet:0,love:0,approxim:0,unix:0,"boolean":0,instal:0,highli:0,from:0,would:0,sake:0,two:0,afterward:0,formul:0,call:0,tell:0,buckling_stress:0,known:0,unpack:0,must:0,none:0,word:0,setup:0,work:0,yield_stress:0,archiv:0,can:0,veloc:0,def:0,control:0,process:0,sudo:0,minimum:0,rather:0,anoth:0,how:0,instead:0,pypi:0,earlier:0,befor:0,mac:0,mai:0,stress:0,github:0,bind:0,minim:0,correspond:0,element:0,allow:0,feedback:0,move:0,approv:0,becaus:0,held:0,evolutionari:0,through:0,same:0,paramet:0,chosen:0,window:0,might:0,them:0,"return":0,greater:0,handl:0,bound:0,now:0,minfunc:0,separ:0,each:0,debug:0,found:0,weight:0,procedur:0,realli:0,expect:0,out:0,variabl:0,gradient:0,content:0,adapt:0,print:0,math:0,insid:0,free:0,base:0,ask:0,bleed:0,suffici:0,could:0,keep:0,length:0,top:0,first:0,onc:0,arrai:0,clariti:0,number:0,done:0,thick:0,open:0,differ:0,script:0,licens:0,system:0,swarm:0,statement:0,termin:0,banana:0,store:0,shell:0,option:0,setuptool:0,specifi:0,than:0,my_directori:0,keyword:0,provid:0,"final":0,str:0,posit:0,ani:0,packag:0,have:0,tabl:0,need:0,seem:0,engin:0,lib:0,note:0,also:0,exampl:0,particl:0,which:0,singl:0,distribut:0,object:0,rho:0,bsd:0,phig:0,renam:0,phip:0,show:0,random:0,syntax:0,current:0,onli:0,locat:0,menu:0,explain:0,should:0,dict:0,factor:0,folder:0,get:0,stop:0,"import":0,report:0,requir:0,bar:0,yield:0,common:0,where:0,frame:0,maximum:0,elast:0,result:0,arg:0,close:0,optimum:0,modulu:0,wikipedia:0,written:0,between:0,progress:0,awai:0,altern:0,addit:0,last:0,equal:0,etc:0,con:0,load:0,simpli:0,point:0,wall:0,overview:0,walk:0,linux:0,respect:0,truss:0,numpi:0,three:0,empti:0,interest:0,argument:0,func:0,input:0,xopt:0,"case":0,defin:0,"while":0,customiz:0,buckl:0,lbf:0,kwarg:0,around:0,author:0,perform:0,sqrt:0,python:0,inch:0,document:0,complet:0,optim:0,kip:0,deflect:0,user:0,swarmsiz:0,defl:0,lower:0,off:0,contact:0,command:0,thi:0,everyth:0,latest:0,distanc:0,just:0,pyswarm:0,when:0,obtain:0,shape:0,aspect:0,densiti:0,els:0,finder:0,take:0,applic:0,psi:0,pso:0,height:0,like:0,success:0,manual:0,necessari:0,downward:0,right:0,maxit:0,successfulli:0,librari:0,fopt:0,scale:0,tube:0,best:0,ieqcon:0,myfunct:0,run:0,usag:0,step:0,about:0,constraint:0,materi:0,slightli:0,stand:0,routin:0,own:0,within:0,easy_instal:0,automat:0,upgrad:0,f_ieqcon:0,your:0,wai:0,support:0,question:0,minstep:0,custom:0,avail:0,start:0,includ:0,"function":0,forc:0,tupl:0,kpsi:0,hear:0,"true":0,bug:0,"default":0,displai:0,below:0,limit:0,problem:0,constant:0,"int":0,certain:0,dure:0,pip:0,again:0,"2to3":0,other:0,you:0,omega:0,algorithm:0,directori:0,ignor:0,time:0},objtypes:{},titles:["Particle swarm optimization (PSO) with constraint support"],objnames:{},filenames:["index"]}) \ No newline at end of file diff --git a/doc/_static/_default.css b/doc/_static/_default.css deleted file mode 100644 index 7aa01b7..0000000 --- a/doc/_static/_default.css +++ /dev/null @@ -1,507 +0,0 @@ -/** - * Alternate Sphinx design - * Originally created by Armin Ronacher for Werkzeug, adapted by Georg Brandl. - */ - -body { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif; - font-size: 14px; - letter-spacing: -0.01em; - line-height: 150%; - text-align: center; - /*background-color: #AFC1C4; */ - background-color: #BFD1D4; - color: black; - padding: 0; - border: 1px solid #aaa; - - margin: 0px 80px 0px 80px; - min-width: 740px; -} - -a { - color: #CA7900; - text-decoration: none; -} - -a:hover { - color: #2491CF; -} - -pre { - font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.015em; - padding: 0.5em; - border: 1px solid #ccc; - background-color: #f8f8f8; -} - -td.linenos pre { - padding: 0.5em 0; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -cite, code, tt { - font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.01em; -} - -hr { - border: 1px solid #abc; - margin: 2em; -} - -tt { - background-color: #f2f2f2; - border-bottom: 1px solid #ddd; - color: #333; -} - -tt.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; - border: 0; -} - -tt.descclassname { - background-color: transparent; - border: 0; -} - -tt.xref { - background-color: transparent; - font-weight: bold; - border: 0; -} - -a tt { - background-color: transparent; - font-weight: bold; - border: 0; - color: #CA7900; -} - -a tt:hover { - color: #2491CF; -} - -dl { - margin-bottom: 15px; -} - -dd p { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -.refcount { - color: #060; -} - -dt:target, -.highlight { - background-color: #fbe54e; -} - -dl.class, dl.function { - border-top: 2px solid #888; -} - -dl.method, dl.attribute { - border-top: 1px solid #aaa; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -pre { - line-height: 120%; -} - -pre a { - color: inherit; - text-decoration: underline; -} - -.first { - margin-top: 0 !important; -} - -div.document { - background-color: white; - text-align: left; - background-image: url(contents.png); - background-repeat: repeat-x; -} - -/* -div.documentwrapper { - width: 100%; -} -*/ - -div.clearer { - clear: both; -} - -div.related h3 { - display: none; -} - -div.related ul { - background-image: url(navigation.png); - height: 2em; - list-style: none; - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 0; - padding-left: 10px; -} - -div.related ul li { - margin: 0; - padding: 0; - height: 2em; - float: left; -} - -div.related ul li.right { - float: right; - margin-right: 5px; -} - -div.related ul li a { - margin: 0; - padding: 0 5px 0 5px; - line-height: 1.75em; - color: #EE9816; -} - -div.related ul li a:hover { - color: #3CA8E7; -} - -div.body { - margin: 0; - padding: 0.5em 20px 20px 20px; -} - -div.bodywrapper { - margin: 0 240px 0 0; - border-right: 1px solid #ccc; -} - -div.body a { - text-decoration: underline; -} - -div.sphinxsidebar { - margin: 0; - padding: 0.5em 15px 15px 0; - width: 210px; - float: right; - text-align: left; -/* margin-left: -100%; */ -} - -div.sphinxsidebar h4, div.sphinxsidebar h3 { - margin: 1em 0 0.5em 0; - font-size: 0.9em; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border: 1px solid #86989B; - background-color: #AFC1C4; -} - -div.sphinxsidebar ul { - padding-left: 1.5em; - margin-top: 7px; - list-style: none; - padding: 0; - line-height: 130%; -} - -div.sphinxsidebar ul ul { - list-style: square; - margin-left: 20px; -} - -p { - margin: 0.8em 0 0.5em 0; -} - -p.rubric { - font-weight: bold; -} - -h1 { - margin: 0; - padding: 0.7em 0 0.3em 0; - font-size: 1.5em; - color: #11557C; -} - -h2 { - margin: 1.3em 0 0.2em 0; - font-size: 1.35em; - padding: 0; -} - -h3 { - margin: 1em 0 -0.3em 0; - font-size: 1.2em; -} - -h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - color: black!important; -} - -h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { - display: none; - margin: 0 0 0 0.3em; - padding: 0 0.2em 0 0.2em; - color: #aaa!important; -} - -h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, -h5:hover a.anchor, h6:hover a.anchor { - display: inline; -} - -h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, -h5 a.anchor:hover, h6 a.anchor:hover { - color: #777; - background-color: #eee; -} - -table { - border-collapse: collapse; - margin: 0 -0.5em 0 -0.5em; -} - -table td, table th { - padding: 0.2em 0.5em 0.2em 0.5em; -} - -div.footer { - background-color: #E3EFF1; - color: #86989B; - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: right; -} - -div.footer a { - color: #86989B; - text-decoration: underline; -} - -div.pagination { - margin-top: 2em; - padding-top: 0.5em; - border-top: 1px solid black; - text-align: center; -} - -div.sphinxsidebar ul.toc { - margin: 1em 0 1em 0; - padding: 0 0 0 0.5em; - list-style: none; -} - -div.sphinxsidebar ul.toc li { - margin: 0.5em 0 0.5em 0; - font-size: 0.9em; - line-height: 130%; -} - -div.sphinxsidebar ul.toc li p { - margin: 0; - padding: 0; -} - -div.sphinxsidebar ul.toc ul { - margin: 0.2em 0 0.2em 0; - padding: 0 0 0 1.8em; -} - -div.sphinxsidebar ul.toc ul li { - padding: 0; -} - -div.admonition, div.warning { - font-size: 0.9em; - margin: 1em 0 0 0; - border: 1px solid #86989B; - background-color: #f7f7f7; -} - -div.admonition p, div.warning p { - margin: 0.5em 1em 0.5em 1em; - padding: 0; -} - -div.admonition pre, div.warning pre { - margin: 0.4em 1em 0.4em 1em; -} - -div.admonition p.admonition-title, -div.warning p.admonition-title { - margin: 0; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border-bottom: 1px solid #86989B; - font-weight: bold; - background-color: #AFC1C4; -} - -div.warning { - border: 1px solid #940000; -} - -div.warning p.admonition-title { - background-color: #CF0000; - border-bottom-color: #940000; -} - -div.admonition ul, div.admonition ol, -div.warning ul, div.warning ol { - margin: 0.1em 0.5em 0.5em 3em; - padding: 0; -} - -div.versioninfo { - margin: 1em 0 0 0; - border: 1px solid #ccc; - background-color: #DDEAF0; - padding: 8px; - line-height: 1.3em; - font-size: 0.9em; -} - - -a.headerlink { - color: #c60f0f!important; - font-size: 1em; - margin-left: 6px; - padding: 0 4px 0 4px; - text-decoration: none!important; - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink { - visibility: visible; -} - -a.headerlink:hover { - background-color: #ccc; - color: white!important; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable dl, table.indextable dd { - margin-top: 0; - margin-bottom: 0; -} - -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; -} - -img.inheritance { - border: 0px -} - -form.pfform { - margin: 10px 0 20px 0; -} - -table.contentstable { - width: 90%; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} diff --git a/doc/_static/favicon.ico b/doc/_static/favicon.ico deleted file mode 100644 index f7c2cf975b294085e69c37fa4c6bf33298bf2137..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11513 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 qfAE!+f!hBchQ-4DzdGJv-BAGHLV^GubL)Hj3` - - - - - - - - - image/svg+xml - - - - - - - pyswarm - - diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html deleted file mode 100644 index 4756526..0000000 --- a/doc/_templates/layout.html +++ /dev/null @@ -1,89 +0,0 @@ -{% extends "!layout.html" %} - -{% block rootrellink %} - {{ toctree() }} -{% endblock %} - - -{% block relbar1 %} - -
-ad -
-{{ super() }} -{% endblock %} - - -{#############################################################################} -{# Sidebar customization #) - -{# put the sidebar before the body #} -{% block sidebar1 %} - -{%- macro sidebar() %} - {%- if not embedded %}{% if not theme_nosidebar|tobool %} -
-
- {%- block sidebarlogo %} - {%- if logo %} - - {%- endif %} - {%- endblock %} - {%- block sidebartoc %} - {%- block sidebarglobaltoc %} -

{{ _('Table of contents') }}

- {{ toctree() }} - {%- endblock %} - {%- endblock %} - {%- block sidebarrel %} - {%- endblock %} - {%- block sidebarsourcelink %} - {%- if show_source and has_source and sourcename %} -

{{ _('This Page') }}

- - {%- endif %} - {%- endblock %} - {%- if customsidebar %} - {% include customsidebar %} - {%- endif %} - {%- if display_toc %} -

{{ _('Section contents') }}

- {{ toc }} - {%- endif %} - {%- block sidebarsearch %} - {%- if pagename != "search" %} - - - {%- endif %} - {%- endblock %} - {%- block copyright %} -

Documentation license

-Creative Commons License - {%- endblock %} -
-
- {%- endif %}{% endif %} -{%- endmacro %} - -{{ sidebar() }}{% endblock %} - - -{% block sidebar2 %}{% endblock %} - diff --git a/doc/conf.py b/doc/conf.py deleted file mode 100644 index 7132737..0000000 --- a/doc/conf.py +++ /dev/null @@ -1,203 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ad Python package documentation build configuration file, created by -# sphinx-quickstart on Tue Jun 8 18:32:22 2010. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -from datetime import date - -import sys, os - -sys.path.insert(0, os.path.abspath('..')) - -import pyswarm - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'pyswarm' -if date.today().year!=2013: - copyright = u'2013–%d, Abraham Lee' % date.today().year -else: - copyright = u'2013, Abraham Lee' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '1' -# The full version, including alpha/beta/rc tags. -release = pyswarm.__version__ - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of documents that shouldn't be included in the build. -#unused_docs = [] - -# List of directories, relative to source directory, that shouldn't be searched -# for source files. -exclude_trees = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -html_theme = 'sphinxdoc' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -html_favicon = 'favicon.ico' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_use_modindex = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -html_show_sourcelink = False - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'pyswarmPythonPackagedoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -# latex_documents = [ -# ('index_TOC', 'adPythonPackage.tex', u'ad Python package Documentation', -# u'Abraham Lee', 'manual'), -# ] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_use_modindex = True diff --git a/doc/index.rst b/doc/index.rst deleted file mode 100644 index ebc8408..0000000 --- a/doc/index.rst +++ /dev/null @@ -1,440 +0,0 @@ -.. meta:: - :description: Particle swarm optimization (PSO) with constraint support - :keywords: particle swarm optimization, pso, optimization, constraints - -====================================================================== -Particle swarm optimization (PSO) with constraint support -====================================================================== - -The ``pyswarm`` package is a gradient-free, evolutionary optimization package -for python that supports constraints. - -Table of Contents -================= - -.. toctree:: - :maxdepth: 1 - -Overview -============ - -The package currently includes a single function for performing PSO: ``pso``. - -Requirements -============ - -- NumPy - -.. index:: installation - -Installation and download -========================= - -Important note --------------- - -The installation commands below should be **run in a DOS or Unix -command shell** (*not* in a Python shell). - -Under Windows (version 7 and earlier), a command shell can be obtained -by running ``cmd.exe`` (through the Runâ€Ļ menu item from the Start -menu). Under Unix (Linux, Mac OS X,â€Ļ), a Unix shell is available when -opening a terminal (in Mac OS X, the Terminal program is found in the -Utilities folder, which can be accessed through the Go menu in the -Finder). - -Automatic install or upgrade ----------------------------- - -One of the automatic installation or upgrade procedures below might work -on your system, if you have a Python package installer or use certain -Linux distributions. - -Under Unix, it may be necessary to prefix the commands below with -``sudo``, so that the installation program has **sufficient access -rights to the system**. - -If you have `pip `_, you can try to install -the latest version with - -.. code-block:: sh - - pip install --upgrade pyswarm - -If you have setuptools_, you can try to automatically install or -upgrade this package with - -.. code-block:: sh - - easy_install --upgrade pyswarm - -Manual download and install ---------------------------- - -Alternatively, you can simply download_ the package archive from the -Python Package Index (PyPI) and unpack it. The package can then be -installed by **going into the unpacked directory** -(:file:`pyswarm-...`), and running the provided :file:`setup.py` -program with - -.. code-block:: sh - - python setup.py install - -or, for an installation in the user Python library (no additional access -rights needed): - -.. code-block:: sh - - python setup.py install --user - -or, for an installation in a custom directory :file:`my_directory`: - -.. code-block:: sh - - python setup.py install --install-lib my_directory - -or, if additional access rights are needed (Unix): - -.. code-block:: sh - - sudo python setup.py install - -You can also simply **move** the :file:`pyswarm-py*` directory -that corresponds best to your version of Python to a location that -Python can import from (directory in which scripts using -:mod:`pyswarm` are run, etc.); the chosen -:file:`pyswarm-py*` directory should then be renamed -:file:`pyswarm`. Python 3 users should then run ``2to3 -w .`` -from inside this directory so as to automatically adapt the code to -Python 3. - -Source code ------------ - -The latest, bleeding-edge but working `code -`_ -and `documentation source -`_ are -available `on GitHub `_. - -.. index:: examples - -Example Usage -============= - -An Interesting Math Problem ---------------------------- - -To illustrate how ``pyswarm`` is to be best utilized, we'll start with a -complete example, which will be explained step-by-step afterwards: - -.. code-block:: python - - from pyswarm import pso - - def banana(x): - x1 = x[0] - x2 = x[1] - return x1**4 - 2*x2*x1**2 + x2**2 + x1**2 - 2*x1 + 5 - - def con(x): - x1 = x[0] - x2 = x[1] - return [-(x1 + 0.25)**2 + 0.75*x2] - - lb = [-3, -1] - ub = [2, 6] - - xopt, fopt = pso(banana, lb, ub, f_ieqcons=con) - - # Optimum should be around x=[0.5, 0.76] with banana(x)=4.5 and con(x)=0 - -Now let's walk through each section of code. We start off with any necessary -imports, in this case it's just the optimizer function ``pso``: - -.. code-block:: python - - from pyswarm import pso - -Then we define the objective function to be minimized, which should be defined -like ``myfunction(x, *args, **kwargs)``. In other words, it takes as its first -argument an 1-d array-like object, followed by any other (optional) arguments -and (again, optional) keyword arguments. The function should return a single -scalar value that is minimized. In this example, the ``banana`` -function: - -.. code-block:: python - - def banana(x): - x1 = x[0] - x2 = x[1] - return x1**4 - 2*x2*x1**2 + x2**2 + x1**2 - 2*x1 + 5 - -Optimizing with constraints is optional, but we include one here to illustrate -how it might be done in the ``con`` function which has the same call -syntax as the objective, but returns an array of values (even if it only has a -single value in it): - -.. code-block:: python - - def con(x): - x1 = x[0] - x2 = x[1] - return [-(x1 + 0.25)**2 + 0.75*x2] - -Rather than specify a starting point for the algorithm, we define the limits -of the input variables that the optimizer is allowed to search within. For the -sake of clarity, we have defined them prior to calling the optimizer in the -objects ``lb`` and ``ub``, which stand for *lower-bound* and *upper-bound*, -respectively: - -.. code-block:: python - - lb = [-3, -1] - ub = [2, 6] - -That is really all that *needs* to be defined to run ``pso``, so we then -call the optimizer: - -.. code-block:: python - - xopt, fopt = pso(banana, lb, ub, f_ieqcons=con) - -Using the kwarg ``f_ieqcons`` tells the routine that there's a single -constraint function that returns an array object. - -Once complete, ``pso`` returns two objects: 1) the optimal input values -and 2) the optimal objective value. - -The full call syntax for ``pso`` is highly customizable and is defined as -follows: - -.. code-block:: python - - pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, - swarmsize=10, omega=0.5, phip=0.5, phig=0.5, maxiter=100, minstep=1e-8, - minfunc=1e-8, debug=False) - -where the minimum required input arguments are: - - func : function - The function to be minimized - lb : array - The lower bounds of the design variable(s) - ub : array - The upper bounds of the design variable(s) - -and the optional input keyword-arguments are defined as: - - ieqcons : list - A list of functions of length n such that ieqcons[j](x,*args) >= 0.0 in - a successfully optimized problem (Default: []) - f_ieqcons : function - Returns a 1-D array in which each element must be greater or equal - to 0.0 in a successfully optimized problem. If f_ieqcons is specified, - ieqcons is ignored (Default: None) - args : tuple - Additional arguments passed to objective and constraint functions - (Default: empty tuple) - kwargs : dict - Additional keyword arguments passed to objective and constraint - functions (Default: empty dict) - swarmsize : int - The number of particles in the swarm (Default: 10) - omega : scalar - Particle's inertia weight (Default: 0.5) - phip : scalar - Particle's cognitive weight (Default: 0.5) - phig : scalar - Swarm's social weight (Default: 0.5) - maxiter : int - The maximum number of iterations for the swarm to search (Default: 1000) - minstep : scalar - The minimum stepsize of swarm's best position before the search - terminates (Default: 1e-8) - minfunc : scalar - The minimum change of swarm's best objective value before the search - terminates (Default: 1e-8) - debug : boolean - If True, progress statements will be displayed every iteration - (Default: False) - -We could have written the constraint function to return a scalar value instead -of an array-like object, like: - -.. code-block:: python - - def con(x): - x1 = x[0] - x2 = x[1] - return -(x1 + 0.25)**2 + 0.75*x2 - -In which case, we would have utilized the keyword-argument ``ieqcons``, which -takes an array of function handles, like: - -.. code-block:: python - - xopt, fopt = pso(banana, lb, ub, ieqcons=[con]) - -The parameters ``args`` and ``kwargs`` are used to pass any additional -parameters to the objective and constraint functions and are not changed during -the optimization process. - -The parameters ``omega``, ``phig`` and ``phip`` are a way of controlling how -closely the particles move away from their own best known position and the best -known position of all the particles in the swarm. These can take any scalar -value, but values between 0 and 1 seem to work best. - -Finally, the parameters ``maxiter``, ``minstep`` and ``minfunc`` are used to -tell the swarm when to stop searching. The last parameter ``debug`` can be -used to print out progress statements about the swarm. - -An Engineering Example ----------------------- - -Another useful example is in the design of a two-bar truss in the shape of an -A-frame. The objective of the problem is to minimize the weight of the truss -while satisfying three design constraints: - -- Yield Stress <= 100 kpsi -- Yield Stress <= Buckling Stress -- Deflection <= 0.25 in - -The design variables are: - -- ``H``: the height of the truss, in inches -- ``d``: the diameter of the truss tubes, in inches -- ``t``: the wall thickness of the tubes, in inches - -Other parameters that will be held constant are: - -- ``B``: the base separation distance, in inches -- ``rho``: the density of the truss material, in lb/in^3 -- ``E``: the modulus of elasticity of the truss material, in kpsi (1000-psi) -- ``P``: the downward vertical load on the top of the truss, in kip (1000-lbf) - -This example shows how the optional ``args`` parameter may be used to pass -other needed values to the objective and constraint functions. The complete -code is as follows: - -.. code-block:: python - - import numpy as np - from pyswarm import pso - - # Define the objective (to be minimize) - def weight(x, *args): - H, d, t = x - B, rho, E, P = args - return rho*2*np.pi*d*t*np.sqrt((B/2)**2 + H**2) - - # Setup the constraint functions - def yield_stress(x, *args): - H, d, t = x - B, rho, E, P = args - return (P*np.sqrt((B/2)**2 + H**2))/(2*t*np.pi*d*H) - - def buckling_stress(x, *args): - H, d, t = x - B, rho, E, P = args - return (np.pi**2*E*(d**2 + t**2))/(8*((B/2)**2 + H**2)) - - def deflection(x, *args): - H, d, t = x - B, rho, E, P = args - return (P*np.sqrt((B/2)**2 + H**2)**3)/(2*t*np.pi*d*H**2*E) - - def constraints(x, *args): - strs = yield_stress(x, *args) - buck = buckling_stress(x, *args) - defl = deflection(x, *args) - return [100 - strs, buck - strs, 0.25 - defl] - - # Define the other parameters - B = 60 # inches - rho = 0.3 # lb/in^3 - E = 30000 # kpsi (1000-psi) - P = 66 # kip (1000-lbs, force) - args = (B, rho, E, P) - - # Define the lower and upper bounds for H, d, t, respectively - lb = [10, 1, 0.01] - ub = [30, 3, 0.25] - - xopt, fopt = pso(weight, lb, ub, f_ieqcons=constraints, args=args) - - # The optimal input values are approximately - # xopt = [29, 2.4, 0.06] - # with function values approximately - # weight = 12 lbs - # yield stress = 100 kpsi (binding constraint) - # buckling stress = 150 kpsi - # deflection = 0.2 in - -Because there's an aspect of randomness in the algorithm, it is common to get a -slightly different result each time it is run. *This is to be expected.* - -Keeping everything else the same, we could have also defined the constraints -using ``ieqcons`` like this: - -.. code-block:: python - - ... - - # Setup the constraint functions - def yield_stress(x, *args): - H, d, t = x - B, rho, E, P = args - strs = (P*np.sqrt((B/2)**2 + H**2))/(2*t*np.pi*d*H) - return 100 - strs - - def buckling_stress(x, *args): - H, d, t = x - B, rho, E, P = args - buck = (np.pi**2*E*(d**2 + t**2))/(8*((B/2)**2 + H**2)) - strs = yield_stress(x, *args) - return buck - strs - - def deflection(x, *args): - H, d, t = x - B, rho, E, P = args - defl = (P*np.sqrt((B/2)**2 + H**2)**3)/(2*t*np.pi*d*H**2*E) - return 0.25 - defl - - ... - - cons = [yield_stress, buckling_stress, deflection] - - ... - - xopt, fopt = pso(weight, lb, ub, ieqcons=cons, args=args) - -And this would function the same way as the prior formulation. Use whichever -way works best for your application! - -.. index:: support - -Contact -======= - -Any feedback, questions, bug reports, or success stores should -be sent to the `author`_. I'd love to hear from you! - -License -======= - -This package is provided under two licenses: - -1. The *BSD License* -2. Any other that the author approves (just ask!) - -References -========== - -- `Particle swarm optimization`_ on Wikipedia - -.. _author: mailto:tisimst@gmail.com -.. _setuptools: http://pypi.python.org/pypi/setuptools -.. _download: http://pypi.python.org/pypi/pyswarm/#downloads -.. _Particle swarm optimization: http://en.wikipedia.org/wiki/Particle_swarm_optimization diff --git a/doc/pyswarm_doc.zip b/doc/pyswarm_doc.zip deleted file mode 100644 index 95269b6bdf5d861eb3bc704ae766fcc381509bb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156739 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
  • UXpfT!Y}izjoEU0hng8Ga$o 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 diff --git a/doc/_build/html/_static/_default.css b/docs/_static/_default.css old mode 100644 new mode 100755 similarity index 100% rename from doc/_build/html/_static/_default.css rename to docs/_static/_default.css diff --git a/doc/_build/html/_static/favicon.ico b/docs/_static/favicon.ico old mode 100644 new mode 100755 similarity index 100% rename from doc/_build/html/_static/favicon.ico rename to docs/_static/favicon.ico diff --git a/doc/_build/html/_static/logo.png b/docs/_static/logo.png old mode 100644 new mode 100755 similarity index 100% rename from doc/_build/html/_static/logo.png rename to docs/_static/logo.png diff --git a/doc/_build/html/_static/logo.svg b/docs/_static/logo.svg old mode 100644 new mode 100755 similarity index 100% rename from doc/_build/html/_static/logo.svg rename to docs/_static/logo.svg diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..0dde9a5 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,146 @@ +# API Reference + +All public symbols are exported from the `pyswarm` package. + +## Exported symbols + +- `pso` + +--- + +## `pso` + +### `pso(func, lb, ub, ...)` + +Minimize an objective function using Particle Swarm Optimization. + +```python +pso( + func, + lb, + ub, + ieqcons=None, + f_ieqcons=None, + args=(), + kwargs=None, + swarmsize=100, + omega=0.5, + phip=0.5, + phig=0.5, + maxiter=100, + minstep=1e-8, + minfunc=1e-8, + debug=False, + processes=1, + particle_output=False, +) +``` + +### Required arguments + +`func` +: Callable objective function to minimize. It receives the current candidate + vector as the first argument and returns a scalar objective value. + +`lb` +: Lower bounds for each design variable. + +`ub` +: Upper bounds for each design variable. + +### Optional arguments + +`ieqcons` +: List of constraint functions. Each function must return a value greater than + or equal to `0.0` for a feasible candidate. If `f_ieqcons` is provided, this + list is ignored. + +`f_ieqcons` +: A single constraint function returning a 1-D array-like object. Every returned + value must be greater than or equal to `0.0` for a feasible candidate. + +`args` +: Additional positional arguments passed to the objective and constraint + functions. + +`kwargs` +: Additional keyword arguments passed to the objective and constraint functions. + +`swarmsize` +: Number of particles in the swarm. Default: `100`. + +`omega` +: Particle velocity scaling factor. Default: `0.5`. + +`phip` +: Scaling factor for movement toward each particle's best known position. + Default: `0.5`. + +`phig` +: Scaling factor for movement toward the swarm's best known position. + Default: `0.5`. + +`maxiter` +: Maximum number of iterations. Default: `100`. + +`minstep` +: Minimum step size of the swarm's best position before the search terminates. + Default: `1e-8`. + +`minfunc` +: Minimum change in the swarm's best objective value before the search + terminates. Default: `1e-8`. + +`debug` +: If `True`, prints progress information during optimization. Default: `False`. + +`processes` +: Number of processes used to evaluate the objective and constraints. Default: + `1`. + +`particle_output` +: If `True`, returns per-particle best positions and objective values in + addition to the swarm best. Default: `False`. + +### Returns + +By default, `pso` returns: + +`xopt` +: The swarm's best known position. + +`fopt` +: The objective value at `xopt`. + +If `particle_output=True`, it also returns: + +`p` +: The best known position per particle. + +`pf` +: The objective values at each position in `p`. + +### Raises + +`TypeError` +: Raised when `func` is not callable. + +`ValueError` +: Raised when lower and upper bounds have different lengths or when any upper + bound is not greater than its corresponding lower bound. + +## Constraint conventions + +Constraints are feasible when they are non-negative: + +```python +def constraint(x): + return [limit - measured_value] +``` + +Use `f_ieqcons` when one function returns all constraint values. Use `ieqcons` +when each constraint is its own scalar function. + +## References + +See [References](references.md) for full citations. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..6937928 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,61 @@ +# PySwarm + +**Particle Swarm Optimization (PSO) for Python** + +`pyswarm` is a gradient-free, evolutionary optimization library for Python that implements [**Particle Swarm Optimization (PSO)**](https://en.wikipedia.org/wiki/Particle_swarm_optimization) with built-in support for constraints. It is lightweight, easy to use, and suitable for a wide range of optimization problems where gradient information is unavailable or impractical to compute. + +## Features + +- Gradient-free minimization for continuous design variables. +- Lower and upper bounds for every variable. +- Inequality constraints through either `ieqcons` or `f_ieqcons`. +- Optional multiprocessing for objective and constraint evaluation. +- Optional per-particle output for deeper inspection of a run. +- A small public API centered on one function: `pso`. + +## Mathematical model + +`pyswarm` solves minimization problems of the form + +$$ +\min_{\mathbf{x}} f(\mathbf{x}) +$$ + +subject to bound constraints + +$$ +\mathbf{l_b} \le \mathbf{x} \le \mathbf{u_b} +$$ + +and optional inequality constraints + +$$ +c_j(\mathbf{x}) \ge 0. +$$ + +Each particle stores a current position, a velocity, its own best position, and +the swarm's best known position. The optimizer updates the swarm with the +standard PSO velocity rule: + +$$ +\mathbf{v} \leftarrow \omega\mathbf{v} + + \phi_p r_p(\mathbf{p}-\mathbf{x}) + + \phi_g r_g(\mathbf{g}-\mathbf{x}) +$$ + +$$ +\mathbf{x} \leftarrow \mathbf{x} + \mathbf{v}. +$$ + +## Public API + +- `pso` - minimize an objective function over bounded variables, optionally + with inequality constraints. + +## Documentation + +- [Theory](theory.md) - mathematical background, hierarchical basis, algorithms +- [Installation](installation.md) - installation guide +- [Quickstart](quickstart.md) - runnable examples +- [API Reference](api.md) - function signature and arguments +- [References](references.md) - literature citations diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..e52d2df --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,115 @@ +# Installation + +`pyswarm` can be installed from PyPI or directly from source via GitHub. + +--- + +## [PyPI](https://pypi.org/project/pyswarm) + +For using the PyPI package in your project, add it to your configuration file: + +=== "pyproject.toml" + + ```toml + [project.dependencies] + pyswarm = "*" # (1)! + ``` + + 1. Specifying a version is recommended + +=== "requirements.txt" + + ``` + pyswarm>=0.1.0 + ``` + +### pip + +=== "Installation for user" + + ```bash + pip install --upgrade --user pyswarm # (1)! + ``` + + 1. You may need to use `pip3` instead of `pip` depending on your Python installation. + +=== "Installation in virtual environment" + + ```bash + python -m venv .venv + source .venv/bin/activate + pip install --require-virtualenv --upgrade pyswarm # (1)! + ``` + + 1. You may need to use `pip3` instead of `pip` depending on your Python installation. + + !!! note + The command to activate the virtual environment depends on your platform and shell. + [More info](https://docs.python.org/3/library/venv.html#how-venvs-work) + +### uv + +=== "Adding to uv project" + + ```bash + uv add pyswarm + uv sync + ``` + +=== "Installing to uv environment" + + ```bash + uv venv + uv pip install pyswarm + ``` + +### pipenv + +```bash +pipenv install pyswarm +``` + +### poetry + +```bash +poetry add pyswarm +``` + +### pdm + +```bash +pdm add pyswarm +``` + +### hatch + +```bash +hatch add pyswarm +``` + +--- + +## [GitHub](https://github.com/eggzec/pyswarm) + +Install the latest development version directly from the repository: + +```bash +pip install --upgrade "git+https://github.com/eggzec/pyswarm.git#egg=pyswarm" +``` + +### Building locally + +Clone and build from source if you want to modify or test local changes: + +```bash +git clone https://github.com/eggzec/pyswarm.git +cd pyswarm +pip install -e . +``` + +--- + +## Dependencies + +- Python 3.10+ +- NumPy diff --git a/docs/quickstart.md b/docs/quickstart.md new file mode 100644 index 0000000..e8ff9c1 --- /dev/null +++ b/docs/quickstart.md @@ -0,0 +1,155 @@ +# Quickstart + +The examples below cover unconstrained optimization, constrained optimization, and a small +engineering design problem. + +## Example 1: banana function without constraints + +Minimize the fourth-order banana function over two bounded variables: + +```python +from pyswarm import pso + + +def banana_func(x): + x1 = x[0] + x2 = x[1] + return x1**4 - 2 * x2 * x1**2 + x2**2 + x1**2 - 2 * x1 + 5 + + +lb = [-3, -1] +ub = [2, 6] + +xopt, fopt = pso(banana_func, lb, ub) +print(f"xopt: {xopt}") +print(f"fopt: {fopt}") +``` + +Expected result: + +- `xopt = [1.0, 1.0]` +- `fopt = 4.0` + +## Example 2: banana function with a constraint + +Add an inequality constraint. A candidate is feasible when every returned +constraint value is greater than or equal to `0.0`: + +```python +from pyswarm import pso + + +def banana_func(x): + x1 = x[0] + x2 = x[1] + return x1**4 - 2 * x2 * x1**2 + x2**2 + x1**2 - 2 * x1 + 5 + + +def banana_constraint(x): + x1 = x[0] + x2 = x[1] + return [-((x1 + 0.25) ** 2) + 0.75 * x2] + + +lb = [-3, -1] +ub = [2, 6] + +xopt, fopt = pso(banana_func, lb, ub, f_ieqcons=banana_constraint) +print(f"xopt: {xopt}") +print(f"fopt: {fopt}") +print(f"constraint: {banana_constraint(xopt)}") +``` + +Expected result: + +- `xopt` close to `[0.5, 0.75]` +- `fopt` close to `4.5` +- every value returned by `banana_constraint(xopt)` to be non-negative + +## Example 3: two-bar truss optimization + +Another useful example is in the design of a two-bar truss in the shape of an +A-frame. The objective of the problem is to minimize the weight of the truss +while satisfying three design constraints: + +- Yield Stress <= 100 kpsi +- Yield Stress <= Buckling Stress +- Deflection <= 0.25 in + +The design variables are: + +- `H`: the height of the truss, in inches +- `d`: the diameter of the truss tubes, in inches +- `t`: the wall thickness of the tubes, in inches + +Other parameters that will be held constant are: + +- `B`: the base separation distance, in inches +- `rho`: the density of the truss material, in lb/in^3 +- `E`: the modulus of elasticity of the truss material, in kpsi (1000-psi) +- `P`: the downward vertical load on the top of the truss, in kip (1000-lbf) + +This example shows how the optional `args` parameter may be used to pass other +needed values to the objective and constraint functions. + +```python +import numpy as np +from pyswarm import pso + + +def weight(x, *args): + h, d, t = x + b, rho, _e, _p = args + return rho * 2 * np.pi * d * t * np.sqrt((b / 2) ** 2 + h**2) + + +def stress(x, *args): + h, d, t = x + b, _rho, _e, p = args + return (p * np.sqrt((b / 2) ** 2 + h**2)) / (2 * t * np.pi * d * h) + + +def buckling_stress(x, *args): + h, d, t = x + b, _rho, e, _p = args + return (np.pi**2 * e * (d**2 + t**2)) / (8 * ((b / 2) ** 2 + h**2)) + + +def deflection(x, *args): + h, d, t = x + b, _rho, e, p = args + return (p * np.sqrt((b / 2) ** 2 + h**2) ** 3) / ( + 2 * t * np.pi * d * h**2 * e + ) + + +def truss_constraints(x, *args): + strs = stress(x, *args) + buck = buckling_stress(x, *args) + defl = deflection(x, *args) + return [100 - strs, buck - strs, 0.25 - defl] + + +b = 60 +rho = 0.3 # lb/in^3 +e = 30000 # kpsi +p = 66 +args = (b, rho, e, p) + +lb = [10, 1, 0.01] +ub = [30, 3, 0.25] + +xopt, fopt = pso( + weight, lb, ub, f_ieqcons=truss_constraints, args=args, maxiter=100 +) +print(f"xopt: {xopt}") +print(f"weight: {fopt}") +print(f"constraints: {truss_constraints(xopt, *args)}") +``` + +Expected result: + +- `fopt` close to `11.94` +- every value returned by `truss_constraints(xopt, *args)` is non-negative + +Because the algorithm is randomized, results can vary slightly between runs. diff --git a/docs/references.md b/docs/references.md new file mode 100644 index 0000000..58218ad --- /dev/null +++ b/docs/references.md @@ -0,0 +1,24 @@ +# References + +1. **Kennedy, J.; Eberhart, R.** + "Particle Swarm Optimization." + *Proceedings of IEEE International Conference on Neural Networks*, 1995. + +2. **Shi, Y.; Eberhart, R. C.** + "A modified particle swarm optimizer." + *Proceedings of IEEE International Conference on Evolutionary Computation*, + 1998. + +3. **Kennedy, J.; Eberhart, R. C.** + *Swarm Intelligence.* + Morgan Kaufmann, 2001. + +4. **Bonyadi, M. R.; Michalewicz, Z.** + "Particle swarm optimization for single objective continuous space problems: + a review." + *Evolutionary Computation*, 25(1), 1-54, 2017. + +5. [Wikipedia: Particle Swarm Optimization](https://en.wikipedia.org/wiki/Particle_swarm_optimization) + +> Source: +pythonhosted.org/pyswarm diff --git a/docs/theory.md b/docs/theory.md new file mode 100644 index 0000000..71b53e4 --- /dev/null +++ b/docs/theory.md @@ -0,0 +1,134 @@ +# Theory + +## 1) Particle swarm optimization + +Particle Swarm Optimization (PSO) is a population-based optimization method. It +iteratively improves a population of candidate solutions, called particles, +with respect to an objective function. + +PSO is a metaheuristic. It makes few assumptions about the problem, can search +large spaces of candidate solutions, and does not require gradients. That makes +it useful for nonlinear, noisy, or derivative-free optimization problems. Like +other metaheuristics, PSO does not guarantee that a global optimum will be +found. + +## 2) Particles and the objective function + +For a minimization problem, let + +$$ +f: \mathbb{R}^{n} \rightarrow \mathbb{R} +$$ + +be the objective function. A candidate solution is a vector + +$$ +\mathbf{x}_i \in \mathbb{R}^{n}. +$$ + +Each particle has: + +- a position $\mathbf{x}_i$ +- a velocity $\mathbf{v}_i$ +- a personal best position $\mathbf{p}_i$ +- access to the swarm's best known position $\mathbf{g}$ + +When a particle finds a position with a better objective value, its personal +best is updated. When any personal best improves on the swarm best, the swarm +best is updated. + +## 3) Velocity and position update + +The basic PSO update combines inertia, personal learning, and social learning: + +$$ +v_{i,d} \leftarrow +\omega v_{i,d} ++ \phi_p r_p(p_{i,d} - x_{i,d}) ++ \phi_g r_g(g_d - x_{i,d}) +$$ + +$$ +\mathbf{x}_i \leftarrow \mathbf{x}_i + \mathbf{v}_i. +$$ + +The random values $r_p$ and $r_g$ are sampled from $[0,1]$. In `pyswarm`, these +terms map directly to: + +- `omega`: inertia weight +- `phip`: cognitive weight, pulling particles toward their own best position +- `phig`: social weight, pulling particles toward the swarm best position + +## 4) Bounds + +`pyswarm` requires lower and upper bounds: + +$$ +\mathbf{l_b} \le \mathbf{x} \le \mathbf{u_b}. +$$ + +Particles are initialized uniformly inside these bounds. During the search, if +a particle moves outside the allowed region, its position is clipped back to the +nearest bound. + +## 5) Constraints + +Constraints are written as inequality functions. A particle is feasible when +every constraint value is non-negative: + +$$ +c_j(\mathbf{x}) \ge 0. +$$ + +There are two supported forms: + +- `f_ieqcons`: one function returning a list or array of constraint values +- `ieqcons`: a list of scalar constraint functions + +The examples in this project use `f_ieqcons` for both the constrained banana +problem and the two-bar truss problem. + +## 6) Parameters and behavior + +The choice of PSO parameters affects convergence speed and solution quality. +The Wikipedia summary notes that inertia should be kept below `1` to avoid +unbounded divergence in common analyses, and that cognitive/social coefficients +are often chosen by the practitioner or tuned for the problem. + +The defaults in `pyswarm` are conservative: + +- `omega = 0.5` +- `phip = 0.5` +- `phig = 0.5` +- `swarmsize = 100` +- `maxiter = 100` + +Increasing `swarmsize` explores more candidate solutions per iteration. +Increasing `maxiter` allows a longer search. Adjusting `omega`, `phip`, and +`phig` changes the balance between exploration and exploitation. + +## 7) Topology + +PSO variants can use different communication topologies. In a global topology, +all particles share the same best known position. In local topologies, each +particle exchanges information with only a subset of neighbors, such as a ring +neighborhood. + +`pyswarm` uses the global-best form: all particles are guided by the best +feasible position found by the swarm. + +## 8) Stopping criteria + +The optimizer stops when one of these conditions is met: + +- `maxiter` iterations have been performed +- the best position changes by less than `minstep` +- the best objective value improves by less than `minfunc` + +Because PSO is stochastic, repeated runs may return slightly different +solutions. + +## Source + +This page summarizes the PSO article text supplied from +[Wikipedia: Particle swarm optimization](https://en.wikipedia.org/wiki/Particle_swarm_optimization). diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..997e41e --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,51 @@ +site_name: pyswarm +site_description: Particle Swarm Optimization (PSO) for Python +site_url: https://eggzec.github.io/pyswarm +repo_url: https://github.com/eggzec/pyswarm +repo_name: eggzec/pyswarm + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/eggzec/pyswarm + - icon: fontawesome/brands/python + link: https://pypi.org/project/pyswarm/ + +theme: + name: material + features: + - content.code.copy + logo: _static/favicon.ico + favicon: _static/favicon.ico + +markdown_extensions: + - attr_list + - md_in_html + - pymdownx.blocks.caption + - tables + - toc: + permalink: true + title: Page contents + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + pygments_lang_class: true + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.tabbed: + alternate_style: true + - pymdownx.arithmatex: + generic: true + +extra_javascript: + - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js + +nav: + - Home: index.md + - Theory: theory.md + - Installation: installation.md + - Quickstart: quickstart.md + - API Reference: api.md + - References: references.md diff --git a/pso_examples.py b/pso_examples.py deleted file mode 100644 index c946788..0000000 --- a/pso_examples.py +++ /dev/null @@ -1,90 +0,0 @@ -import numpy as np -from pyswarm import pso - -############################################################################### - -print('*'*65) -print('Example minimization of 4th-order banana function (no constraints)') -def myfunc(x): - x1 = x[0] - x2 = x[1] - return x1**4 - 2*x2*x1**2 + x2**2 + x1**2 - 2*x1 + 5 - -lb = [-3, -1] -ub = [2, 6] - -xopt1, fopt1 = pso(myfunc, lb, ub) - -print('The optimum is at:') -print(' {}'.format(xopt1)) -print('Optimal function value:') -print(' myfunc: {}'.format(fopt1)) - -############################################################################### - -print('*'*65) -print('Example minimization of 4th-order banana function (with constraint)') -def mycon(x): - x1 = x[0] - x2 = x[1] - return [-(x1 + 0.25)**2 + 0.75*x2] - -xopt2, fopt2 = pso(myfunc, lb, ub, f_ieqcons=mycon) - -print('The optimum is at:') -print(' {}'.format(xopt2)) -print('Optimal function value:') -print(' myfunc: {}'.format(fopt2)) -print(' mycon : {}'.format(mycon(xopt2))) - -############################################################################### - -print('*'*65) -print('Engineering example: minimization of twobar truss weight, subject to') -print(' Yield Stress <= 100 kpsi') -print(' Yield Stress <= Buckling Stress') -print(' Deflection <= 0.25 inches') -def weight(x, *args): - H, d, t = x # all in inches - B, rho, E, P = args - return rho*2*np.pi*d*t*np.sqrt((B/2)**2 + H**2) - -def stress(x, *args): - H, d, t = x # all in inches - B, rho, E, P = args - return (P*np.sqrt((B/2)**2 + H**2))/(2*t*np.pi*d*H) - -def buckling_stress(x, *args): - H, d, t = x # all in inches - B, rho, E, P = args - return (np.pi**2*E*(d**2 + t**2))/(8*((B/2)**2 + H**2)) - -def deflection(x, *args): - H, d, t = x # all in inches - B, rho, E, P = args - return (P*np.sqrt((B/2)**2 + H**2)**3)/(2*t*np.pi*d*H**2*E) - -def mycons(x, *args): - strs = stress(x, *args) - buck = buckling_stress(x, *args) - defl = deflection(x, *args) - return [100 - strs, buck - strs, 0.25 - defl] - -B = 60 # inches -rho = 0.3 # lb/in^3 -E = 30000 # kpsi -P = 66 # lb (force) -args = (B, rho, E, P) -lb = [10, 1, 0.01] -ub = [30, 3, 0.25] -xopt4, fopt4 = pso(weight, lb, ub, f_ieqcons=mycons, args=args) - -print('The optimum is at:') -print(' {}'.format(xopt4)) -print('Optimal function values:') -print(' weight : {}'.format(fopt4)) -print('Constraint functions:') -print(' stress : {}'.format(stress(xopt4, *args))) -print(' buckling stress: {}'.format(buckling_stress(xopt4, *args))) -print(' deflection : {}'.format(deflection(xopt4, *args))) - diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6237b90 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,128 @@ +[build-system] +requires = ["hatchling >= 1.26", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "pyswarm" +dynamic = ["version"] +description = "Particle Swarm Optimization (PSO) for Python" +authors = [ + { name = "Abraham Lee", email = "tisimst@gmail.com" }, +] +maintainers = [ + { name = "Saud Zahir", email = "m.saud.zahir@gmail.com" }, + { name = "M Laraib Ali", email = "laraibg786@outlook.com" } +] +readme = "README.md" +license = "BSD-3-Clause" +keywords = [ + "particle", + "swarm", + "optimization", + "python", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "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", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Software Development", + "Topic :: Scientific/Engineering", + "Operating System :: OS Independent", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS", +] +dependencies = [ + "numpy", +] +requires-python = ">=3.10" + +[project.urls] +homepage = "https://eggzec.github.io/pyswarm/" +documentation = "https://eggzec.github.io/pyswarm/" +source = "https://github.com/eggzec/pyswarm" +# TODO: provide changelog URL from docs +releasenotes = "https://github.com/eggzec/pyswarm/releases/latest" +issues = "https://github.com/eggzec/pyswarm/issues" + +[dependency-groups] +dev = [ + {include-group = "docs"}, + {include-group = "lint"}, + {include-group = "test"} +] +docs = [ + "zensical>=0.0.23", + "mkdocstrings[python]>=0.30.1" +] +lint = [ + "ruff==0.15.*", +] +test = [ + "pytest>=8.3.5", + "pytest-cov>=7.0.0", + "pytest-xdist>=3.6.1", +] + +[tool.hatch.version] +source = "vcs" + +[tool.ruff] +line-length = 80 +indent-width = 4 +preview = true + +# Output serialization format for violations. The default serialization +# format is "full" [env: RUFF_OUTPUT_FORMAT=] [possible values: +# concise, full, json, json-lines, junit, grouped, github, gitlab, +# pylint, rdjson, azure, sarif] +output-format = "grouped" + +[tool.ruff.lint] +isort.lines-after-imports = 2 +isort.split-on-trailing-comma = false + +select = [ + "ANN", # flake8-annotations (required strict type annotations for public functions) + "S", # flake8-bandit (checks basic security issues in code) + "BLE", # flake8-blind-except (checks the except blocks that do not specify exception) + "FBT", # flake8-boolean-trap (ensure that boolean args can be used with kw only) + "E", # pycodestyle errors (PEP 8 style guide violations) + "W", # pycodestyle warnings (e.g., extra spaces, indentation issues) + "DOC", # pydoclint issues (e.g., extra or missing return, yield, warnings) + "A", # flake8-buitins (check variable and function names to not shadow builtins) + "N", # Naming convention checks (e.g., PEP 8 variable and function names) + "F", # Pyflakes errors (e.g., unused imports, undefined variables) + "I", # isort (Ensures imports are sorted properly) + "B", # flake8-bugbear (Detects likely bugs and bad practices) + "TID", # flake8-tidy-imports (Checks for banned or misplaced imports) + "UP", # pyupgrade (Automatically updates old Python syntax) + "YTT", # flake8-2020 (Detects outdated Python 2/3 compatibility issues) + "FLY", # flynt (Converts old-style string formatting to f-strings) + "PIE", # flake8-pie + "PL", # pylint + "RUF", # Ruff-specific rules (Additional optimizations and best practices) +] + +ignore = [] + +[tool.ruff.lint.per-file-ignores] +"**/__init__.py" = ["RUF067"] +"tests/*.py" = [] + +[tool.ruff.format] +docstring-code-format = true +skip-magic-trailing-comma = true + +[tool.pytest.ini_options] +addopts = "--doctest-modules" diff --git a/pyswarm/__init__.py b/pyswarm/__init__.py index 97d2a40..3284a34 100644 --- a/pyswarm/__init__.py +++ b/pyswarm/__init__.py @@ -1,17 +1,24 @@ """ -================================================================================ -pyswarm: Particle swarm optimization (PSO) with constraint support -================================================================================ +=========================================== +PySwarm: Particle Swarm Optimization (PSO) +=========================================== Authors: Abraham Lee Sebastian Castillo-Hair -Copyright: 2013-2015 + Saud Zahir +Copyright (c) 2013, Abraham D. Lee """ -# from __future__ import absolute_import -__author__ = 'Abraham Lee' -__version__ = '0.7' +from importlib.metadata import PackageNotFoundError, version -from pyswarm.pso import * - + +try: + __version__ = version(__name__) +except PackageNotFoundError: + __version__ = "unknown" + +from pyswarm.pso import pso + + +__all__ = ["pso"] diff --git a/pyswarm/pso.py b/pyswarm/pso.py index 1811cd9..553bc5f 100644 --- a/pyswarm/pso.py +++ b/pyswarm/pso.py @@ -1,28 +1,62 @@ +from __future__ import annotations + +import multiprocessing +from collections.abc import Callable from functools import partial + import numpy as np -def _obj_wrapper(func, args, kwargs, x): + +def _obj_wrapper( + func: Callable, args: tuple, kwargs: dict, x: np.ndarray +) -> float: return func(x, *args, **kwargs) -def _is_feasible_wrapper(func, x): - return np.all(func(x)>=0) -def _cons_none_wrapper(x): +def _is_feasible_wrapper(func: Callable, x: np.ndarray) -> bool: + return np.all(func(x) >= 0) + + +def _cons_none_wrapper(x: np.ndarray) -> np.ndarray: return np.array([0]) -def _cons_ieqcons_wrapper(ieqcons, args, kwargs, x): + +def _cons_ieqcons_wrapper( + ieqcons: list, args: tuple, kwargs: dict, x: np.ndarray +) -> np.ndarray: return np.array([y(x, *args, **kwargs) for y in ieqcons]) -def _cons_f_ieqcons_wrapper(f_ieqcons, args, kwargs, x): + +def _cons_f_ieqcons_wrapper( + f_ieqcons: Callable, args: tuple, kwargs: dict, x: np.ndarray +) -> np.ndarray: return np.array(f_ieqcons(x, *args, **kwargs)) - -def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, - swarmsize=100, omega=0.5, phip=0.5, phig=0.5, maxiter=100, - minstep=1e-8, minfunc=1e-8, debug=False, processes=1, - particle_output=False): + + +def pso( # noqa: PLR0913, PLR0917, PLR0912, PLR0915, PLR0914 + func: Callable, + lb: list | np.ndarray, + ub: list | np.ndarray, + ieqcons: list | None = None, + f_ieqcons: Callable | None = None, + args: tuple = (), + kwargs: dict | None = None, + swarmsize: int = 100, + omega: float = 0.5, + phip: float = 0.5, + phig: float = 0.5, + maxiter: int = 100, + minstep: float = 1e-8, + minfunc: float = 1e-8, + debug: bool = False, # noqa: FBT001, FBT002 + processes: int = 1, + particle_output: bool = False, # noqa: FBT001, FBT002 +) -> ( + tuple[np.ndarray, float] | tuple[np.ndarray, float, np.ndarray, np.ndarray] +): """ - Perform a particle swarm optimization (PSO) - + Particle Swarm Optimizer (PSO) + Parameters ========== func : function @@ -31,21 +65,21 @@ def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, The lower bounds of the design variable(s) ub : array The upper bounds of the design variable(s) - + Optional ======== ieqcons : list - A list of functions of length n such that ieqcons[j](x,*args) >= 0.0 in + A list of functions of length n such that ieqcons[j](x,*args) >= 0.0 in a successfully optimized problem (Default: []) f_ieqcons : function - Returns a 1-D array in which each element must be greater or equal - to 0.0 in a successfully optimized problem. If f_ieqcons is specified, + Returns a 1-D array in which each element must be greater or equal + to 0.0 in a successfully optimized problem. If f_ieqcons is specified, ieqcons is ignored (Default: None) args : tuple Additional arguments passed to objective and constraint functions (Default: empty tuple) kwargs : dict - Additional keyword arguments passed to objective and constraint + Additional keyword arguments passed to objective and constraint functions (Default: empty dict) swarmsize : int The number of particles in the swarm (Default: 100) @@ -69,12 +103,12 @@ def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, If True, progress statements will be displayed every iteration (Default: False) processes : int - The number of processes to use to evaluate objective function and + The number of processes to use to evaluate objective function and constraints (default: 1) particle_output : boolean Whether to include the best per-particle position and the objective values at those. - + Returns ======= g : array @@ -85,66 +119,83 @@ def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, The best known position per particle pf: arrray The objective values at each position in p - + + Raises + ====== + TypeError + If ``func`` is not callable. + ValueError + If bounds are mismatched or upper bounds are not all greater than lower. + """ - - assert len(lb)==len(ub), 'Lower- and upper-bounds must be the same length' - assert hasattr(func, '__call__'), 'Invalid function handle' + + if kwargs is None: + kwargs = {} + if ieqcons is None: + ieqcons = [] + if len(lb) != len(ub): + msg = "Lower- and upper-bounds must be the same length" + raise ValueError(msg) + if not callable(func): + msg = "Invalid function handle" + raise TypeError(msg) lb = np.array(lb) ub = np.array(ub) - assert np.all(ub>lb), 'All upper-bound values must be greater than lower-bound values' - + if not np.all(ub > lb): + msg = "All upper-bound values must be greater than lower-bound values" + raise ValueError(msg) + vhigh = np.abs(ub - lb) vlow = -vhigh # Initialize objective function obj = partial(_obj_wrapper, func, args, kwargs) - + # Check for constraint function(s) ######################################### if f_ieqcons is None: - if not len(ieqcons): + if not ieqcons: if debug: - print('No constraints given.') + print("No constraints given.") cons = _cons_none_wrapper else: if debug: - print('Converting ieqcons to a single constraint function') + print("Converting ieqcons to a single constraint function") cons = partial(_cons_ieqcons_wrapper, ieqcons, args, kwargs) else: if debug: - print('Single constraint function given in f_ieqcons') + print("Single constraint function given in f_ieqcons") cons = partial(_cons_f_ieqcons_wrapper, f_ieqcons, args, kwargs) is_feasible = partial(_is_feasible_wrapper, cons) # Initialize the multiprocessing module if necessary + mp_pool = None if processes > 1: - import multiprocessing mp_pool = multiprocessing.Pool(processes) - + # Initialize the particle swarm ############################################ - S = swarmsize - D = len(lb) # the number of dimensions each particle has - x = np.random.rand(S, D) # particle positions + swarm_size = swarmsize + num_dims = len(lb) # the number of dimensions each particle has + x = np.random.rand(swarm_size, num_dims) # particle positions v = np.zeros_like(x) # particle velocities p = np.zeros_like(x) # best particle positions - fx = np.zeros(S) # current particle function values - fs = np.zeros(S, dtype=bool) # feasibility of each particle - fp = np.ones(S)*np.inf # best particle function values + fx = np.zeros(swarm_size) # current particle function values + fs = np.zeros(swarm_size, dtype=bool) # feasibility of each particle + fp = np.ones(swarm_size) * np.inf # best particle function values g = [] # best swarm position fg = np.inf # best swarm position starting value - + # Initialize the particle's position - x = lb + x*(ub - lb) + x = lb + x * (ub - lb) # Calculate objective and constraints for each particle if processes > 1: fx = np.array(mp_pool.map(obj, x)) fs = np.array(mp_pool.map(is_feasible, x)) else: - for i in range(S): + for i in range(swarm_size): fx[i] = obj(x[i, :]) fs[i] = is_feasible(x[i, :]) - + # Store particle's best position (if constraints are satisfied) i_update = np.logical_and((fx < fp), fs) p[i_update, :] = x[i_update, :].copy() @@ -159,31 +210,31 @@ def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, # At the start, there may not be any feasible starting point, so just # give it a temporary "best" point since it's likely to change g = x[0, :].copy() - + # Initialize the particle's velocity - v = vlow + np.random.rand(S, D)*(vhigh - vlow) - + v = vlow + np.random.rand(swarm_size, num_dims) * (vhigh - vlow) + # Iterate until termination criterion met ################################## it = 1 while it <= maxiter: - rp = np.random.uniform(size=(S, D)) - rg = np.random.uniform(size=(S, D)) + rp = np.random.uniform(size=(swarm_size, num_dims)) + rg = np.random.uniform(size=(swarm_size, num_dims)) # Update the particles velocities - v = omega*v + phip*rp*(p - x) + phig*rg*(g - x) + v = omega * v + phip * rp * (p - x) + phig * rg * (g - x) # Update the particles' positions - x = x + v + x += v # Correct for bound violations maskl = x < lb masku = x > ub - x = x*(~np.logical_or(maskl, masku)) + lb*maskl + ub*masku + x = x * (~np.logical_or(maskl, masku)) + lb * maskl + ub * masku # Update objectives and constraints if processes > 1: fx = np.array(mp_pool.map(obj, x)) fs = np.array(mp_pool.map(is_feasible, x)) else: - for i in range(S): + for i in range(swarm_size): fx[i] = obj(x[i, :]) fs[i] = is_feasible(x[i, :]) @@ -196,22 +247,25 @@ def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, i_min = np.argmin(fp) if fp[i_min] < fg: if debug: - print('New best for swarm at iteration {:}: {:} {:}'\ - .format(it, p[i_min, :], fp[i_min])) + print( + f"New best for swarm at iteration {it}: {p[i_min, :]} {fp[i_min]}" # noqa: E501 + ) p_min = p[i_min, :].copy() - stepsize = np.sqrt(np.sum((g - p_min)**2)) + stepsize = np.sqrt(np.sum((g - p_min) ** 2)) if np.abs(fg - fp[i_min]) <= minfunc: - print('Stopping search: Swarm best objective change less than {:}'\ - .format(minfunc)) + print( + f"Stopping search: Swarm best objective change less than {minfunc}" # noqa: E501 + ) if particle_output: return p_min, fp[i_min], p, fp else: return p_min, fp[i_min] elif stepsize <= minstep: - print('Stopping search: Swarm best position change less than {:}'\ - .format(minstep)) + print( + f"Stopping search: Swarm best position change less than {minstep}" # noqa: E501 + ) if particle_output: return p_min, fp[i_min], p, fp else: @@ -221,13 +275,15 @@ def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, fg = fp[i_min] if debug: - print('Best after iteration {:}: {:} {:}'.format(it, g, fg)) + print(f"Best after iteration {it}: {g} {fg}") it += 1 - print('Stopping search: maximum iterations reached --> {:}'.format(maxiter)) - + print(f"Stopping search: maximum iterations reached --> {maxiter}") + if not is_feasible(g): - print("However, the optimization couldn't find a feasible design. Sorry") + print( + "However, the optimization couldn't find a feasible design. Sorry" + ) if particle_output: return g, fg, p, fp else: diff --git a/setup.py b/setup.py deleted file mode 100644 index dc2f59b..0000000 --- a/setup.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -from setuptools import setup - -import pyswarm - -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() - -setup( - name='pyswarm', - version=pyswarm.__version__, - author=pyswarm.__author__, - author_email='tisimst@gmail.com', - description='Particle swarm optimization (PSO) with constraint support', - url='https://github.com/tisimst/pyswarm', - license='BSD License', - long_description=read('README.rst'), - packages=['pyswarm'], - install_requires=['numpy'], - keywords=[ - 'PSO', - 'particle swarm optimization', - 'optimization', - 'python' - ], - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Education', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Topic :: Education', - 'Topic :: Scientific/Engineering', - 'Topic :: Scientific/Engineering :: Mathematics', - 'Topic :: Scientific/Engineering :: Physics', - 'Topic :: Software Development', - 'Topic :: Software Development :: Libraries', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: Utilities' - ] - ) diff --git a/tests/test_banana_no_constraints.py b/tests/test_banana_no_constraints.py new file mode 100644 index 0000000..8f31118 --- /dev/null +++ b/tests/test_banana_no_constraints.py @@ -0,0 +1,22 @@ +import numpy as np +from numpy.typing import NDArray + +from pyswarm.pso import pso + + +def banana_func(x: NDArray[np.floating]) -> np.floating: + x1 = x[0] + x2 = x[1] + return x1**4 - 2 * x2 * x1**2 + x2**2 + x1**2 - 2 * x1 + 5 + + +def test_banana_no_constraints() -> None: + lb = [-3, -1] + ub = [2, 6] + xopt, fopt = pso(banana_func, lb, ub, debug=True) + if not np.allclose(xopt, [1.0, 1.0], atol=0.001): + msg = f"Expected xopt close to [1.0, 1.0], got {xopt}" + raise AssertionError(msg) + if not np.isclose(fopt, 4.0): + msg = f"Expected fopt close to 4.0, got {fopt}" + raise AssertionError(msg) diff --git a/tests/test_banana_with_constraints.py b/tests/test_banana_with_constraints.py new file mode 100644 index 0000000..a0db97b --- /dev/null +++ b/tests/test_banana_with_constraints.py @@ -0,0 +1,34 @@ +import numpy as np +from numpy.typing import NDArray + +from pyswarm.pso import pso + + +def banana_func(x: NDArray[np.floating]) -> np.floating: + x1 = x[0] + x2 = x[1] + return x1**4 - 2 * x2 * x1**2 + x2**2 + x1**2 - 2 * x1 + 5 + + +def banana_constraint(x: NDArray[np.floating]) -> list[float]: + x1 = x[0] + x2 = x[1] + return [-((x1 + 0.25) ** 2) + 0.75 * x2] + + +def test_banana_with_constraints() -> None: + lb = [-3, -1] + ub = [2, 6] + xopt, fopt = pso( + banana_func, lb, ub, f_ieqcons=banana_constraint, debug=True + ) + if not np.allclose(xopt, [0.5, 0.75], atol=0.1): + msg = f"Expected xopt close to [0.5, 0.75], got {xopt}" + raise AssertionError(msg) + if not np.isclose(fopt, 4.5, atol=0.1): + msg = f"Expected fopt close to 4.5, got {fopt}" + raise AssertionError(msg) + constraints = banana_constraint(xopt) + if not all(c >= 0 for c in constraints): + msg = f"Expected all constraints >= 0, got {constraints}" + raise AssertionError(msg) diff --git a/tests/test_twobar_truss.py b/tests/test_twobar_truss.py new file mode 100644 index 0000000..773ba77 --- /dev/null +++ b/tests/test_twobar_truss.py @@ -0,0 +1,64 @@ +import numpy as np +from numpy.typing import NDArray + +from pyswarm.pso import pso + + +def weight(x: NDArray[np.floating], *args: float) -> np.floating: + h, d, t = x + b, rho, _e, _p = args + return rho * 2 * np.pi * d * t * np.sqrt((b / 2) ** 2 + h**2) + + +def stress(x: NDArray[np.floating], *args: float) -> np.floating: + h, d, t = x + b, _rho, _e, p = args + return (p * np.sqrt((b / 2) ** 2 + h**2)) / (2 * t * np.pi * d * h) + + +def buckling_stress(x: NDArray[np.floating], *args: float) -> np.floating: + h, d, t = x + b, _rho, e, _p = args + return (np.pi**2 * e * (d**2 + t**2)) / (8 * ((b / 2) ** 2 + h**2)) + + +def deflection(x: NDArray[np.floating], *args: float) -> np.floating: + h, d, t = x + b, _rho, e, p = args + return (p * np.sqrt((b / 2) ** 2 + h**2) ** 3) / ( + 2 * t * np.pi * d * h**2 * e + ) + + +def truss_constraints( + x: NDArray[np.floating], *args: float +) -> list[np.floating]: + strs = stress(x, *args) + buck = buckling_stress(x, *args) + defl = deflection(x, *args) + return [100 - strs, buck - strs, 0.25 - defl] + + +def test_twobar_truss() -> None: + b = 60 + rho = 0.3 + e = 30000 + p = 66 + args = (b, rho, e, p) + lb = [10, 1, 0.01] + ub = [30, 3, 0.25] + xopt, fopt = pso( + weight, + lb, + ub, + f_ieqcons=truss_constraints, + args=args, + maxiter=100, + debug=True, + ) + if not np.isclose(fopt, 11.94, atol=0.1): + msg = f"Expected fopt close to 11.94, got {fopt}" + raise AssertionError(msg) + if not all(c >= 0 for c in truss_constraints(xopt, *args)): + msg = "Expected all constraints >= 0" + raise AssertionError(msg) diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..58ed8a5 --- /dev/null +++ b/uv.lock @@ -0,0 +1,959 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.11'", + "python_full_version < '3.11'", +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/d4/7827d9ffa34d5d4d752eec907022aa417120936282fc488306f5da08c292/coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415", size = 219152, upload-time = "2026-02-09T12:56:11.974Z" }, + { url = "https://files.pythonhosted.org/packages/35/b0/d69df26607c64043292644dbb9dc54b0856fabaa2cbb1eeee3331cc9e280/coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b", size = 219667, upload-time = "2026-02-09T12:56:13.33Z" }, + { url = "https://files.pythonhosted.org/packages/82/a4/c1523f7c9e47b2271dbf8c2a097e7a1f89ef0d66f5840bb59b7e8814157b/coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a", size = 246425, upload-time = "2026-02-09T12:56:14.552Z" }, + { url = "https://files.pythonhosted.org/packages/f8/02/aa7ec01d1a5023c4b680ab7257f9bfde9defe8fdddfe40be096ac19e8177/coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f", size = 248229, upload-time = "2026-02-09T12:56:16.31Z" }, + { url = "https://files.pythonhosted.org/packages/35/98/85aba0aed5126d896162087ef3f0e789a225697245256fc6181b95f47207/coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012", size = 250106, upload-time = "2026-02-09T12:56:18.024Z" }, + { url = "https://files.pythonhosted.org/packages/96/72/1db59bd67494bc162e3e4cd5fbc7edba2c7026b22f7c8ef1496d58c2b94c/coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def", size = 252021, upload-time = "2026-02-09T12:56:19.272Z" }, + { url = "https://files.pythonhosted.org/packages/9d/97/72899c59c7066961de6e3daa142d459d47d104956db43e057e034f015c8a/coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256", size = 247114, upload-time = "2026-02-09T12:56:21.051Z" }, + { url = "https://files.pythonhosted.org/packages/39/1f/f1885573b5970235e908da4389176936c8933e86cb316b9620aab1585fa2/coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda", size = 248143, upload-time = "2026-02-09T12:56:22.585Z" }, + { url = "https://files.pythonhosted.org/packages/a8/cf/e80390c5b7480b722fa3e994f8202807799b85bc562aa4f1dde209fbb7be/coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92", size = 246152, upload-time = "2026-02-09T12:56:23.748Z" }, + { url = "https://files.pythonhosted.org/packages/44/bf/f89a8350d85572f95412debb0fb9bb4795b1d5b5232bd652923c759e787b/coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c", size = 249959, upload-time = "2026-02-09T12:56:25.209Z" }, + { url = "https://files.pythonhosted.org/packages/f7/6e/612a02aece8178c818df273e8d1642190c4875402ca2ba74514394b27aba/coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58", size = 246416, upload-time = "2026-02-09T12:56:26.475Z" }, + { url = "https://files.pythonhosted.org/packages/cb/98/b5afc39af67c2fa6786b03c3a7091fc300947387ce8914b096db8a73d67a/coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9", size = 247025, upload-time = "2026-02-09T12:56:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/51/30/2bba8ef0682d5bd210c38fe497e12a06c9f8d663f7025e9f5c2c31ce847d/coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf", size = 221758, upload-time = "2026-02-09T12:56:29.051Z" }, + { url = "https://files.pythonhosted.org/packages/78/13/331f94934cf6c092b8ea59ff868eb587bc8fe0893f02c55bc6c0183a192e/coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95", size = 222693, upload-time = "2026-02-09T12:56:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/b4/ad/b59e5b451cf7172b8d1043dc0fa718f23aab379bc1521ee13d4bd9bfa960/coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053", size = 219278, upload-time = "2026-02-09T12:56:31.673Z" }, + { url = "https://files.pythonhosted.org/packages/f1/17/0cb7ca3de72e5f4ef2ec2fa0089beafbcaaaead1844e8b8a63d35173d77d/coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11", size = 219783, upload-time = "2026-02-09T12:56:33.104Z" }, + { url = "https://files.pythonhosted.org/packages/ab/63/325d8e5b11e0eaf6d0f6a44fad444ae58820929a9b0de943fa377fe73e85/coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa", size = 250200, upload-time = "2026-02-09T12:56:34.474Z" }, + { url = "https://files.pythonhosted.org/packages/76/53/c16972708cbb79f2942922571a687c52bd109a7bd51175aeb7558dff2236/coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7", size = 252114, upload-time = "2026-02-09T12:56:35.749Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c2/7ab36d8b8cc412bec9ea2d07c83c48930eb4ba649634ba00cb7e4e0f9017/coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00", size = 254220, upload-time = "2026-02-09T12:56:37.796Z" }, + { url = "https://files.pythonhosted.org/packages/d6/4d/cf52c9a3322c89a0e6febdfbc83bb45c0ed3c64ad14081b9503adee702e7/coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef", size = 256164, upload-time = "2026-02-09T12:56:39.016Z" }, + { url = "https://files.pythonhosted.org/packages/78/e9/eb1dd17bd6de8289df3580e967e78294f352a5df8a57ff4671ee5fc3dcd0/coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903", size = 250325, upload-time = "2026-02-09T12:56:40.668Z" }, + { url = "https://files.pythonhosted.org/packages/71/07/8c1542aa873728f72267c07278c5cc0ec91356daf974df21335ccdb46368/coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f", size = 251913, upload-time = "2026-02-09T12:56:41.97Z" }, + { url = "https://files.pythonhosted.org/packages/74/d7/c62e2c5e4483a748e27868e4c32ad3daa9bdddbba58e1bc7a15e252baa74/coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299", size = 249974, upload-time = "2026-02-09T12:56:43.323Z" }, + { url = "https://files.pythonhosted.org/packages/98/9f/4c5c015a6e98ced54efd0f5cf8d31b88e5504ecb6857585fc0161bb1e600/coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505", size = 253741, upload-time = "2026-02-09T12:56:45.155Z" }, + { url = "https://files.pythonhosted.org/packages/bd/59/0f4eef89b9f0fcd9633b5d350016f54126ab49426a70ff4c4e87446cabdc/coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6", size = 249695, upload-time = "2026-02-09T12:56:46.636Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2c/b7476f938deb07166f3eb281a385c262675d688ff4659ad56c6c6b8e2e70/coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9", size = 250599, upload-time = "2026-02-09T12:56:48.13Z" }, + { url = "https://files.pythonhosted.org/packages/b8/34/c3420709d9846ee3785b9f2831b4d94f276f38884032dca1457fa83f7476/coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9", size = 221780, upload-time = "2026-02-09T12:56:50.479Z" }, + { url = "https://files.pythonhosted.org/packages/61/08/3d9c8613079d2b11c185b865de9a4c1a68850cfda2b357fae365cf609f29/coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f", size = 222715, upload-time = "2026-02-09T12:56:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/18/1a/54c3c80b2f056164cc0a6cdcb040733760c7c4be9d780fe655f356f433e4/coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f", size = 221385, upload-time = "2026-02-09T12:56:53.194Z" }, + { url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" }, + { url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" }, + { url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" }, + { url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" }, + { url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" }, + { url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" }, + { url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" }, + { url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" }, + { url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" }, + { url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" }, + { url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" }, + { url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" }, + { url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" }, + { url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" }, + { url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" }, + { url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" }, + { url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" }, + { url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" }, + { url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" }, + { url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" }, + { url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" }, + { url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" }, + { url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" }, + { url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" }, + { url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" }, + { url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" }, + { url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" }, + { url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" }, + { url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" }, + { url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" }, + { url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" }, + { url = "https://files.pythonhosted.org/packages/92/11/a9cf762bb83386467737d32187756a42094927150c3e107df4cb078e8590/coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601", size = 219522, upload-time = "2026-02-09T12:58:08.623Z" }, + { url = "https://files.pythonhosted.org/packages/d3/28/56e6d892b7b052236d67c95f1936b6a7cf7c3e2634bf27610b8cbd7f9c60/coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689", size = 219855, upload-time = "2026-02-09T12:58:10.176Z" }, + { url = "https://files.pythonhosted.org/packages/e5/69/233459ee9eb0c0d10fcc2fe425a029b3fa5ce0f040c966ebce851d030c70/coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c", size = 250887, upload-time = "2026-02-09T12:58:12.503Z" }, + { url = "https://files.pythonhosted.org/packages/06/90/2cdab0974b9b5bbc1623f7876b73603aecac11b8d95b85b5b86b32de5eab/coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129", size = 253396, upload-time = "2026-02-09T12:58:14.615Z" }, + { url = "https://files.pythonhosted.org/packages/ac/15/ea4da0f85bf7d7b27635039e649e99deb8173fe551096ea15017f7053537/coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552", size = 254745, upload-time = "2026-02-09T12:58:16.162Z" }, + { url = "https://files.pythonhosted.org/packages/99/11/bb356e86920c655ca4d61daee4e2bbc7258f0a37de0be32d233b561134ff/coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a", size = 257055, upload-time = "2026-02-09T12:58:17.892Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0f/9ae1f8cb17029e09da06ca4e28c9e1d5c1c0a511c7074592e37e0836c915/coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356", size = 250911, upload-time = "2026-02-09T12:58:19.495Z" }, + { url = "https://files.pythonhosted.org/packages/89/3a/adfb68558fa815cbc29747b553bc833d2150228f251b127f1ce97e48547c/coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71", size = 252754, upload-time = "2026-02-09T12:58:21.064Z" }, + { url = "https://files.pythonhosted.org/packages/32/b1/540d0c27c4e748bd3cd0bd001076ee416eda993c2bae47a73b7cc9357931/coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5", size = 250720, upload-time = "2026-02-09T12:58:22.622Z" }, + { url = "https://files.pythonhosted.org/packages/c7/95/383609462b3ffb1fe133014a7c84fc0dd01ed55ac6140fa1093b5af7ebb1/coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98", size = 254994, upload-time = "2026-02-09T12:58:24.548Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ba/1761138e86c81680bfc3c49579d66312865457f9fe405b033184e5793cb3/coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5", size = 250531, upload-time = "2026-02-09T12:58:26.271Z" }, + { url = "https://files.pythonhosted.org/packages/f8/8e/05900df797a9c11837ab59c4d6fe94094e029582aab75c3309a93e6fb4e3/coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0", size = 252189, upload-time = "2026-02-09T12:58:27.807Z" }, + { url = "https://files.pythonhosted.org/packages/00/bd/29c9f2db9ea4ed2738b8a9508c35626eb205d51af4ab7bf56a21a2e49926/coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb", size = 222258, upload-time = "2026-02-09T12:58:29.441Z" }, + { url = "https://files.pythonhosted.org/packages/a7/4d/1f8e723f6829977410efeb88f73673d794075091c8c7c18848d273dc9d73/coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505", size = 223073, upload-time = "2026-02-09T12:58:31.026Z" }, + { url = "https://files.pythonhosted.org/packages/51/5b/84100025be913b44e082ea32abcf1afbf4e872f5120b7a1cab1d331b1e13/coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2", size = 221638, upload-time = "2026-02-09T12:58:32.599Z" }, + { url = "https://files.pythonhosted.org/packages/a7/e4/c884a405d6ead1370433dad1e3720216b4f9fd8ef5b64bfd984a2a60a11a/coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056", size = 220246, upload-time = "2026-02-09T12:58:34.181Z" }, + { url = "https://files.pythonhosted.org/packages/81/5c/4d7ed8b23b233b0fffbc9dfec53c232be2e695468523242ea9fd30f97ad2/coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc", size = 220514, upload-time = "2026-02-09T12:58:35.704Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6f/3284d4203fd2f28edd73034968398cd2d4cb04ab192abc8cff007ea35679/coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9", size = 261877, upload-time = "2026-02-09T12:58:37.864Z" }, + { url = "https://files.pythonhosted.org/packages/09/aa/b672a647bbe1556a85337dc95bfd40d146e9965ead9cc2fe81bde1e5cbce/coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf", size = 264004, upload-time = "2026-02-09T12:58:39.492Z" }, + { url = "https://files.pythonhosted.org/packages/79/a1/aa384dbe9181f98bba87dd23dda436f0c6cf2e148aecbb4e50fc51c1a656/coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55", size = 266408, upload-time = "2026-02-09T12:58:41.852Z" }, + { url = "https://files.pythonhosted.org/packages/53/5e/5150bf17b4019bc600799f376bb9606941e55bd5a775dc1e096b6ffea952/coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72", size = 267544, upload-time = "2026-02-09T12:58:44.093Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ed/f1de5c675987a4a7a672250d2c5c9d73d289dbf13410f00ed7181d8017dd/coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a", size = 260980, upload-time = "2026-02-09T12:58:45.721Z" }, + { url = "https://files.pythonhosted.org/packages/b3/e3/fe758d01850aa172419a6743fe76ba8b92c29d181d4f676ffe2dae2ba631/coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6", size = 263871, upload-time = "2026-02-09T12:58:47.334Z" }, + { url = "https://files.pythonhosted.org/packages/b6/76/b829869d464115e22499541def9796b25312b8cf235d3bb00b39f1675395/coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3", size = 261472, upload-time = "2026-02-09T12:58:48.995Z" }, + { url = "https://files.pythonhosted.org/packages/14/9e/caedb1679e73e2f6ad240173f55218488bfe043e38da577c4ec977489915/coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750", size = 265210, upload-time = "2026-02-09T12:58:51.178Z" }, + { url = "https://files.pythonhosted.org/packages/3a/10/0dd02cb009b16ede425b49ec344aba13a6ae1dc39600840ea6abcb085ac4/coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39", size = 260319, upload-time = "2026-02-09T12:58:53.081Z" }, + { url = "https://files.pythonhosted.org/packages/92/8e/234d2c927af27c6d7a5ffad5bd2cf31634c46a477b4c7adfbfa66baf7ebb/coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0", size = 262638, upload-time = "2026-02-09T12:58:55.258Z" }, + { url = "https://files.pythonhosted.org/packages/2f/64/e5547c8ff6964e5965c35a480855911b61509cce544f4d442caa759a0702/coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea", size = 223040, upload-time = "2026-02-09T12:58:56.936Z" }, + { url = "https://files.pythonhosted.org/packages/c7/96/38086d58a181aac86d503dfa9c47eb20715a79c3e3acbdf786e92e5c09a8/coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932", size = 224148, upload-time = "2026-02-09T12:58:58.645Z" }, + { url = "https://files.pythonhosted.org/packages/ce/72/8d10abd3740a0beb98c305e0c3faf454366221c0f37a8bcf8f60020bb65a/coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b", size = 222172, upload-time = "2026-02-09T12:59:00.396Z" }, + { url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "deepmerge" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/3a/b0ba594708f1ad0bc735884b3ad854d3ca3bdc1d741e56e40bbda6263499/deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20", size = 19890, upload-time = "2024-08-30T05:31:50.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475, upload-time = "2024-08-30T05:31:48.659Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "execnet" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "griffelib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/06/eccbd311c9e2b3ca45dbc063b93134c57a1ccc7607c5e545264ad092c4a9/griffelib-2.0.0.tar.gz", hash = "sha256:e504d637a089f5cab9b5daf18f7645970509bf4f53eda8d79ed71cce8bd97934", size = 166312, upload-time = "2026-03-23T21:06:55.954Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/51/c936033e16d12b627ea334aaaaf42229c37620d0f15593456ab69ab48161/griffelib-2.0.0-py3-none-any.whl", hash = "sha256:01284878c966508b6d6f1dbff9b6fa607bc062d8261c5c7253cb285b06422a7f", size = 142004, upload-time = "2026-02-09T19:09:40.561Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588, upload-time = "2026-02-10T15:23:55.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530, upload-time = "2026-02-10T15:23:53.817Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/62/0dfc5719514115bf1781f44b1d7f2a0923fcc01e9c5d7990e48a05c9ae5d/mkdocstrings-1.0.3.tar.gz", hash = "sha256:ab670f55040722b49bb45865b2e93b824450fb4aef638b00d7acb493a9020434", size = 100946, upload-time = "2026-02-07T14:31:40.973Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/41/1cf02e3df279d2dd846a1bf235a928254eba9006dd22b4a14caa71aed0f7/mkdocstrings-1.0.3-py3-none-any.whl", hash = "sha256:0d66d18430c2201dc7fe85134277382baaa15e6b30979f3f3bdbabd6dbdb6046", size = 35523, upload-time = "2026-02-07T14:31:39.27Z" }, +] + +[package.optional-dependencies] +python = [ + { name = "mkdocstrings-python" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffelib" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/33/c225eaf898634bdda489a6766fc35d1683c640bffe0e0acd10646b13536d/mkdocstrings_python-2.0.3.tar.gz", hash = "sha256:c518632751cc869439b31c9d3177678ad2bfa5c21b79b863956ad68fc92c13b8", size = 199083, upload-time = "2026-02-20T10:38:36.368Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/28/79f0f8de97cce916d5ae88a7bee1ad724855e83e6019c0b4d5b3fabc80f3/mkdocstrings_python-2.0.3-py3-none-any.whl", hash = "sha256:0b83513478bdfd803ff05aa43e9b1fca9dd22bcd9471f09ca6257f009bc5ee12", size = 104779, upload-time = "2026-02-20T10:38:34.517Z" }, +] + +[[package]] +name = "numpy" +version = "2.2.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, + { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, + { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, + { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, + { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, + { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, + { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, + { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, + { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, + { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, + { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, + { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, + { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, + { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, + { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, + { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, + { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, + { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, + { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, + { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, + { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.4" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/c6/4218570d8c8ecc9704b5157a3348e486e84ef4be0ed3e38218ab473c83d2/numpy-2.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f983334aea213c99992053ede6168500e5f086ce74fbc4acc3f2b00f5762e9db", size = 16976799, upload-time = "2026-03-29T13:18:15.438Z" }, + { url = "https://files.pythonhosted.org/packages/dd/92/b4d922c4a5f5dab9ed44e6153908a5c665b71acf183a83b93b690996e39b/numpy-2.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72944b19f2324114e9dc86a159787333b77874143efcf89a5167ef83cfee8af0", size = 14971552, upload-time = "2026-03-29T13:18:18.606Z" }, + { url = "https://files.pythonhosted.org/packages/8a/dc/df98c095978fa6ee7b9a9387d1d58cbb3d232d0e69ad169a4ce784bde4fd/numpy-2.4.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:86b6f55f5a352b48d7fbfd2dbc3d5b780b2d79f4d3c121f33eb6efb22e9a2015", size = 5476566, upload-time = "2026-03-29T13:18:21.532Z" }, + { url = "https://files.pythonhosted.org/packages/28/34/b3fdcec6e725409223dd27356bdf5a3c2cc2282e428218ecc9cb7acc9763/numpy-2.4.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:ba1f4fc670ed79f876f70082eff4f9583c15fb9a4b89d6188412de4d18ae2f40", size = 6806482, upload-time = "2026-03-29T13:18:23.634Z" }, + { url = "https://files.pythonhosted.org/packages/68/62/63417c13aa35d57bee1337c67446761dc25ea6543130cf868eace6e8157b/numpy-2.4.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a87ec22c87be071b6bdbd27920b129b94f2fc964358ce38f3822635a3e2e03d", size = 15973376, upload-time = "2026-03-29T13:18:26.677Z" }, + { url = "https://files.pythonhosted.org/packages/cf/c5/9fcb7e0e69cef59cf10c746b84f7d58b08bc66a6b7d459783c5a4f6101a6/numpy-2.4.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df3775294accfdd75f32c74ae39fcba920c9a378a2fc18a12b6820aa8c1fb502", size = 16925137, upload-time = "2026-03-29T13:18:30.14Z" }, + { url = "https://files.pythonhosted.org/packages/7e/43/80020edacb3f84b9efdd1591120a4296462c23fd8db0dde1666f6ef66f13/numpy-2.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d4e437e295f18ec29bc79daf55e8a47a9113df44d66f702f02a293d93a2d6dd", size = 17329414, upload-time = "2026-03-29T13:18:33.733Z" }, + { url = "https://files.pythonhosted.org/packages/fd/06/af0658593b18a5f73532d377188b964f239eb0894e664a6c12f484472f97/numpy-2.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6aa3236c78803afbcb255045fbef97a9e25a1f6c9888357d205ddc42f4d6eba5", size = 18658397, upload-time = "2026-03-29T13:18:37.511Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ce/13a09ed65f5d0ce5c7dd0669250374c6e379910f97af2c08c57b0608eee4/numpy-2.4.4-cp311-cp311-win32.whl", hash = "sha256:30caa73029a225b2d40d9fae193e008e24b2026b7ee1a867b7ee8d96ca1a448e", size = 6239499, upload-time = "2026-03-29T13:18:40.372Z" }, + { url = "https://files.pythonhosted.org/packages/bd/63/05d193dbb4b5eec1eca73822d80da98b511f8328ad4ae3ca4caf0f4db91d/numpy-2.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:6bbe4eb67390b0a0265a2c25458f6b90a409d5d069f1041e6aff1e27e3d9a79e", size = 12614257, upload-time = "2026-03-29T13:18:42.95Z" }, + { url = "https://files.pythonhosted.org/packages/87/c5/8168052f080c26fa984c413305012be54741c9d0d74abd7fbeeccae3889f/numpy-2.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:fcfe2045fd2e8f3cb0ce9d4ba6dba6333b8fa05bb8a4939c908cd43322d14c7e", size = 10486775, upload-time = "2026-03-29T13:18:45.835Z" }, + { url = "https://files.pythonhosted.org/packages/28/05/32396bec30fb2263770ee910142f49c1476d08e8ad41abf8403806b520ce/numpy-2.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15716cfef24d3a9762e3acdf87e27f58dc823d1348f765bbea6bef8c639bfa1b", size = 16689272, upload-time = "2026-03-29T13:18:49.223Z" }, + { url = "https://files.pythonhosted.org/packages/c5/f3/a983d28637bfcd763a9c7aafdb6d5c0ebf3d487d1e1459ffdb57e2f01117/numpy-2.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23cbfd4c17357c81021f21540da84ee282b9c8fba38a03b7b9d09ba6b951421e", size = 14699573, upload-time = "2026-03-29T13:18:52.629Z" }, + { url = "https://files.pythonhosted.org/packages/9b/fd/e5ecca1e78c05106d98028114f5c00d3eddb41207686b2b7de3e477b0e22/numpy-2.4.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b3b60bb7cba2c8c81837661c488637eee696f59a877788a396d33150c35d842", size = 5204782, upload-time = "2026-03-29T13:18:55.579Z" }, + { url = "https://files.pythonhosted.org/packages/de/2f/702a4594413c1a8632092beae8aba00f1d67947389369b3777aed783fdca/numpy-2.4.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e4a010c27ff6f210ff4c6ef34394cd61470d01014439b192ec22552ee867f2a8", size = 6552038, upload-time = "2026-03-29T13:18:57.769Z" }, + { url = "https://files.pythonhosted.org/packages/7f/37/eed308a8f56cba4d1fdf467a4fc67ef4ff4bf1c888f5fc980481890104b1/numpy-2.4.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9e75681b59ddaa5e659898085ae0eaea229d054f2ac0c7e563a62205a700121", size = 15670666, upload-time = "2026-03-29T13:19:00.341Z" }, + { url = "https://files.pythonhosted.org/packages/0a/0d/0e3ecece05b7a7e87ab9fb587855548da437a061326fff64a223b6dcb78a/numpy-2.4.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:81f4a14bee47aec54f883e0cad2d73986640c1590eb9bfaaba7ad17394481e6e", size = 16645480, upload-time = "2026-03-29T13:19:03.63Z" }, + { url = "https://files.pythonhosted.org/packages/34/49/f2312c154b82a286758ee2f1743336d50651f8b5195db18cdb63675ff649/numpy-2.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:62d6b0f03b694173f9fcb1fb317f7222fd0b0b103e784c6549f5e53a27718c44", size = 17020036, upload-time = "2026-03-29T13:19:07.428Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e9/736d17bd77f1b0ec4f9901aaec129c00d59f5d84d5e79bba540ef12c2330/numpy-2.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fbc356aae7adf9e6336d336b9c8111d390a05df88f1805573ebb0807bd06fd1d", size = 18368643, upload-time = "2026-03-29T13:19:10.775Z" }, + { url = "https://files.pythonhosted.org/packages/63/f6/d417977c5f519b17c8a5c3bc9e8304b0908b0e21136fe43bf628a1343914/numpy-2.4.4-cp312-cp312-win32.whl", hash = "sha256:0d35aea54ad1d420c812bfa0385c71cd7cc5bcf7c65fed95fc2cd02fe8c79827", size = 5961117, upload-time = "2026-03-29T13:19:13.464Z" }, + { url = "https://files.pythonhosted.org/packages/2d/5b/e1deebf88ff431b01b7406ca3583ab2bbb90972bbe1c568732e49c844f7e/numpy-2.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:b5f0362dc928a6ecd9db58868fca5e48485205e3855957bdedea308f8672ea4a", size = 12320584, upload-time = "2026-03-29T13:19:16.155Z" }, + { url = "https://files.pythonhosted.org/packages/58/89/e4e856ac82a68c3ed64486a544977d0e7bdd18b8da75b78a577ca31c4395/numpy-2.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:846300f379b5b12cc769334464656bc882e0735d27d9726568bc932fdc49d5ec", size = 10221450, upload-time = "2026-03-29T13:19:18.994Z" }, + { url = "https://files.pythonhosted.org/packages/14/1d/d0a583ce4fefcc3308806a749a536c201ed6b5ad6e1322e227ee4848979d/numpy-2.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:08f2e31ed5e6f04b118e49821397f12767934cfdd12a1ce86a058f91e004ee50", size = 16684933, upload-time = "2026-03-29T13:19:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/c1/62/2b7a48fbb745d344742c0277f01286dead15f3f68e4f359fbfcf7b48f70f/numpy-2.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e823b8b6edc81e747526f70f71a9c0a07ac4e7ad13020aa736bb7c9d67196115", size = 14694532, upload-time = "2026-03-29T13:19:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/e5/87/499737bfba066b4a3bebff24a8f1c5b2dee410b209bc6668c9be692580f0/numpy-2.4.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4a19d9dba1a76618dd86b164d608566f393f8ec6ac7c44f0cc879011c45e65af", size = 5199661, upload-time = "2026-03-29T13:19:28.31Z" }, + { url = "https://files.pythonhosted.org/packages/cd/da/464d551604320d1491bc345efed99b4b7034143a85787aab78d5691d5a0e/numpy-2.4.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d2a8490669bfe99a233298348acc2d824d496dee0e66e31b66a6022c2ad74a5c", size = 6547539, upload-time = "2026-03-29T13:19:30.97Z" }, + { url = "https://files.pythonhosted.org/packages/7d/90/8d23e3b0dafd024bf31bdec225b3bb5c2dbfa6912f8a53b8659f21216cbf/numpy-2.4.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45dbed2ab436a9e826e302fcdcbe9133f9b0006e5af7168afb8963a6520da103", size = 15668806, upload-time = "2026-03-29T13:19:33.887Z" }, + { url = "https://files.pythonhosted.org/packages/d1/73/a9d864e42a01896bb5974475438f16086be9ba1f0d19d0bb7a07427c4a8b/numpy-2.4.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c901b15172510173f5cb310eae652908340f8dede90fff9e3bf6c0d8dfd92f83", size = 16632682, upload-time = "2026-03-29T13:19:37.336Z" }, + { url = "https://files.pythonhosted.org/packages/34/fb/14570d65c3bde4e202a031210475ae9cde9b7686a2e7dc97ee67d2833b35/numpy-2.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:99d838547ace2c4aace6c4f76e879ddfe02bb58a80c1549928477862b7a6d6ed", size = 17019810, upload-time = "2026-03-29T13:19:40.963Z" }, + { url = "https://files.pythonhosted.org/packages/8a/77/2ba9d87081fd41f6d640c83f26fb7351e536b7ce6dd9061b6af5904e8e46/numpy-2.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0aec54fd785890ecca25a6003fd9a5aed47ad607bbac5cd64f836ad8666f4959", size = 18357394, upload-time = "2026-03-29T13:19:44.859Z" }, + { url = "https://files.pythonhosted.org/packages/a2/23/52666c9a41708b0853fa3b1a12c90da38c507a3074883823126d4e9d5b30/numpy-2.4.4-cp313-cp313-win32.whl", hash = "sha256:07077278157d02f65c43b1b26a3886bce886f95d20aabd11f87932750dfb14ed", size = 5959556, upload-time = "2026-03-29T13:19:47.661Z" }, + { url = "https://files.pythonhosted.org/packages/57/fb/48649b4971cde70d817cf97a2a2fdc0b4d8308569f1dd2f2611959d2e0cf/numpy-2.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:5c70f1cc1c4efbe316a572e2d8b9b9cc44e89b95f79ca3331553fbb63716e2bf", size = 12317311, upload-time = "2026-03-29T13:19:50.67Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/11490cddd564eb4de97b4579ef6bfe6a736cc07e94c1598590ae25415e01/numpy-2.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:ef4059d6e5152fa1a39f888e344c73fdc926e1b2dd58c771d67b0acfbf2aa67d", size = 10222060, upload-time = "2026-03-29T13:19:54.229Z" }, + { url = "https://files.pythonhosted.org/packages/99/5d/dab4339177a905aad3e2221c915b35202f1ec30d750dd2e5e9d9a72b804b/numpy-2.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4bbc7f303d125971f60ec0aaad5e12c62d0d2c925f0ab1273debd0e4ba37aba5", size = 14822302, upload-time = "2026-03-29T13:19:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e4/0564a65e7d3d97562ed6f9b0fd0fb0a6f559ee444092f105938b50043876/numpy-2.4.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:4d6d57903571f86180eb98f8f0c839fa9ebbfb031356d87f1361be91e433f5b7", size = 5327407, upload-time = "2026-03-29T13:20:00.601Z" }, + { url = "https://files.pythonhosted.org/packages/29/8d/35a3a6ce5ad371afa58b4700f1c820f8f279948cca32524e0a695b0ded83/numpy-2.4.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:4636de7fd195197b7535f231b5de9e4b36d2c440b6e566d2e4e4746e6af0ca93", size = 6647631, upload-time = "2026-03-29T13:20:02.855Z" }, + { url = "https://files.pythonhosted.org/packages/f4/da/477731acbd5a58a946c736edfdabb2ac5b34c3d08d1ba1a7b437fa0884df/numpy-2.4.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad2e2ef14e0b04e544ea2fa0a36463f847f113d314aa02e5b402fdf910ef309e", size = 15727691, upload-time = "2026-03-29T13:20:06.004Z" }, + { url = "https://files.pythonhosted.org/packages/e6/db/338535d9b152beabeb511579598418ba0212ce77cf9718edd70262cc4370/numpy-2.4.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a285b3b96f951841799528cd1f4f01cd70e7e0204b4abebac9463eecfcf2a40", size = 16681241, upload-time = "2026-03-29T13:20:09.417Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a9/ad248e8f58beb7a0219b413c9c7d8151c5d285f7f946c3e26695bdbbe2df/numpy-2.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f8474c4241bc18b750be2abea9d7a9ec84f46ef861dbacf86a4f6e043401f79e", size = 17085767, upload-time = "2026-03-29T13:20:13.126Z" }, + { url = "https://files.pythonhosted.org/packages/b5/1a/3b88ccd3694681356f70da841630e4725a7264d6a885c8d442a697e1146b/numpy-2.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4e874c976154687c1f71715b034739b45c7711bec81db01914770373d125e392", size = 18403169, upload-time = "2026-03-29T13:20:17.096Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c9/fcfd5d0639222c6eac7f304829b04892ef51c96a75d479214d77e3ce6e33/numpy-2.4.4-cp313-cp313t-win32.whl", hash = "sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008", size = 6083477, upload-time = "2026-03-29T13:20:20.195Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e3/3938a61d1c538aaec8ed6fd6323f57b0c2d2d2219512434c5c878db76553/numpy-2.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8", size = 12457487, upload-time = "2026-03-29T13:20:22.946Z" }, + { url = "https://files.pythonhosted.org/packages/97/6a/7e345032cc60501721ef94e0e30b60f6b0bd601f9174ebd36389a2b86d40/numpy-2.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233", size = 10292002, upload-time = "2026-03-29T13:20:25.909Z" }, + { url = "https://files.pythonhosted.org/packages/6e/06/c54062f85f673dd5c04cbe2f14c3acb8c8b95e3384869bb8cc9bff8cb9df/numpy-2.4.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0", size = 16684353, upload-time = "2026-03-29T13:20:29.504Z" }, + { url = "https://files.pythonhosted.org/packages/4c/39/8a320264a84404c74cc7e79715de85d6130fa07a0898f67fb5cd5bd79908/numpy-2.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a", size = 14704914, upload-time = "2026-03-29T13:20:33.547Z" }, + { url = "https://files.pythonhosted.org/packages/91/fb/287076b2614e1d1044235f50f03748f31fa287e3dbe6abeb35cdfa351eca/numpy-2.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a", size = 5210005, upload-time = "2026-03-29T13:20:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/63/eb/fcc338595309910de6ecabfcef2419a9ce24399680bfb149421fa2df1280/numpy-2.4.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b", size = 6544974, upload-time = "2026-03-29T13:20:39.014Z" }, + { url = "https://files.pythonhosted.org/packages/44/5d/e7e9044032a716cdfaa3fba27a8e874bf1c5f1912a1ddd4ed071bf8a14a6/numpy-2.4.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a", size = 15684591, upload-time = "2026-03-29T13:20:42.146Z" }, + { url = "https://files.pythonhosted.org/packages/98/7c/21252050676612625449b4807d6b695b9ce8a7c9e1c197ee6216c8a65c7c/numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d", size = 16637700, upload-time = "2026-03-29T13:20:46.204Z" }, + { url = "https://files.pythonhosted.org/packages/b1/29/56d2bbef9465db24ef25393383d761a1af4f446a1df9b8cded4fe3a5a5d7/numpy-2.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252", size = 17035781, upload-time = "2026-03-29T13:20:50.242Z" }, + { url = "https://files.pythonhosted.org/packages/e3/2b/a35a6d7589d21f44cea7d0a98de5ddcbb3d421b2622a5c96b1edf18707c3/numpy-2.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f", size = 18362959, upload-time = "2026-03-29T13:20:54.019Z" }, + { url = "https://files.pythonhosted.org/packages/64/c9/d52ec581f2390e0f5f85cbfd80fb83d965fc15e9f0e1aec2195faa142cde/numpy-2.4.4-cp314-cp314-win32.whl", hash = "sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc", size = 6008768, upload-time = "2026-03-29T13:20:56.912Z" }, + { url = "https://files.pythonhosted.org/packages/fa/22/4cc31a62a6c7b74a8730e31a4274c5dc80e005751e277a2ce38e675e4923/numpy-2.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74", size = 12449181, upload-time = "2026-03-29T13:20:59.548Z" }, + { url = "https://files.pythonhosted.org/packages/70/2e/14cda6f4d8e396c612d1bf97f22958e92148801d7e4f110cabebdc0eef4b/numpy-2.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb", size = 10496035, upload-time = "2026-03-29T13:21:02.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e8/8fed8c8d848d7ecea092dc3469643f9d10bc3a134a815a3b033da1d2039b/numpy-2.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e", size = 14824958, upload-time = "2026-03-29T13:21:05.671Z" }, + { url = "https://files.pythonhosted.org/packages/05/1a/d8007a5138c179c2bf33ef44503e83d70434d2642877ee8fbb230e7c0548/numpy-2.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113", size = 5330020, upload-time = "2026-03-29T13:21:08.635Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/ffb99ac6ae93faf117bcbd5c7ba48a7f45364a33e8e458545d3633615dda/numpy-2.4.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d", size = 6650758, upload-time = "2026-03-29T13:21:10.949Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6e/795cc078b78a384052e73b2f6281ff7a700e9bf53bcce2ee579d4f6dd879/numpy-2.4.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d", size = 15729948, upload-time = "2026-03-29T13:21:14.047Z" }, + { url = "https://files.pythonhosted.org/packages/5f/86/2acbda8cc2af5f3d7bfc791192863b9e3e19674da7b5e533fded124d1299/numpy-2.4.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f", size = 16679325, upload-time = "2026-03-29T13:21:17.561Z" }, + { url = "https://files.pythonhosted.org/packages/bc/59/cafd83018f4aa55e0ac6fa92aa066c0a1877b77a615ceff1711c260ffae8/numpy-2.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0", size = 17084883, upload-time = "2026-03-29T13:21:21.106Z" }, + { url = "https://files.pythonhosted.org/packages/f0/85/a42548db84e65ece46ab2caea3d3f78b416a47af387fcbb47ec28e660dc2/numpy-2.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150", size = 18403474, upload-time = "2026-03-29T13:21:24.828Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ad/483d9e262f4b831000062e5d8a45e342166ec8aaa1195264982bca267e62/numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871", size = 6155500, upload-time = "2026-03-29T13:21:28.205Z" }, + { url = "https://files.pythonhosted.org/packages/c7/03/2fc4e14c7bd4ff2964b74ba90ecb8552540b6315f201df70f137faa5c589/numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e", size = 12637755, upload-time = "2026-03-29T13:21:31.107Z" }, + { url = "https://files.pythonhosted.org/packages/58/78/548fb8e07b1a341746bfbecb32f2c268470f45fa028aacdbd10d9bc73aab/numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7", size = 10566643, upload-time = "2026-03-29T13:21:34.339Z" }, + { url = "https://files.pythonhosted.org/packages/6b/33/8fae8f964a4f63ed528264ddf25d2b683d0b663e3cba26961eb838a7c1bd/numpy-2.4.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:58c8b5929fcb8287cbd6f0a3fae19c6e03a5c48402ae792962ac465224a629a4", size = 16854491, upload-time = "2026-03-29T13:21:38.03Z" }, + { url = "https://files.pythonhosted.org/packages/bc/d0/1aabee441380b981cf8cdda3ae7a46aa827d1b5a8cce84d14598bc94d6d9/numpy-2.4.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:eea7ac5d2dce4189771cedb559c738a71512768210dc4e4753b107a2048b3d0e", size = 14895830, upload-time = "2026-03-29T13:21:41.509Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b8/aafb0d1065416894fccf4df6b49ef22b8db045187949545bced89c034b8e/numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:51fc224f7ca4d92656d5a5eb315f12eb5fe2c97a66249aa7b5f562528a3be38c", size = 5400927, upload-time = "2026-03-29T13:21:44.747Z" }, + { url = "https://files.pythonhosted.org/packages/d6/77/063baa20b08b431038c7f9ff5435540c7b7265c78cf56012a483019ca72d/numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:28a650663f7314afc3e6ec620f44f333c386aad9f6fc472030865dc0ebb26ee3", size = 6715557, upload-time = "2026-03-29T13:21:47.406Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a8/379542d45a14f149444c5c4c4e7714707239ce9cc1de8c2803958889da14/numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19710a9ca9992d7174e9c52f643d4272dcd1558c5f7af7f6f8190f633bd651a7", size = 15804253, upload-time = "2026-03-29T13:21:50.753Z" }, + { url = "https://files.pythonhosted.org/packages/a2/c8/f0a45426d6d21e7ea3310a15cf90c43a14d9232c31a837702dba437f3373/numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b2aec6af35c113b05695ebb5749a787acd63cafc83086a05771d1e1cd1e555f", size = 16753552, upload-time = "2026-03-29T13:21:54.344Z" }, + { url = "https://files.pythonhosted.org/packages/04/74/f4c001f4714c3ad9ce037e18cf2b9c64871a84951eaa0baf683a9ca9301c/numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119", size = 12509075, upload-time = "2026-03-29T13:21:57.644Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.9.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394, upload-time = "2026-02-16T03:56:10.574Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.21.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/08/f1c908c581fd11913da4711ea7ba32c0eee40b0190000996bb863b0c9349/pymdown_extensions-10.21.2.tar.gz", hash = "sha256:c3f55a5b8a1d0edf6699e35dcbea71d978d34ff3fa79f3d807b8a5b3fa90fbdc", size = 853922, upload-time = "2026-03-29T15:01:55.233Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/27/a2fc51a4a122dfd1015e921ae9d22fee3d20b0b8080d9a704578bf9deece/pymdown_extensions-10.21.2-py3-none-any.whl", hash = "sha256:5c0fd2a2bea14eb39af8ff284f1066d898ab2187d81b889b75d46d4348c01638", size = 268901, upload-time = "2026-03-29T15:01:53.244Z" }, +] + +[[package]] +name = "pyswarm" +source = { editable = "." } +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] + +[package.dev-dependencies] +dev = [ + { name = "mkdocstrings", extra = ["python"] }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-xdist" }, + { name = "ruff" }, + { name = "zensical" }, +] +docs = [ + { name = "mkdocstrings", extra = ["python"] }, + { name = "zensical" }, +] +lint = [ + { name = "ruff" }, +] +test = [ + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-xdist" }, +] + +[package.metadata] +requires-dist = [{ name = "numpy" }] + +[package.metadata.requires-dev] +dev = [ + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.30.1" }, + { name = "pytest", specifier = ">=8.3.5" }, + { name = "pytest-cov", specifier = ">=7.0.0" }, + { name = "pytest-xdist", specifier = ">=3.6.1" }, + { name = "ruff", specifier = "==0.15.*" }, + { name = "zensical", specifier = ">=0.0.23" }, +] +docs = [ + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.30.1" }, + { name = "zensical", specifier = ">=0.0.23" }, +] +lint = [{ name = "ruff", specifier = "==0.15.*" }] +test = [ + { name = "pytest", specifier = ">=8.3.5" }, + { name = "pytest-cov", specifier = ">=7.0.0" }, + { name = "pytest-xdist", specifier = ">=3.6.1" }, +] + +[[package]] +name = "pytest" +version = "9.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/8d/192f3d7103816158dfd5ea50d098ef2aec19194e6cbccd4b3485bdb2eb2d/ruff-0.15.11.tar.gz", hash = "sha256:f092b21708bf0e7437ce9ada249dfe688ff9a0954fc94abab05dcea7dcd29c33", size = 4637264, upload-time = "2026-04-16T18:46:26.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/1e/6aca3427f751295ab011828e15e9bf452200ac74484f1db4be0197b8170b/ruff-0.15.11-py3-none-linux_armv6l.whl", hash = "sha256:e927cfff503135c558eb581a0c9792264aae9507904eb27809cdcff2f2c847b7", size = 10607943, upload-time = "2026-04-16T18:46:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/e7/26/1341c262e74f36d4e84f3d6f4df0ac68cd53331a66bfc5080daa17c84c0b/ruff-0.15.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7a1b5b2938d8f890b76084d4fa843604d787a912541eae85fd7e233398bbb73e", size = 10988592, upload-time = "2026-04-16T18:46:00.742Z" }, + { url = "https://files.pythonhosted.org/packages/03/71/850b1d6ffa9564fbb6740429bad53df1094082fe515c8c1e74b6d8d05f18/ruff-0.15.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d4176f3d194afbdaee6e41b9ccb1a2c287dba8700047df474abfbe773825d1cb", size = 10338501, upload-time = "2026-04-16T18:46:03.723Z" }, + { url = "https://files.pythonhosted.org/packages/f2/11/cc1284d3e298c45a817a6aadb6c3e1d70b45c9b36d8d9cce3387b495a03a/ruff-0.15.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b17c886fb88203ced3afe7f14e8d5ae96e9d2f4ccc0ee66aa19f2c2675a27e4", size = 10670693, upload-time = "2026-04-16T18:46:41.941Z" }, + { url = "https://files.pythonhosted.org/packages/ce/9e/f8288b034ab72b371513c13f9a41d9ba3effac54e24bfb467b007daee2ca/ruff-0.15.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:49fafa220220afe7758a487b048de4c8f9f767f37dfefad46b9dd06759d003eb", size = 10416177, upload-time = "2026-04-16T18:46:21.717Z" }, + { url = "https://files.pythonhosted.org/packages/85/71/504d79abfd3d92532ba6bbe3d1c19fada03e494332a59e37c7c2dabae427/ruff-0.15.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2ab8427e74a00d93b8bda1307b1e60970d40f304af38bccb218e056c220120d", size = 11221886, upload-time = "2026-04-16T18:46:15.086Z" }, + { url = "https://files.pythonhosted.org/packages/43/5a/947e6ab7a5ad603d65b474be15a4cbc6d29832db5d762cd142e4e3a74164/ruff-0.15.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:195072c0c8e1fc8f940652073df082e37a5d9cb43b4ab1e4d0566ab8977a13b7", size = 12075183, upload-time = "2026-04-16T18:46:07.944Z" }, + { url = "https://files.pythonhosted.org/packages/9f/a1/0b7bb6268775fdd3a0818aee8efd8f5b4e231d24dd4d528ced2534023182/ruff-0.15.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3a0996d486af3920dec930a2e7daed4847dfc12649b537a9335585ada163e9e", size = 11516575, upload-time = "2026-04-16T18:46:31.687Z" }, + { url = "https://files.pythonhosted.org/packages/30/c3/bb5168fc4d233cc06e95f482770d0f3c87945a0cd9f614b90ea8dc2f2833/ruff-0.15.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bef2cb556d509259f1fe440bb9cd33c756222cf0a7afe90d15edf0866702431", size = 11306537, upload-time = "2026-04-16T18:46:36.988Z" }, + { url = "https://files.pythonhosted.org/packages/e4/92/4cfae6441f3967317946f3b788136eecf093729b94d6561f963ed810c82e/ruff-0.15.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:030d921a836d7d4a12cf6e8d984a88b66094ccb0e0f17ddd55067c331191bf19", size = 11296813, upload-time = "2026-04-16T18:46:24.182Z" }, + { url = "https://files.pythonhosted.org/packages/43/26/972784c5dde8313acde8ac71ba8ac65475b85db4a2352a76c9934361f9bc/ruff-0.15.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0e783b599b4577788dbbb66b9addcef87e9a8832f4ce0c19e34bf55543a2f890", size = 10633136, upload-time = "2026-04-16T18:46:39.802Z" }, + { url = "https://files.pythonhosted.org/packages/5b/53/3985a4f185020c2f367f2e08a103032e12564829742a1b417980ce1514a0/ruff-0.15.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ae90592246625ba4a34349d68ec28d4400d75182b71baa196ddb9f82db025ef5", size = 10424701, upload-time = "2026-04-16T18:46:10.381Z" }, + { url = "https://files.pythonhosted.org/packages/d3/57/bf0dfb32241b56c83bb663a826133da4bf17f682ba8c096973065f6e6a68/ruff-0.15.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1f111d62e3c983ed20e0ca2e800f8d77433a5b1161947df99a5c2a3fb60514f0", size = 10873887, upload-time = "2026-04-16T18:46:29.157Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/e48076b2a57dc33ee8c7a957296f97c744ca891a8ffb4ffb1aaa3b3f517d/ruff-0.15.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:06f483d6646f59eaffba9ae30956370d3a886625f511a3108994000480621d1c", size = 11404316, upload-time = "2026-04-16T18:46:19.462Z" }, + { url = "https://files.pythonhosted.org/packages/88/27/0195d15fe7a897cbcba0904792c4b7c9fdd958456c3a17d2ea6093716a9a/ruff-0.15.11-py3-none-win32.whl", hash = "sha256:476a2aa56b7da0b73a3ee80b6b2f0e19cce544245479adde7baa65466664d5f3", size = 10655535, upload-time = "2026-04-16T18:46:12.47Z" }, + { url = "https://files.pythonhosted.org/packages/3a/5e/c927b325bd4c1d3620211a4b96f47864633199feed60fa936025ab27e090/ruff-0.15.11-py3-none-win_amd64.whl", hash = "sha256:8b6756d88d7e234fb0c98c91511aae3cd519d5e3ed271cae31b20f39cb2a12a3", size = 11779692, upload-time = "2026-04-16T18:46:17.268Z" }, + { url = "https://files.pythonhosted.org/packages/63/b6/aeadee5443e49baa2facd51131159fd6301cc4ccfc1541e4df7b021c37dd/ruff-0.15.11-py3-none-win_arm64.whl", hash = "sha256:063fed18cc1bbe0ee7393957284a6fe8b588c6a406a285af3ee3f46da2391ee4", size = 11032614, upload-time = "2026-04-16T18:46:34.487Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" }, + { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" }, + { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" }, + { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" }, + { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" }, + { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" }, + { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" }, + { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" }, + { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" }, + { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" }, + { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" }, + { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" }, + { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + +[[package]] +name = "zensical" +version = "0.0.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "deepmerge" }, + { name = "markdown" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "pyyaml" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/59/c2/dea4b86dc1ca2a7b55414017f12cfb12b5cfdf3a1ed7c77a04c271eb523b/zensical-0.0.33.tar.gz", hash = "sha256:05209cb4f80185c533e0d37c25d084ddc2050e3d5a4dd1b1812961c2ee0c3380", size = 3892278, upload-time = "2026-04-14T11:08:19.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/5f/45d5200405420a9d8ac91cf9e7826622ea12f3198e8e6ac4ffb481eb53bf/zensical-0.0.33-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f658e3c241cfbb560bd8811116a9486cff7e04d7d5aed73569dd533c74187450", size = 12416748, upload-time = "2026-04-14T11:07:43.246Z" }, + { url = "https://files.pythonhosted.org/packages/33/1e/aadaf31d6e4d20419ecedaf0b1c804e359ec23dcdb44c8d2bf6d8407080c/zensical-0.0.33-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f9813ac3256c28e2e2f1ba5c9fab1b4bca62bbe0e0f8e85ac22d33b068b1b08a", size = 12293372, upload-time = "2026-04-14T11:07:46.569Z" }, + { url = "https://files.pythonhosted.org/packages/db/e5/838be8451ea8b2aecec39fbec3971060fc705e17f5741249740d9b6a6824/zensical-0.0.33-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bad7ac71028769c5d1f3f84f448dbb7352db28d77095d1b40a8d1b0aa34ec30", size = 12659832, upload-time = "2026-04-14T11:07:50.754Z" }, + { url = "https://files.pythonhosted.org/packages/1e/5c/dd957d7c83efc13a70a6058d4190a3afcf29942aefb391120bca5466347d/zensical-0.0.33-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:06bb039daf044547c9400a52f9493b3cd486ba9baef3324fdcffd2e26e61105f", size = 12603847, upload-time = "2026-04-14T11:07:53.698Z" }, + { url = "https://files.pythonhosted.org/packages/b7/99/dd6ccc392ece1f34fb20ea339a01717badbbeb2fba1d4f3019a5028d0bcc/zensical-0.0.33-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:260238062b3139ece0edab93f4dbe7a12923453091f5aa580dfd73e799388076", size = 12956236, upload-time = "2026-04-14T11:07:56.728Z" }, + { url = "https://files.pythonhosted.org/packages/f4/76/e0a1b884eadf6afa7e2d56c90c268eec36836ac27e96ef250c0129e55417/zensical-0.0.33-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dff0f4afda7b8586bc4ab2a5684bce5b282232dd4e0cad3be4c73fedd264425", size = 12701944, upload-time = "2026-04-14T11:07:59.928Z" }, + { url = "https://files.pythonhosted.org/packages/38/38/e1ff13461e406864fa2b23fc828822659a7dbac5c79398f724d17f088540/zensical-0.0.33-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:207b4d81b208d75b97dc7bd318804550b886a3e852ef67429ef0e6b9442839d1", size = 12835444, upload-time = "2026-04-14T11:08:02.998Z" }, + { url = "https://files.pythonhosted.org/packages/41/04/7d24d52d6903fc5c511633afe8b5716fef19da09685327665cc127f61648/zensical-0.0.33-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:06d2f57f7bc8cc8fd904386020ea1365eebc411e8698a871e9525c885abca574", size = 12878419, upload-time = "2026-04-14T11:08:06.054Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ec/87fc9e360c694ab006363c7834639eccafd0d26a487cd63dd609bd68f36a/zensical-0.0.33-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:c2851b82d83aa0b2ae4f8e99731cfeedeecebfa04e6b3fc4d375deca629fa240", size = 13022474, upload-time = "2026-04-14T11:08:09.007Z" }, + { url = "https://files.pythonhosted.org/packages/10/b3/0bf174ab6ceedb31d9af462073b5339c894b2084a27d42cb9f0906050d76/zensical-0.0.33-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:90daaf512b0429d7b9147ad5e6085b455d24803eff18b508aed738ca65444683", size = 12975233, upload-time = "2026-04-14T11:08:12.535Z" }, + { url = "https://files.pythonhosted.org/packages/a9/27/7cc3c2d284698647f60f3b823e0101e619c87edf158d47ee11bf4bfb6228/zensical-0.0.33-cp310-abi3-win32.whl", hash = "sha256:2701820597fe19361a12371129927c58c19633dcaa5f6986d610dce58cecd8c4", size = 12012664, upload-time = "2026-04-14T11:08:14.977Z" }, + { url = "https://files.pythonhosted.org/packages/25/0b/6be5c2fdaf9f1600577e7ba5e235d86b72a26f6af389efb146f978f76ac3/zensical-0.0.33-cp310-abi3-win_amd64.whl", hash = "sha256:a5a0911b4247708a55951b74c459f4d5faec5daaf287d23a2e1f0d96be1e647f", size = 12206255, upload-time = "2026-04-14T11:08:17.375Z" }, +] From 82d9d145242ac79a5d09d6924273b91d3e151202 Mon Sep 17 00:00:00 2001 From: saudzahirr Date: Sat, 18 Apr 2026 17:55:50 +0500 Subject: [PATCH 2/2] Add seed parameter to PSO function for reproducibility --- pyswarm/pso.py | 14 ++++++++++---- tests/test_twobar_truss.py | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pyswarm/pso.py b/pyswarm/pso.py index 553bc5f..8479607 100644 --- a/pyswarm/pso.py +++ b/pyswarm/pso.py @@ -51,6 +51,7 @@ def pso( # noqa: PLR0913, PLR0917, PLR0912, PLR0915, PLR0914 debug: bool = False, # noqa: FBT001, FBT002 processes: int = 1, particle_output: bool = False, # noqa: FBT001, FBT002 + seed: int | None = None, ) -> ( tuple[np.ndarray, float] | tuple[np.ndarray, float, np.ndarray, np.ndarray] ): @@ -83,6 +84,9 @@ def pso( # noqa: PLR0913, PLR0917, PLR0912, PLR0915, PLR0914 functions (Default: empty dict) swarmsize : int The number of particles in the swarm (Default: 100) + seed : int, optional + Seed for the random number generator used by particles and velocity + updates. Use ``None`` for nondeterministic behavior (Default: None). omega : scalar Particle velocity scaling factor (Default: 0.5) phip : scalar @@ -148,6 +152,8 @@ def pso( # noqa: PLR0913, PLR0917, PLR0912, PLR0915, PLR0914 vhigh = np.abs(ub - lb) vlow = -vhigh + rng = np.random.default_rng(seed) + # Initialize objective function obj = partial(_obj_wrapper, func, args, kwargs) @@ -175,7 +181,7 @@ def pso( # noqa: PLR0913, PLR0917, PLR0912, PLR0915, PLR0914 # Initialize the particle swarm ############################################ swarm_size = swarmsize num_dims = len(lb) # the number of dimensions each particle has - x = np.random.rand(swarm_size, num_dims) # particle positions + x = rng.random((swarm_size, num_dims)) # particle positions v = np.zeros_like(x) # particle velocities p = np.zeros_like(x) # best particle positions fx = np.zeros(swarm_size) # current particle function values @@ -212,13 +218,13 @@ def pso( # noqa: PLR0913, PLR0917, PLR0912, PLR0915, PLR0914 g = x[0, :].copy() # Initialize the particle's velocity - v = vlow + np.random.rand(swarm_size, num_dims) * (vhigh - vlow) + v = rng.uniform(vlow, vhigh, size=(swarm_size, num_dims)) # Iterate until termination criterion met ################################## it = 1 while it <= maxiter: - rp = np.random.uniform(size=(swarm_size, num_dims)) - rg = np.random.uniform(size=(swarm_size, num_dims)) + rp = rng.uniform(size=(swarm_size, num_dims)) + rg = rng.uniform(size=(swarm_size, num_dims)) # Update the particles velocities v = omega * v + phip * rp * (p - x) + phig * rg * (g - x) diff --git a/tests/test_twobar_truss.py b/tests/test_twobar_truss.py index 773ba77..1f3aa9e 100644 --- a/tests/test_twobar_truss.py +++ b/tests/test_twobar_truss.py @@ -55,6 +55,7 @@ def test_twobar_truss() -> None: args=args, maxiter=100, debug=True, + seed=0, ) if not np.isclose(fopt, 11.94, atol=0.1): msg = f"Expected fopt close to 11.94, got {fopt}"