diff --git a/.dockerignore b/.dockerignore
index a1b797f..41ec0d7 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,26 +1,34 @@
+.git/
.github/
-.venv/
.vscode/
.idea/
+
+.venv/
+__pycache__/
+*.py[cod]
+*.egg-info/
+
+.pytest_cache/
+.mypy_cache/
+.ruff_cache/
+.coverage
+.coverage.*
+htmlcov/
+test-results.xml
+
ci/
doc/
-gurobi/
-htmlcov/
local_test/
-*.egg-info/
-unit_test/
+tests/
+gurobi/
+
.env
-.env.local
-.env.template
-.gitignore
-.taplo.toml
+.env.*
+
CHANGELOG.md
CONTRIBUTING.md
-dev.Dockerfile
-docker-compose.worker-only.yml
-docker-compose.yml
LICENSE
run.bat
run.sh
run_windows.sh
-test-results.xml
+dev.Dockerfile
diff --git a/.env.template b/.env.template
index 14f4455..35bf500 100644
--- a/.env.template
+++ b/.env.template
@@ -1,22 +1,32 @@
-ESDL_OUTPUT_PROFILES_TYPE=POSTGRESQL
+LOG_LEVEL=INFO
+ESDL_OUTPUT_PROFILES_TYPE=POSTGRESQL
DB_HOSTNAME=omotes_postgres
DB_PORT=6432
DB_USERNAME=omotes_timeseries_rw
DB_PASSWORD=somepass4
-RABBITMQ_USERNAME=celery
-RABBITMQ_PASSWORD=somepass2
-RABBITMQ_HOSTNAME=localhost
-RABBITMQ_PORT=5672
-RABBITMQ_VIRTUALHOST=omotes_celery
+# ESDL_OUTPUT_PROFILES_TYPE=INFLUXDB
+# DB_HOSTNAME=omotes_influxdb
+# DB_PORT=8096
+# DB_USERNAME=root
+# DB_PASSWORD=9012
-# May be grow_optimizer_default, grow_optimizer_no_heat_losses, grow_optimizer_with_pressure or grow_simulator
-GROW_TASK_TYPE=grow_optimizer_default
-LOG_LEVEL=INFO
+MINIO_HOST=minio:9000
+MINIO_EXTERNAL_HOST=minio:9000
+MINIO_ACCESS_KEY=omotesadmin
+MINIO_SECRET=password
+
+PREFECT_API_URL=http://localhost:4200/api
+PREFECT_API_URL_FOR_WORKER=http://prefect-server:4200/api
+PREFECT_WORK_POOL_NAME="docker-worker"
+PREFECT_API_AUTH_STRING=admin:password
-TASK_RESULT_QUEUE_NAME=omotes_task_result_events
-TASK_PROGRESS_QUEUE_NAME=omotes_task_progress_events
+PREFECT_FLOW_MAX_CONCURRENT_RUNS=4
-# MAX_TASKS_BEFORE_RESTART: 0 means no scheduled restarts
-MAX_TASKS_BEFORE_RESTART=0
+# For deploying to prefect (will run inside local docker container or k8s pod)
+# When using docker desktop you can use your local code without pushing to gitlab first:
+PREFECT_USE_LOCAL_CODE_AND_IMAGE=false
+PREFECT_USE_LOCAL_SDK_AND_MESIDO=false
+# OPTIMIZER_WORKER_VERSION not used when PREFECT_USE_LOCAL_CODE_AND_IMAGE=true:
+OPTIMIZER_WORKER_VERSION=3.0.0
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ac5d42f..16c4167 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,45 +6,41 @@ jobs:
lint:
name: Lint
runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version: [ "3.10" ]
steps:
- - uses: actions/checkout@v3
- - name: setup python
+ - uses: actions/checkout@v4
+ - name: Set up Python
uses: actions/setup-python@v4
with:
- python-version: ${{ matrix.python-version }}
- cache: pip
- - name: create and activate venv
- run: |
- ./ci/linux/create_venv.sh
- ./ci/linux/install_dependencies.sh
- - name: run lint
- run: |
- ./ci/linux/lint.sh
+ python-version: "3.10"
+ - name: Install uv
+ uses: astral-sh/setup-uv@v2
+ - name: Install just
+ uses: taiki-e/install-action@just
+ - name: Install dependencies
+ run: just install
+ - name: Run linter
+ run: just lint
+ - name: Check formatting
+ run: just format-check
test:
- name: Unit Tests
+ name: Test
runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version: [ "3.10" ]
steps:
- - uses: actions/checkout@v3
- - name: setup python
+ - uses: actions/checkout@v4
+ - name: Set up Python
uses: actions/setup-python@v4
with:
- python-version: ${{ matrix.python-version }}
- cache: pip
- - name: create and activate venv
- run: |
- ./ci/linux/create_venv.sh
- ./ci/linux/install_dependencies.sh
- - name: run unit tests
- run: |
- ./ci/linux/test_unit.sh
- - name: surface failing tests
+ python-version: "3.10"
+ - name: Install uv
+ uses: astral-sh/setup-uv@v2
+ - name: Install just
+ uses: taiki-e/install-action@just
+ - name: Install dependencies
+ run: just install
+ - name: Run unit tests
+ run: just test
+ - name: Publish test results
if: always()
uses: pmeier/pytest-results-action@main
with:
@@ -54,22 +50,19 @@ jobs:
fail-on-empty: true
typecheck:
- name: Typecheck
+ name: Type Check
runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version: [ "3.10" ]
steps:
- - uses: actions/checkout@v3
- - name: setup python
+ - uses: actions/checkout@v4
+ - name: Set up Python
uses: actions/setup-python@v4
with:
- python-version: ${{ matrix.python-version }}
- cache: pip
- - name: create and activate venv
- run: |
- ./ci/linux/create_venv.sh
- ./ci/linux/install_dependencies.sh
- - name: run typechecker
- run: |
- ./ci/linux/typecheck.sh
\ No newline at end of file
+ python-version: "3.10"
+ - name: Install uv
+ uses: astral-sh/setup-uv@v2
+ - name: Install just
+ uses: taiki-e/install-action@just
+ - name: Install dependencies
+ run: just install
+ - name: Run type checker
+ run: just typecheck
\ No newline at end of file
diff --git a/.github/workflows/publish_container_image.yml b/.github/workflows/publish_container_image.yml
index d366636..8e461ad 100644
--- a/.github/workflows/publish_container_image.yml
+++ b/.github/workflows/publish_container_image.yml
@@ -1,28 +1,48 @@
-name: Deply to GitHub Container Registry
+name: Publish Container Image
+run-name: Releasing next version 🚀
+
on:
push:
tags:
- - '*'
+ - "*"
jobs:
- publish-container-image:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v3
- with:
- fetch-depth: 0
+ publish-container-image:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - name: Checkout sources
+ uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
- - name: Login to GitHub Container Registry
- uses: docker/login-action@v1
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Extract Docker metadata
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ghcr.io/project-omotes/omotes-optimizer
+ tags: |
+ type=raw,value=latest
+ type=raw,value=${{ github.ref_name }}
- - name: Build the container image
- run: |
- docker build . --tag ghcr.io/project-omotes/omotes-grow-optimizer-worker:latest --tag ghcr.io/project-omotes/omotes-grow-optimizer-worker:${{ github.ref_name}}
- docker push ghcr.io/project-omotes/omotes-grow-optimizer-worker:latest
- docker push ghcr.io/project-omotes/omotes-grow-optimizer-worker:${{ github.ref_name}}
+ - name: Build and push container image
+ uses: docker/build-push-action@v6
+ with:
+ context: .
+ file: ./Dockerfile
+ push: true
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
diff --git a/.gitignore b/.gitignore
index 48f5126..efae4e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,226 +1,48 @@
-# Byte-compiled / optimized / DLL files
+# Byte-compiled / optimized files
__pycache__/
*.py[cod]
*$py.class
-# C extensions
+# Native extensions
*.so
-# Distribution / packaging
-.Python
+ # Build / packaging artifacts
build/
-develop-eggs/
dist/
-downloads/
-eggs/
+*.egg-info/
.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
pip-wheel-metadata/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
*.egg
-MANIFEST
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
+# Virtual environments
+.venv/
+venv/
+env/
+ENV/
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
+# Local environment files
+.env
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
+# Test / coverage artifacts
+.pytest_cache/
.coverage
.coverage.*
-.cache
-nosetests.xml
+htmlcov/
coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-doc/*/_build/
-doc/*/_static/
-doc/*/_templates/
-
-# PyBuilder
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-.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
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
+test-results.xml
+unit_test_coverage/
-# mypy
+# Type checker / linter caches
.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
+.ruff_cache/
.pyre/
-### PyCharm+all ###
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
-# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
-
-# User-specific stuff
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
-# AWS User-specific
-.idea/**/aws.xml
-
-# Generated files
-.idea/**/contentModel.xml
-
-# Sensitive or high-churn files
-.idea/**/dataSources/
-.idea/**/dataSources.ids
-.idea/**/dataSources.local.xml
-.idea/**/sqlDataSources.xml
-.idea/**/dynamic.xml
-.idea/**/uiDesigner.xml
-.idea/**/dbnavigator.xml
-
-# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
-
-# Gradle and Maven with auto-import
-# When using Gradle or Maven with auto-import, you should exclude module files,
-# since they will be recreated, and may cause churn. Uncomment if using
-# auto-import.
-# .idea/artifacts
-# .idea/compiler.xml
-# .idea/jarRepositories.xml
-# .idea/modules.xml
-# .idea/*.iml
-# .idea/modules
-# *.iml
-# *.ipr
-
-# CMake
-cmake-build-*/
-
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
-
-# File-based project format
-*.iws
-
-# IntelliJ
-out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Cursive Clojure plugin
-.idea/replstate.xml
-
-# SonarLint plugin
-.idea/sonarlint/
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
-
-# Editor-based Rest Client
-.idea/httpRequests
-
-# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
-
-### PyCharm+all Patch ###
-# Ignore everything but code style settings and run configurations
-# that are supposed to be shared within teams.
-
-.idea/*
+# Editor / IDE
+.idea/
-!.idea/codeStyles
-!.idea/runConfigurations
-
-unit_test_coverage/
-test-results.xml
+# Notebook checkpoints
+.ipynb_checkpoints/
+# Misc local output
temp/
gurobi/
-.idea/
diff --git a/.taplo.toml b/.taplo.toml
deleted file mode 100644
index 66d8049..0000000
--- a/.taplo.toml
+++ /dev/null
@@ -1,5 +0,0 @@
-include = ["pyproject.toml"]
-
-
-[schema]
-path = "https://json.schemastore.org/pyproject.json"
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 00aff4e..a6cab56 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -2,17 +2,43 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Run worker.py",
+ "name": "prefect_deploy_flow",
"type": "debugpy",
"request": "launch",
- "program": "${workspaceFolder}/src/grow_worker/worker.py",
+ "program": "${workspaceFolder}/src/omotes_optimizer_worker/prefect_deploy_flow.py",
+ "cwd": "${workspaceFolder}/src",
"console": "integratedTerminal",
+ "env": {
+ "PYTHONPATH": "${workspaceFolder}/src"
+ },
+ "envFile": "${workspaceFolder}/.env"
+ },
+ {
+ "name": "run_optimizer_flow_function",
+ "type": "debugpy",
+ "request": "launch",
+ "program": "${workspaceFolder}/local_test/run_optimizer_flow_function.py",
"cwd": "${workspaceFolder}",
- "justMyCode": true,
+ "console": "integratedTerminal",
"env": {
"PYTHONPATH": "${workspaceFolder}/src"
},
"envFile": "${workspaceFolder}/.env"
+ },
+ {
+ "name": "pytest",
+ "type": "debugpy",
+ "request": "launch",
+ "module": "pytest",
+ "args": [
+ "tests",
+ "-q"
+ ],
+ "env": {
+ "PYTHONPATH": "${workspaceFolder}/src"
+ },
+ "console": "integratedTerminal",
+ "justMyCode": false
}
]
}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 9d29e7e..c459c01 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,24 +1,23 @@
{
"flake8.enabled": false,
"[python]": {
- "editor.formatOnSave": true,
- "editor.defaultFormatter": "ms-python.black-formatter",
+ "editor.defaultFormatter": "charliermarsh.ruff",
"editor.codeActionsOnSave": {
- "source.organizeImports": "explicit"
- },
+ "source.fixAll.ruff": "always",
+ "source.organizeImports.ruff": "explicit"
+ }
},
"python.analysis.typeCheckingMode": "basic",
"python.testing.unittestArgs": [
"-v",
"-s",
- "./unit_test",
+ "./tests",
"-p",
"test_*.py"
],
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.testing.autoTestDiscoverOnSaveEnabled": true,
- "mypy.runUsingActiveInterpreter": true,
"isort.args": [
"--profile",
"black"
@@ -26,4 +25,18 @@
"terminal.integrated.env.windows": {
"PYTHONPATH": "${workspaceFolder}/src"
},
+ "python.languageServer": "None", // disable Pylance (ruff/ty is used)
+ "ty.diagnosticMode": "workspace",
+ "ty.importStrategy": "fromEnvironment",
+ "ty.interpreter": "${workspaceFolder}/.venv/bin/python",
+ "ruff.organizeImports": true,
+ "ruff.lint.enable": true,
+ "[just]": {
+ "editor.formatOnSave": false,
+ "editor.defaultFormatter": null
+ },
+ "files.associations": {
+ "justfile": "just",
+ "*.just": "just"
+ }
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 149a75c..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Changelog
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [Unreleased] - 2024-3-31
-### Added
-- New functionality added to the project, with reference to issue-ticket (#123)
-- Another new item (#1234)
-
-### Fixed
-- bugfixes, with references to your issue-tickets (#123)
-- another bugfix (#1234)
-
-### Changed
-- Changes, for example code structure
-- but also changed/updated dependencies
-- Add references to tickets where applicable (#123)
-
-### Removed
-- Files that have been removed
-- Functionality that has been removed
-- Add references to tickets where applicable (#123)
-
-## [0.0.1] - 2023-09-21
-### Added
-- Kickoff of Nieuwe Warmte Nu!.
-- initialized repo from template.
-
-### Changed
-- everything.
diff --git a/Dockerfile b/Dockerfile
index c6652ef..688ebb9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM python:3.10-slim-bookworm
+FROM python:3.11-slim-bookworm
WORKDIR /app
RUN apt update && \
@@ -18,13 +18,21 @@ ENV GUROBI_VERSION="$CASADI_GUROBI_VERSION"
# This env var is for gurobi
ENV GRB_LICENSE_FILE="/app/gurobi/gurobi.lic"
-
RUN mkdir -p /app/gurobi && \
wget -qO- https://packages.gurobi.com/${GUROBI_VERSION_URL_MAJOR}/gurobi${GUROBI_VERSION_URL}_linux64.tar.gz | tar xvz --strip-components=2 -C /app/gurobi
-COPY requirements.txt /app/grow_worker/requirements.txt
-RUN pip install -r /app/grow_worker/requirements.txt --no-cache-dir
+# install uv
+COPY --from=ghcr.io/astral-sh/uv:0.8.22 /uv /uvx /bin/
+
+WORKDIR /src
-COPY src/grow_worker /app/grow_worker/
+# install dependencies, avoid using Gurobi's embedded python
+ENV UV_PYTHON=/usr/local/bin/python3.11
+RUN --mount=type=cache,target=/root/.cache/uv \
+ --mount=type=bind,source=uv.lock,target=uv.lock \
+ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
+ uv sync --locked --no-install-project --no-dev
+# enable running commands without 'uv run'
+ENV PATH="/src/.venv/bin:$PATH"
-CMD ["python3", "-m", "grow_worker.worker"]
+COPY src .
diff --git a/README.md b/README.md
index dde100b..36d3e31 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,83 @@
# Optimizer worker
-to test locally run:
-```
-docker-compose up
+Prefect flow repo for the NWN optimizer.\
+This defines the prefect flow function which is the entry function for prefect runs.\
+There is a `prefect_deploy_flow` script to create/update a prefect deployment which can be used for runs.
+
+## Development
+
+### Tools
+
+This project uses:
+
+- **uv**: Fast Python package manager and resolver. Install via [https://docs.astral.sh/uv/](https://docs.astral.sh/uv/)
+- **just**: Command runner for common tasks (similar to Make). Install via [https://github.com/casey/just](https://github.com/casey/just)
+
+### Setup
+
+1. Install dependencies:
+
+ ```bash
+ uv sync
+ ```
+
+2. Copy `.env.template` to `.env`
+
+**Note** to use local code for sdk run `.venv/bin/pip install -e ../omotes-sdk-python/`.
+
+### Run/debug the prefect flow function locally
+
+In vscode go to the debug view and run `run_optimizer_flow_function`. This runs the function without prefect.
+
+### Lint/typecheck/test locally
+
+Run via just (also used in in github actions):
+
+```bash
+just ci # run all CI checks (lint, format-check, typecheck, test)
+
+just lint # ruff checks
+just format # ruff format
+just format-check # verify formatting
+just typecheck # ty type checking
+just test # pytest
```
-The local_test service can be run multiple times.
-The result exit code is printed in each `local_test` test app output.
-For testing during development keep `rabbitmq` and `omotes_influxdd` running and run:
+To debug test go to the debug view in vscode and run "pytest".\
+When using an editable install of the sdk, don't use the just command as `uv run ...` will remove this editable install.
+
+### Deploy flow to prefect
+
+In vscode go to the debug view and run `prefect_deploy_flow`.\
+This will create a deployment on prefect (to the prefect instance on `PREFECT_API_URL`).\
+
+During development you may want to deploy local code of this repo instead of an already published image, then set `PREFECT_USE_LOCAL_CODE_AND_IMAGE=true` in `.env`.
+To also use local code for the omoted-sdk-python and mesido set `PREFECT_USE_LOCAL_SDK_AND_MESIDO=true` as well.
+
+## Project Structure
+
+```text
+optimizer-worker/
+├── src/
+│ └── omotes_optimizer_worker/
+│ ├── __init__.py # Package initialization
+│ ├── env.py # Environment configuration helpers
+│ ├── prefect_deploy_flow.py # Registers/updates Prefect deployment
+│ ├── prefect_flow.py # Main Prefect flow implementation
+│ └── worker_types.py # Workflow/solver mapping utilities
+├── tests/
+│ ├── test_prefect_deploy_flow.py # Tests for deploy flow module behavior
+│ └── test_worker_types.py # Tests for worker type mapping logic
+├── local_test/
+│ ├── Delft_T.esdl # Local test input ESDL
+│ ├── Delft_T feedback.esdl # Local test output/feedback ESDL
+│ └── run_optimizer_flow_function.py # Run flow function locally without Prefect
+├── doc/ # Project documentation assets
+├── gurobi/
+│ └── gurobi.lic # Local Gurobi license file
+├── Dockerfile # Runtime image for optimizer worker
+├── dev.Dockerfile # Local development image (monorepo/local SDK mode)
+├── justfile # Task runner commands (ci, lint, typecheck, test)
+├── pyproject.toml # Dependencies and project metadata
+└── README.md
```
-docker-compose up --build grow_worker local_test
-```
\ No newline at end of file
diff --git a/ci/linux/_load_dot_env.sh b/ci/linux/_load_dot_env.sh
deleted file mode 100755
index 434c067..0000000
--- a/ci/linux/_load_dot_env.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
-set -a
-source $1
-set +a
diff --git a/ci/linux/create_venv.sh b/ci/linux/create_venv.sh
deleted file mode 100755
index 13ffbc9..0000000
--- a/ci/linux/create_venv.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-python3.10 -m venv ./.venv
-if [[ "$OSTYPE" != "win32" && "$OSTYPE" != "msys" ]]; then
- echo "Activating .venv first."
- . .venv/bin/activate
-fi
-pip3 install pip-tools
diff --git a/ci/linux/install_dependencies.sh b/ci/linux/install_dependencies.sh
deleted file mode 100755
index e00b897..0000000
--- a/ci/linux/install_dependencies.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ "$OSTYPE" != "win32" && "$OSTYPE" != "msys" ]]; then
- echo "Activating .venv first."
- . .venv/bin/activate
-fi
-
-pip-sync ./dev-requirements.txt ./requirements.txt
diff --git a/ci/linux/lint.sh b/ci/linux/lint.sh
deleted file mode 100755
index a07472f..0000000
--- a/ci/linux/lint.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ "$OSTYPE" != "win32" && "$OSTYPE" != "msys" ]]; then
- echo "Activating .venv first."
- . .venv/bin/activate
-fi
-
-flake8 ./src/grow_worker ./unit_test/
diff --git a/ci/linux/test_unit.sh b/ci/linux/test_unit.sh
deleted file mode 100755
index bff0c15..0000000
--- a/ci/linux/test_unit.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ "$OSTYPE" != "win32" && "$OSTYPE" != "msys" ]]; then
- echo "Activating .venv first."
- . .venv/bin/activate
-fi
-
-PYTHONPATH='$PYTHONPATH:src/' pytest --junit-xml=test-results.xml unit_test/
diff --git a/ci/linux/typecheck.sh b/ci/linux/typecheck.sh
deleted file mode 100755
index 70fb623..0000000
--- a/ci/linux/typecheck.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ "$OSTYPE" != "win32" && "$OSTYPE" != "msys" ]]; then
- echo "Activating .venv first."
- . .venv/bin/activate
-fi
-
-python -m mypy ./src/grow_worker ./unit_test/
diff --git a/ci/linux/update_dependencies.sh b/ci/linux/update_dependencies.sh
deleted file mode 100755
index fea6566..0000000
--- a/ci/linux/update_dependencies.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ "$OSTYPE" != "win32" && "$OSTYPE" != "msys" ]]; then
- echo "Activating .venv first."
- . .venv/bin/activate
-fi
-
-pip-compile --upgrade --output-file=requirements.txt pyproject.toml
-pip-compile --upgrade --extra=dev -c requirements.txt --output-file=dev-requirements.txt pyproject.toml
diff --git a/ci/win32/create_venv.cmd b/ci/win32/create_venv.cmd
deleted file mode 100644
index 3cd00af..0000000
--- a/ci/win32/create_venv.cmd
+++ /dev/null
@@ -1,9 +0,0 @@
-rem Short script to initialize virtual environment using venv and pip
-rem @echo off
-
-pushd .
-cd /D "%~dp0"
-py -3.10 -m venv ..\..\venv
-call ..\..\venv\Scripts\activate.bat
-python -m pip install pip-tools
-popd
diff --git a/ci/win32/install_dependencies.cmd b/ci/win32/install_dependencies.cmd
deleted file mode 100644
index e76c29d..0000000
--- a/ci/win32/install_dependencies.cmd
+++ /dev/null
@@ -1,6 +0,0 @@
-
-pushd .
-cd /D "%~dp0"
-cd ..\..\
-pip-sync .\dev-requirements.txt .\requirements.txt
-popd
\ No newline at end of file
diff --git a/ci/win32/lint.cmd b/ci/win32/lint.cmd
deleted file mode 100644
index 061804d..0000000
--- a/ci/win32/lint.cmd
+++ /dev/null
@@ -1,8 +0,0 @@
-rem Short script to run linting
-rem @echo off
-
-pushd .
-cd /D "%~dp0"
-cd ..\..\
-flake8 .\src\grow_worker
-popd
diff --git a/ci/win32/test_unit.cmd b/ci/win32/test_unit.cmd
deleted file mode 100644
index c2d51b8..0000000
--- a/ci/win32/test_unit.cmd
+++ /dev/null
@@ -1,9 +0,0 @@
-
-pushd .
-cd /D "%~dp0"
-
-cd ..\..\
-call .\venv\Scripts\activate
-set PYTHONPATH=.\src\;%$PYTHONPATH%
-pytest unit_test/
-popd
\ No newline at end of file
diff --git a/ci/win32/typecheck.cmd b/ci/win32/typecheck.cmd
deleted file mode 100644
index cd5d30f..0000000
--- a/ci/win32/typecheck.cmd
+++ /dev/null
@@ -1,8 +0,0 @@
-REM script to run mypy type checker on this source tree.
-pushd .
-cd /D "%~dp0"
-cd ..\..\
-call .\venv\Scripts\activate
-set PYTHONPATH=.\src\grow_worker;%$PYTHONPATH%
-python -m mypy ./src/grow_worker ./unit_test/
-popd
\ No newline at end of file
diff --git a/ci/win32/update_dependencies.cmd b/ci/win32/update_dependencies.cmd
deleted file mode 100644
index b76748f..0000000
--- a/ci/win32/update_dependencies.cmd
+++ /dev/null
@@ -1,6 +0,0 @@
-
-pushd .
-cd /D "%~dp0"
-pip-compile --output-file=..\..\requirements.txt ..\..\pyproject.toml
-pip-compile --extra=dev --output-file=..\..\dev-requirements.txt -c requirements.txt ..\..\pyproject.toml
-popd
\ No newline at end of file
diff --git a/dev-requirements.txt b/dev-requirements.txt
deleted file mode 100644
index 990ec4e..0000000
--- a/dev-requirements.txt
+++ /dev/null
@@ -1,355 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.10
-# by the following command:
-#
-# pip-compile --constraint=requirements.txt --extra=dev --output-file=dev-requirements.txt pyproject.toml
-#
-aio-pika==9.4.3
- # via
- # -c requirements.txt
- # omotes-sdk-python
-aiormq==6.8.1
- # via
- # -c requirements.txt
- # aio-pika
-amqp==5.3.1
- # via
- # -c requirements.txt
- # kombu
-antlr4-python3-runtime==4.13.2
- # via
- # -c requirements.txt
- # pymoca
-attrs==26.1.0
- # via flake8-bugbear
-billiard==4.2.4
- # via
- # -c requirements.txt
- # celery
-black==24.10.0
- # via omotes-grow-worker (pyproject.toml)
-build==1.2.2.post1
- # via omotes-grow-worker (pyproject.toml)
-casadi-gil-comp==3.6.7
- # via
- # -c requirements.txt
- # mesido
- # rtc-tools-gil-comp
-celery==5.6.3
- # via
- # -c requirements.txt
- # omotes-sdk-python
-certifi==2026.6.17
- # via
- # -c requirements.txt
- # requests
-charset-normalizer==3.4.9
- # via
- # -c requirements.txt
- # requests
-click==8.4.2
- # via
- # -c requirements.txt
- # black
- # celery
- # click-didyoumean
- # click-plugins
- # click-repl
-click-didyoumean==0.3.1
- # via
- # -c requirements.txt
- # celery
-click-plugins==1.1.1.2
- # via
- # -c requirements.txt
- # celery
-click-repl==0.3.0
- # via
- # -c requirements.txt
- # celery
-coolprop==6.6.0
- # via
- # -c requirements.txt
- # mesido
-coverage[toml]==7.15.2
- # via pytest-cov
-defusedxml==0.7.1
- # via
- # -c requirements.txt
- # rtc-tools-gil-comp
-et-xmlfile==2.0.0
- # via
- # -c requirements.txt
- # openpyxl
-exceptiongroup==1.3.1
- # via
- # -c requirements.txt
- # celery
- # pytest
-flake8==7.1.1
- # via
- # flake8-bugbear
- # flake8-docstrings
- # flake8-pyproject
- # flake8-quotes
- # flake8-tuple
- # omotes-grow-worker (pyproject.toml)
-flake8-bugbear==24.10.31
- # via omotes-grow-worker (pyproject.toml)
-flake8-docstrings==1.7.0
- # via omotes-grow-worker (pyproject.toml)
-flake8-mock==0.4
- # via omotes-grow-worker (pyproject.toml)
-flake8-pyproject==1.2.4
- # via omotes-grow-worker (pyproject.toml)
-flake8-quotes==3.4.0
- # via omotes-grow-worker (pyproject.toml)
-flake8-tuple==0.4.1
- # via omotes-grow-worker (pyproject.toml)
-future-fstrings==1.2.0
- # via
- # -c requirements.txt
- # pyecore
-idna==3.18
- # via
- # -c requirements.txt
- # requests
- # yarl
-influxdb==5.3.1
- # via
- # -c requirements.txt
- # mesido
- # pyesdl
-iniconfig==2.3.0
- # via pytest
-isort==5.13.2
- # via omotes-grow-worker (pyproject.toml)
-kombu==5.6.2
- # via
- # -c requirements.txt
- # celery
-lxml==6.1.1
- # via
- # -c requirements.txt
- # pyecore
-mccabe==0.7.0
- # via flake8
-mesido==0.1.20.3
- # via
- # -c requirements.txt
- # omotes-grow-worker (pyproject.toml)
-msgpack==1.2.1
- # via
- # -c requirements.txt
- # influxdb
-multidict==6.7.1
- # via
- # -c requirements.txt
- # yarl
-mypy==1.13.0
- # via omotes-grow-worker (pyproject.toml)
-mypy-extensions==1.1.0
- # via
- # black
- # mypy
-numpy==1.25.2
- # via
- # -c requirements.txt
- # casadi-gil-comp
- # pandas
- # pymoca
- # rtc-tools-gil-comp
- # scipy
-omotes-sdk-protocol==1.2.0
- # via
- # -c requirements.txt
- # omotes-sdk-python
-omotes-sdk-python==4.3.6
- # via
- # -c requirements.txt
- # omotes-grow-worker (pyproject.toml)
-openpyxl==3.1.2
- # via
- # -c requirements.txt
- # pyesdl
-ordered-set==4.1.0
- # via
- # -c requirements.txt
- # pyecore
-packaging==26.2
- # via
- # -c requirements.txt
- # black
- # build
- # kombu
- # pytest
- # setuptools-git-versioning
-pamqp==3.3.0
- # via
- # -c requirements.txt
- # aiormq
- # omotes-sdk-python
-pandas==1.5.3
- # via
- # -c requirements.txt
- # mesido
-pathspec==1.1.1
- # via black
-platformdirs==4.10.0
- # via black
-pluggy==1.6.0
- # via pytest
-prompt-toolkit==3.0.52
- # via
- # -c requirements.txt
- # click-repl
-propcache==0.5.2
- # via
- # -c requirements.txt
- # yarl
-protobuf==5.29.6
- # via
- # -c requirements.txt
- # omotes-sdk-protocol
-psycopg[binary]==3.3.3
- # via
- # -c requirements.txt
- # pyesdl
-psycopg-binary==3.3.3
- # via
- # -c requirements.txt
- # psycopg
- # pyesdl
-pycodestyle==2.12.1
- # via flake8
-pydocstyle==6.3.0
- # via flake8-docstrings
-pyecore==0.13.2
- # via
- # -c requirements.txt
- # mesido
- # pyesdl
-pyesdl[profiles]==26.7
- # via
- # -c requirements.txt
- # mesido
- # omotes-sdk-python
-pyflakes==3.2.0
- # via flake8
-pymoca==0.9.2
- # via
- # -c requirements.txt
- # mesido
- # rtc-tools-channel-flow
- # rtc-tools-gil-comp
-pyproject-hooks==1.2.0
- # via build
-pytest==8.3.5
- # via
- # omotes-grow-worker (pyproject.toml)
- # pytest-cov
-pytest-cov==6.0.0
- # via omotes-grow-worker (pyproject.toml)
-python-dateutil==2.9.0.post0
- # via
- # -c requirements.txt
- # celery
- # influxdb
- # pandas
-python-dotenv==1.0.1
- # via
- # -c requirements.txt
- # omotes-grow-worker (pyproject.toml)
-pytz==2026.2
- # via
- # -c requirements.txt
- # influxdb
- # pandas
-requests==2.34.2
- # via
- # -c requirements.txt
- # influxdb
-restrictedpython==8.4
- # via
- # -c requirements.txt
- # pyecore
-rtc-tools-channel-flow==1.3.1
- # via
- # -c requirements.txt
- # rtc-tools-gil-comp
-rtc-tools-gil-comp==2.6.1
- # via
- # -c requirements.txt
- # mesido
-scipy==1.10.1
- # via
- # -c requirements.txt
- # rtc-tools-gil-comp
-setuptools-git-versioning==2.1.0
- # via omotes-grow-worker (pyproject.toml)
-six==1.17.0
- # via
- # -c requirements.txt
- # flake8-tuple
- # influxdb
- # python-dateutil
-snowballstemmer==3.1.1
- # via pydocstyle
-streamcapture==1.2.7
- # via
- # -c requirements.txt
- # omotes-sdk-python
-strenum==0.4.15
- # via
- # -c requirements.txt
- # mesido
-tomli==2.4.1
- # via
- # black
- # build
- # coverage
- # flake8-pyproject
- # mypy
- # pytest
- # setuptools-git-versioning
-typing-extensions==4.16.0
- # via
- # -c requirements.txt
- # black
- # exceptiongroup
- # multidict
- # mypy
- # omotes-sdk-python
- # psycopg
-tzdata==2026.3
- # via
- # -c requirements.txt
- # kombu
-tzlocal==5.4.4
- # via
- # -c requirements.txt
- # celery
-urllib3==2.7.0
- # via
- # -c requirements.txt
- # requests
-vine==5.1.0
- # via
- # -c requirements.txt
- # amqp
- # celery
- # kombu
-wcwidth==0.8.2
- # via
- # -c requirements.txt
- # prompt-toolkit
-wheel==0.45.1
- # via omotes-grow-worker (pyproject.toml)
-yarl==1.24.2
- # via
- # -c requirements.txt
- # aio-pika
- # aiormq
-
-# The following packages are considered to be unsafe in a requirements file:
-# setuptools
diff --git a/dev.Dockerfile b/dev.Dockerfile
index c6efedc..2bc2cdb 100644
--- a/dev.Dockerfile
+++ b/dev.Dockerfile
@@ -1,4 +1,4 @@
-FROM python:3.10-slim-bookworm
+FROM python:3.11-slim-bookworm
WORKDIR /app
RUN apt update && \
@@ -18,18 +18,27 @@ ENV GUROBI_VERSION="$CASADI_GUROBI_VERSION"
# This env var is for gurobi
ENV GRB_LICENSE_FILE="/app/gurobi/gurobi.lic"
-
RUN mkdir -p /app/gurobi && \
wget -qO- https://packages.gurobi.com/${GUROBI_VERSION_URL_MAJOR}/gurobi${GUROBI_VERSION_URL}_linux64.tar.gz | tar xvz --strip-components=2 -C /app/gurobi
-COPY optimizer-worker/requirements.txt /app/grow_worker/requirements.txt
-RUN pip install -r /app/grow_worker/requirements.txt --no-cache-dir
+# install uv
+COPY --from=ghcr.io/astral-sh/uv:0.8.22 /uv /uvx /bin/
+
+WORKDIR /src
-COPY ../omotes-sdk-protocol/python/ /omotes-sdk-protocol/python/
-COPY ../omotes-sdk-python/ /omotes-sdk-python/
-RUN pip install /omotes-sdk-python/
-RUN pip install /omotes-sdk-protocol/python/
+# install dependencies, avoid using Gurobi's embedded python
+ENV UV_PYTHON=/usr/local/bin/python3.11
+RUN --mount=type=cache,target=/root/.cache/uv \
+ --mount=type=bind,source=optimizer-worker/uv.lock,target=uv.lock \
+ --mount=type=bind,source=optimizer-worker/pyproject.toml,target=pyproject.toml \
+ uv sync --locked --no-install-project --no-dev
+# enable running commands without 'uv run'
+ENV PATH="/src/.venv/bin:$PATH"
-COPY optimizer-worker/src/grow_worker /app/grow_worker/
+# install omotes-sdk-python and mesido from local code
+COPY omotes-sdk-python/ /omotes-sdk-python/
+RUN uv pip install --python /src/.venv/bin/python /omotes-sdk-python/
+COPY mesido/ /mesido/
+RUN uv pip install --python /src/.venv/bin/python /mesido/
-CMD ["python3", "-m", "grow_worker.worker"]
+COPY optimizer-worker/src .
diff --git a/doc/dev_documentation/Makefile b/doc/dev_documentation/Makefile
deleted file mode 100644
index d4bb2cb..0000000
--- a/doc/dev_documentation/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# Minimal makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line, and also
-# from the environment for the first two.
-SPHINXOPTS ?=
-SPHINXBUILD ?= sphinx-build
-SOURCEDIR = .
-BUILDDIR = _build
-
-# Put it first so that "make" without argument is like "make help".
-help:
- @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-.PHONY: help Makefile
-
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile
- @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/dev_documentation/Tools.rst b/doc/dev_documentation/Tools.rst
deleted file mode 100644
index 2f4653f..0000000
--- a/doc/dev_documentation/Tools.rst
+++ /dev/null
@@ -1,60 +0,0 @@
-Tools & IDE's
-===================================================================
-
-.. toctree::
- :maxdepth: 2
- :caption: Contents:
-
-
-There are numerous IDE's for developing python applications, but we
-will focus on two: Visual Studio Code and PyCharm
-
-General
--------
-Python code can be writtin using any text editor. However, we've chosen the following tools to support us:
-
-- **Black** for code formatting
-- **Flake8** for code linting
-- **MyPy** for typehints/typeChecking
-- **pytest** for unit testing
--
-
-PyCharm
--------
-
-
-
-
-
-VS Code
--------
-
-The following extensions should be installed:
-
-* https://marketplace.visualstudio.com/items?itemName=ms-python.python
-* https://marketplace.visualstudio.com/items?itemName=ms-python.flake8
-* https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter
-* https://marketplace.visualstudio.com/items?itemName=matangover.mypy
-
-settings.json for vscode:
-
-.. code-block:: JSON
-
- {
- "python.analysis.typeCheckingMode": "basic",
- "[python]": {
- "editor.defaultFormatter": "ms-python.black-formatter"
- },
- "python.formatting.provider": "black",
- "mypy.runUsingActiveInterpreter": true,
- }
-
-
-
-
-Indices and tables
-------------------
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/doc/dev_documentation/conf.py b/doc/dev_documentation/conf.py
deleted file mode 100644
index 2c567ef..0000000
--- a/doc/dev_documentation/conf.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Configuration file for the Sphinx documentation builder.
-#
-# This file only contains a selection of the most common options. For a full
-# list see the documentation:
-# https://www.sphinx-doc.org/en/master/usage/configuration.html
-
-# -- Path setup --------------------------------------------------------------
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#
-# import os
-# import sys
-# sys.path.insert(0, os.path.abspath('.'))
-
-
-# -- Project information -----------------------------------------------------
-
-project = 'Nieuwe Warmte Nu! python user documentation'
-copyright = '2023, NieuweWarmteNu Design Toolkit'
-author = 'Sebastiaan la Fleur'
-
-
-# -- General configuration ---------------------------------------------------
-
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
-extensions = [
- "sphinx.ext.autodoc",
- "sphinx.ext.intersphinx",
- "sphinx.ext.autosummary",
- "sphinx.ext.napoleon",
- "sphinx_copybutton",
-]
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ["_templates"]
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
-
-
-# -- Options for HTML output -------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-#
-html_theme = "furo"
-
-# 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"]
diff --git a/doc/dev_documentation/index.rst b/doc/dev_documentation/index.rst
deleted file mode 100644
index 77be81e..0000000
--- a/doc/dev_documentation/index.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-.. Deltares python Developer documentation documentation master file, created by
- sphinx-quickstart on Fri Apr 21 15:13:59 2023.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-Welcome to Design Toolkit python Developer documentation's documentation!
-===================================================================
-
-.. toctree::
- :maxdepth: 2
- :caption: Contents:
-
- Tools
-
-This is the developer documentation for this project. This documentation provides
-information on tools, configurations and howto's for developers.
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/doc/dev_documentation/make.bat b/doc/dev_documentation/make.bat
deleted file mode 100644
index 954237b..0000000
--- a/doc/dev_documentation/make.bat
+++ /dev/null
@@ -1,35 +0,0 @@
-@ECHO OFF
-
-pushd %~dp0
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set SOURCEDIR=.
-set BUILDDIR=_build
-
-%SPHINXBUILD% >NUL 2>NUL
-if errorlevel 9009 (
- echo.
- echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
- echo.installed, then set the SPHINXBUILD environment variable to point
- echo.to the full path of the 'sphinx-build' executable. Alternatively you
- echo.may add the Sphinx directory to PATH.
- echo.
- echo.If you don't have Sphinx installed, grab it from
- echo.https://www.sphinx-doc.org/
- exit /b 1
-)
-
-if "%1" == "" goto help
-
-%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
-goto end
-
-:help
-%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
-
-:end
-popd
diff --git a/doc/user_documentation/Makefile b/doc/user_documentation/Makefile
deleted file mode 100644
index d4bb2cb..0000000
--- a/doc/user_documentation/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# Minimal makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line, and also
-# from the environment for the first two.
-SPHINXOPTS ?=
-SPHINXBUILD ?= sphinx-build
-SOURCEDIR = .
-BUILDDIR = _build
-
-# Put it first so that "make" without argument is like "make help".
-help:
- @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-.PHONY: help Makefile
-
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile
- @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/user_documentation/conf.py b/doc/user_documentation/conf.py
deleted file mode 100644
index d31a147..0000000
--- a/doc/user_documentation/conf.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Configuration file for the Sphinx documentation builder.
-#
-# This file only contains a selection of the most common options. For a full
-# list see the documentation:
-# https://www.sphinx-doc.org/en/master/usage/configuration.html
-
-# -- Path setup --------------------------------------------------------------
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#
-# import os
-# import sys
-# sys.path.insert(0, os.path.abspath('.'))
-
-
-# -- Project information -----------------------------------------------------
-
-project = 'Nieuwe Warmte Nu! python user documentation'
-copyright = '2023, NieuweWarmteNu Design Toolkit'
-author = 'Sebastiaan la Fleur'
-
-
-# -- 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']
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
-
-
-# -- Options for HTML output -------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-#
-html_theme = 'alabaster'
-
-# 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']
\ No newline at end of file
diff --git a/doc/user_documentation/index.rst b/doc/user_documentation/index.rst
deleted file mode 100644
index 097493f..0000000
--- a/doc/user_documentation/index.rst
+++ /dev/null
@@ -1,20 +0,0 @@
-.. Deltares python user documentation documentation master file, created by
- sphinx-quickstart on Fri Apr 21 15:13:29 2023.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-Welcome to Design Toolkit python user documentation's documentation!
-==============================================================
-
-.. toctree::
- :maxdepth: 2
- :caption: Contents:
-
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/doc/user_documentation/make.bat b/doc/user_documentation/make.bat
deleted file mode 100644
index 954237b..0000000
--- a/doc/user_documentation/make.bat
+++ /dev/null
@@ -1,35 +0,0 @@
-@ECHO OFF
-
-pushd %~dp0
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set SOURCEDIR=.
-set BUILDDIR=_build
-
-%SPHINXBUILD% >NUL 2>NUL
-if errorlevel 9009 (
- echo.
- echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
- echo.installed, then set the SPHINXBUILD environment variable to point
- echo.to the full path of the 'sphinx-build' executable. Alternatively you
- echo.may add the Sphinx directory to PATH.
- echo.
- echo.If you don't have Sphinx installed, grab it from
- echo.https://www.sphinx-doc.org/
- exit /b 1
-)
-
-if "%1" == "" goto help
-
-%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
-goto end
-
-:help
-%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
-
-:end
-popd
diff --git a/docker-compose.worker-only.dev.yml b/docker-compose.worker-only.dev.yml
deleted file mode 100644
index 676732f..0000000
--- a/docker-compose.worker-only.dev.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-networks:
- omotes:
- external: true
-
-services:
- grow_worker:
- build:
- context: ..
- dockerfile: optimizer-worker/dev.Dockerfile
- environment:
- INFLUXDB_HOSTNAME: omotes_influxdb
- INFLUXDB_PORT: 8096
- INFLUXDB_USERNAME: root
- INFLUXDB_PASSWORD: 9012
-
- RABBITMQ_HOSTNAME: rabbitmq-nwn
- RABBITMQ_PORT: 5672
- RABBITMQ_USERNAME: root
- RABBITMQ_PASSWORD: 5678
- RABBITMQ_VIRTUALHOST: omotes_celery
-
- GROW_TASK_TYPE: grow_optimizer_no_heat_losses_gurobi
- LOG_LEVEL: INFO
- volumes:
- - "./gurobi/gurobi.lic:/app/gurobi/gurobi.lic"
- networks:
- - omotes
- deploy:
- replicas: 1
- resources:
- limits:
- cpus: '4'
- memory: 4gb
- memswap_limit: 4gb
diff --git a/docker-compose.worker-only.yml b/docker-compose.worker-only.yml
deleted file mode 100644
index 2c54610..0000000
--- a/docker-compose.worker-only.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-networks:
- omotes:
- external: true
-
-services:
- grow_worker:
- build:
- context: .
- environment:
- INFLUXDB_HOSTNAME: omotes_influxdb
- INFLUXDB_PORT: 8096
- INFLUXDB_USERNAME: root
- INFLUXDB_PASSWORD: 9012
-
- RABBITMQ_HOSTNAME: rabbitmq-nwn
- RABBITMQ_PORT: 5672
- RABBITMQ_USERNAME: root
- RABBITMQ_PASSWORD: 5678
- RABBITMQ_VIRTUALHOST: omotes_celery
-
- GROW_TASK_TYPE: grow_optimizer_default
- LOG_LEVEL: DEBUG
- volumes:
- - "./gurobi/gurobi.lic:/app/gurobi/gurobi.lic"
- networks:
- - omotes
- deploy:
- replicas: 3
- resources:
- limits:
- cpus: '4'
- memory: 4gb
- memswap_limit: 4gb
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 21bfbdb..0000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,67 +0,0 @@
-networks:
- omotes:
-
-volumes:
- db-data:
- broker-data:
- influxdb_storage:
-
-services:
- rabbitmq:
- image: bitnami/rabbitmq:3.8.27
- ports:
- - "15672:15672"
- - "5673:5672"
- networks:
- - omotes
- healthcheck:
- test: [ "CMD", "curl", "-f", "http://localhost:15672" ]
- interval: 10s
- timeout: 10s
- retries: 5
-
- omotes_influxdb:
- image: influxdb:1.7
- ports:
- - "${INFLUXDB_PORT}:${INFLUXDB_PORT}"
- - "${INFLUXDB_RPC_PORT}:${INFLUXDB_RPC_PORT}"
- networks:
- - omotes
- environment:
- - INFLUXDB_ADMIN_USER=${INFLUXDB_ADMIN_USER}
- - INFLUXDB_ADMIN_PASSWORD=${INFLUXDB_ADMIN_PASSWORD}
- - INFLUXDB_HTTP_BIND_ADDRESS=:${INFLUXDB_PORT}
- - INFLUXDB_BIND_ADDRESS=:${INFLUXDB_RPC_PORT}
- - INFLUXDB_DB=omotes_timeseries
- - INFLUXDB_WRITE_USER=${INFLUXDB_WRITE_USER}
- - INFLUXDB_WRITE_USER_PASSWORD=${INFLUXDB_WRITE_USER_PASSWORD}
- healthcheck:
- test: [ "CMD", "curl", "-f", "http://omotes_influxdb:${INFLUXDB_PORT}/ping" ]
- interval: 10s
- timeout: 5s
- volumes:
- - influxdb_storage:/var/lib/influxdb
-
- grow_worker:
- build:
- context: .
- env_file: .env
- networks:
- - omotes
- deploy:
- replicas: 1
- depends_on:
- rabbitmq:
- condition: service_healthy
- omotes_influxdb:
- condition: service_healthy
-
- local_test:
- build:
- context: ./local_test
- dockerfile: Dockerfile
- networks:
- - omotes
- depends_on:
- grow_worker:
- condition: service_started
diff --git a/justfile b/justfile
new file mode 100644
index 0000000..93ed975
--- /dev/null
+++ b/justfile
@@ -0,0 +1,32 @@
+# CI tasks
+
+# Install dependencies with dev group
+install:
+ uv sync --locked --group dev
+
+# Run linter checks
+lint:
+ uv run ruff check ./src ./tests
+
+# Fix linting issues
+format:
+ uv run ruff format ./src ./tests
+
+# Check formatting without modifying files
+format-check:
+ uv run ruff format --check ./src ./tests
+
+# Run type checker
+typecheck:
+ uv run ty check ./src ./tests
+
+# Run tests
+test:
+ uv run pytest --junit-xml=test-results.xml tests/
+
+# Run all checks (install, lint, format-check, typecheck, test)
+ci: install lint format-check typecheck test
+
+# Show this help message
+help:
+ @just --list
diff --git a/local_test/Delft_T feedback.esdl b/local_test/Delft_T feedback.esdl
new file mode 100644
index 0000000..e6620b4
--- /dev/null
+++ b/local_test/Delft_T feedback.esdl
@@ -0,0 +1,697 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/local_test/Delft_T.esdl b/local_test/Delft_T.esdl
new file mode 100644
index 0000000..4fdeb81
--- /dev/null
+++ b/local_test/Delft_T.esdl
@@ -0,0 +1,697 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/local_test/Dockerfile b/local_test/Dockerfile
deleted file mode 100644
index a635c18..0000000
--- a/local_test/Dockerfile
+++ /dev/null
@@ -1,11 +0,0 @@
-FROM python:3.10
-
-WORKDIR /app
-
-COPY ./requirements.txt .
-
-RUN pip install -r requirements.txt
-
-COPY . .
-
-ENTRYPOINT python -u test_app.py
diff --git a/local_test/requirements.txt b/local_test/requirements.txt
deleted file mode 100644
index 0d07dbf..0000000
--- a/local_test/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-celery==5.3.5
-jsonpickle==3.0.2
diff --git a/local_test/run_optimizer_flow_function.py b/local_test/run_optimizer_flow_function.py
new file mode 100644
index 0000000..556a7d7
--- /dev/null
+++ b/local_test/run_optimizer_flow_function.py
@@ -0,0 +1,21 @@
+from omotes_optimizer_worker.prefect_flow import optimizer_flow
+
+input_esdl_file = "./local_test/Delft_T.esdl"
+# input_esdl_file = "./local_test/Delft_T feedback.esdl"
+
+workflow_type_name = "grow_optimizer_no_heat_losses"
+
+with open(input_esdl_file) as open_file:
+ input_esdl = open_file.read()
+
+optimizer_flow_result = optimizer_flow.fn(
+ input_esdl=input_esdl,
+ workflow_config={},
+ workflow_type_name=workflow_type_name,
+)
+print("--------------ESDL messages:")
+print(optimizer_flow_result.esdl_messages)
+print("--------------Result")
+print(f"Job is done (type: {workflow_type_name}). Output esdl length: {len(optimizer_flow_result.output_esdl)}, ")
+
+# print("Output ESDL:", optimizer_flow_result.output_esdl)
diff --git a/local_test/test_app.py b/local_test/test_app.py
deleted file mode 100644
index 9656809..0000000
--- a/local_test/test_app.py
+++ /dev/null
@@ -1,85 +0,0 @@
-import sys
-import threading
-from uuid import uuid4
-import jsonpickle
-from celery import Celery
-
-input_esdl_no_influx = "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz4KPGVzZGw6RW5lcmd5U3lzdGVtIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOmVzZGw9Imh0dHA6Ly93d3cudG5vLm5sL2VzZGwiIG5hbWU9IlVudGl0bGVkIEVuZXJneVN5c3RlbSB3aXRoIHJldHVybiBuZXR3b3JrIiBpZD0iN2FjMDkyMzEtY2U2MC00YzI0LTgzMzgtOWMwMzE3Njk1YmE0X3dpdGhfcmV0dXJuX25ldHdvcmsiIGRlc2NyaXB0aW9uPSIiIGVzZGxWZXJzaW9uPSJ2MjIxMCIgdmVyc2lvbj0iMTQiPgogIDxlbmVyZ3lTeXN0ZW1JbmZvcm1hdGlvbiB4c2k6dHlwZT0iZXNkbDpFbmVyZ3lTeXN0ZW1JbmZvcm1hdGlvbiIgaWQ9ImU2NDczN2Q5LWQ3NzItNDcyMy1iMDkyLWEwYjM5N2FjMDBiMyI+CiAgICA8Y2FycmllcnMgeHNpOnR5cGU9ImVzZGw6Q2FycmllcnMiIGlkPSI5ZGZmMTNiOS03N2NkLTRiOTktODc3Ny02Yjc2ODBhMTU1YjYiPgogICAgICA8Y2FycmllciB4c2k6dHlwZT0iZXNkbDpIZWF0Q29tbW9kaXR5IiBpZD0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5IiBuYW1lPSJIZWF0IiBzdXBwbHlUZW1wZXJhdHVyZT0iNzAuMCIvPgogICAgICA8Y2FycmllciB4c2k6dHlwZT0iZXNkbDpIZWF0Q29tbW9kaXR5IiByZXR1cm5UZW1wZXJhdHVyZT0iNDAuMCIgaWQ9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOV9yZXQiIG5hbWU9IkhlYXRfcmV0Ii8+CiAgICA8L2NhcnJpZXJzPgogIDwvZW5lcmd5U3lzdGVtSW5mb3JtYXRpb24+CiAgPGluc3RhbmNlIHhzaTp0eXBlPSJlc2RsOkluc3RhbmNlIiBpZD0iZjg1MmI5NDEtOTlmZS00ODdiLWEyMGQtMDFiZWZmOWU3YzQzIiBuYW1lPSJVbnRpdGxlZCBJbnN0YW5jZSI+CiAgICA8YXJlYSB4c2k6dHlwZT0iZXNkbDpBcmVhIiBpZD0iZjRhY2M3ZWYtYTM3ZC00M2I3LTg3Y2ItOGFmNWI4MmUzZmVkIiBuYW1lPSJVbnRpdGxlZCBBcmVhIj4KICAgICAgPGFzc2V0IHhzaTp0eXBlPSJlc2RsOkhlYXRpbmdEZW1hbmQiIG5hbWU9IkhlYXRpbmdEZW1hbmRfMSIgaWQ9ImMyZDc3YWJjLTE2NTYtNDcyMi04NTA4LTdjNjQ1NzRlMDRlZiIgcG93ZXI9IjEwMDAwMDAwLjAiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDE5ODU4ODk0NDE0NiIgbG9uPSI0LjMwODg3MjIyMjkwMDM5MTUiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSIxZGZkYzE3Mi05MzU5LTQzNWEtODE1My0wYTY1NzkzMjIyM2EiIGlkPSIyYTg3MzE5NS1mYTZiLTQyNTAtODUxOS0wNDZmMDQwZmVkYjciIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iZWY3NGVhOGMtODliNC00MmUwLWE5OGMtNDExODYwODc2YzFhIiBjb25uZWN0ZWRUbz0iMThjZTY5MDYtNTk1Yy00NWU0LWFjZjAtZTA3ZjdkNzY0OGM2IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJPdXQiLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9ImQ4YTY3MjQzLTRlNGUtNDNmOC05ODAxLWZkNDU3OWMwZWRkZiI+CiAgICAgICAgICA8aW5zdGFsbGF0aW9uQ29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIxMDAwMDAwLjAiIGlkPSJhY2NkODRiYy1kM2VkLTQ1MjgtYTFmZi1mOTA2YzQ4OTkxYTEiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiB1bml0PSJFVVJPIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiBpZD0iYWU4YjgxZmItODU3Yi00MjgwLTllOTEtOTE5ZGQxYzc2NzVlIiBkZXNjcmlwdGlvbj0iQ29zdCBpbiBFVVIiLz4KICAgICAgICAgIDwvaW5zdGFsbGF0aW9uQ29zdHM+CiAgICAgICAgPC9jb3N0SW5mb3JtYXRpb24+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpIZWF0aW5nRGVtYW5kIiBuYW1lPSJIZWF0aW5nRGVtYW5kXzIiIGlkPSI5MzUyZDk4NC0wZTIxLTRhZjYtOWM1Zi05MWY5ODRhYmZjZmQiIHBvd2VyPSIxMDAwMDAwMC4wIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIENSUz0iV0dTODQiIGxhdD0iNTIuMDQwMDI1OTAzNjk1NjgiIGxvbj0iNC4zMTA2MTAyOTQzNDIwNDIiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSI1M2E1NDQ0OC1hYmRiLTQxYWItYTUzZS00OTg1NTYwNjIyMTYiIGlkPSJhNGE3YzIzZS00ZDc3LTRiYmUtYjhiNC1kZGYyZDJkNmU5N2UiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iYmY2ZTBiNmItYmFhYy00NjhiLWE5YmEtZjgzOTdiYWJmNWQ2IiBjb25uZWN0ZWRUbz0iZDEyNmY3OWUtYzQzZS00ZDlkLWE3Y2UtOGY1OGJlNjM0Njk1IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJPdXQiLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9IjdkOTVkYzU4LTAyYjAtNDljZi1hN2E3LTU2MjNmZmZiNDA3OSI+CiAgICAgICAgICA8aW5zdGFsbGF0aW9uQ29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIxMDAwMDAwLjAiIGlkPSJjMzNhZjYyOS02ZmM1LTRkN2MtOWFjNC01YjFlMGRiMjk1YTUiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiB1bml0PSJFVVJPIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiBpZD0iODkzMDE4MjYtYWNmMy00ZmVjLWIwM2MtN2RiMjc3ZGUwMDRhIiBkZXNjcmlwdGlvbj0iQ29zdCBpbiBFVVIiLz4KICAgICAgICAgIDwvaW5zdGFsbGF0aW9uQ29zdHM+CiAgICAgICAgPC9jb3N0SW5mb3JtYXRpb24+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpIZWF0aW5nRGVtYW5kIiBuYW1lPSJIZWF0aW5nRGVtYW5kXzMiIGlkPSJlMjk1YTE1NS0zZmFiLTRhYjEtOTI1ZC03YmRiNTAwOTRmNDgiIHBvd2VyPSIxMDAwMDAwMC4wIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxhdD0iNTIuMDM3OTY4NDg2MTM3NjEiIGxvbj0iNC4zMTI2NDYwOTA5ODQzNDUiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSIxNmIxMzM3Yy01OTcwLTRlYjQtOTBkMy1lNTJkNTE0YTEzZGYiIGlkPSI3NzAwMjJlNi0zZTcxLTRlNTEtODU0NC0wZGJhODZjNDZhNWIiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iOWMwMjViMTktNTdkMS00M2E4LWIyZTgtZGIzZTY4NDc1NmYyIiBjb25uZWN0ZWRUbz0iNWNkMGYyZTAtZDQ1Ni00OTA5LWE4MWMtNGIzMTJiMWJlODU3IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJPdXQiLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9IjNkMDdiMTcxLWY2NWItNDEzZC05MDkwLTJkMWNkNTc4YTQ4OCI+CiAgICAgICAgICA8aW5zdGFsbGF0aW9uQ29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIxMDAwMDAwLjAiIGlkPSJhZTFkNmNkOC0yOTkwLTRhNzctYTc0Yy02NWViOWM5M2IwODQiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiB1bml0PSJFVVJPIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiBpZD0iN2ZlYjI4Y2EtYmZiOC00YzBkLWIxYjUtYWIxYjM5N2UzOTRjIiBkZXNjcmlwdGlvbj0iQ29zdCBpbiBFVVIiLz4KICAgICAgICAgIDwvaW5zdGFsbGF0aW9uQ29zdHM+CiAgICAgICAgPC9jb3N0SW5mb3JtYXRpb24+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpQaXBlIiByZWxhdGVkPSJQaXBlMV9yZXQiIGRpYW1ldGVyPSJETjQ1MCIgbmFtZT0iUGlwZTEiIGxlbmd0aD0iMjQ1LjciIGlubmVyRGlhbWV0ZXI9IjAuNDQ0NCIgaWQ9IlBpcGUxIiBvdXRlckRpYW1ldGVyPSIwLjYzIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6TGluZSIgQ1JTPSJXR1M4NCI+CiAgICAgICAgICA8cG9pbnQgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxhdD0iNTIuMDQ0Njk4MDUxMTkyMTQiIGxvbj0iNC4zMTAwNTIzOTQ4NjY5NDQiLz4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbGF0PSI1Mi4wNDI3NDE0ODM4ODg0OSIgbG9uPSI0LjMxMTcyMDcyODg3NDIwNyIvPgogICAgICAgIDwvZ2VvbWV0cnk+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6SW5Qb3J0IiBjb25uZWN0ZWRUbz0iNDViZmM3ZDAtZWY1OS00ZjQ5LWIzN2EtODY3YjE4ZTA0Yjg2IiBpZD0iYjQ2MmQ1NjQtYThjMC00YWUwLWE0YWYtMzY5NThmMjQ1NWVhIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9IkluIi8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6T3V0UG9ydCIgaWQ9IjY2NTkwZjk2LWEzOTctNGQ2Zi05Y2ZiLWU3ZDM0MjMyY2FkNiIgY29ubmVjdGVkVG89IjUxODUyODYxLWFlZWItNDYxZi1iOGVjLTA4ZjAwMGFiYzZkZCIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5IiBuYW1lPSJPdXQiLz4KICAgICAgICA8bWF0ZXJpYWwgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXIiIGNvbXBvdW5kVHlwZT0iTEFZRVJFRCI+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjAwNjMiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSI1Mi4xNSIgbmFtZT0ic3RlZWwiIGlkPSIzNzFjMWQ3Mi1kZTM1LTQ1NTktOWIwZS00NzE3MmU1ZDFkODMiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wODA1Ij4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iMC4wMjciIG5hbWU9IlBVUiIgaWQ9ImRmMzBiZDM3LTJmYzQtNDk5My04MjhmLTFiN2NmMWU4MjAyYyIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjAwNiI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjAuNCIgbmFtZT0iSERQRSIgaWQ9ImY1M2RlMzdiLWE3MzUtNGIwZC1iMjI2LWE2YjcyMjAyOWEwMSIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgPC9tYXRlcmlhbD4KICAgICAgICA8ZGF0YVNvdXJjZSB4c2k6dHlwZT0iZXNkbDpEYXRhU291cmNlIiBhdHRyaWJ1dGlvbj0iaHR0cHM6Ly93d3cubG9nc3Rvci5jb20vbWVkaWEvNjUwNi9wcm9kdWN0LWNhdGFsb2d1ZS11ay0yMDIwMDMucGRmIiBuYW1lPSJMb2dzdG9yIFByb2R1Y3QgQ2F0YWxvZ3VlIFZlcnNpb24gMjAyMC4wMyIvPgogICAgICAgIDxjb3N0SW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6Q29zdEluZm9ybWF0aW9uIiBpZD0iZWMyZDc0MGMtMmYxMy00YjcwLWExYmItNmU0YTU2MTQxNGMyIj4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIG5hbWU9IkNvbWJpbmVkIGludmVzdG1lbnQgYW5kIGluc3RhbGxhdGlvbiBjb3N0cyIgaWQ9ImE0MDE2NWU4LTg4YmQtNDliOS04MWQ5LTI5ODgxMmFjMDE3MCIgdmFsdWU9IjM0MTcuOSI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSJkMGFlYmM3Ni0yMDFiLTRiMmQtODFmZS01NTI2OWZjZWZlM2IiIGRlc2NyaXB0aW9uPSJDb3N0cyBpbiBFVVIvbSIgcGVyVW5pdD0iTUVUUkUiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIHVuaXQ9IkVVUk8iLz4KICAgICAgICAgIDwvaW52ZXN0bWVudENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6UGlwZSIgcmVsYXRlZD0iUGlwZTJfcmV0IiBkaWFtZXRlcj0iRE40NTAiIG5hbWU9IlBpcGUyIiBsZW5ndGg9IjE5NS40IiBpbm5lckRpYW1ldGVyPSIwLjQ0NDQiIGlkPSJQaXBlMiIgb3V0ZXJEaWFtZXRlcj0iMC42MyI+CiAgICAgICAgPGdlb21ldHJ5IHhzaTp0eXBlPSJlc2RsOkxpbmUiIENSUz0iV0dTODQiPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsYXQ9IjUyLjA0MjcxMTc4ODI3ODAxIiBsb249IjQuMzExNjI5NTMzNzY3NzAxIi8+CiAgICAgICAgICA8cG9pbnQgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxhdD0iNTIuMDQyMDIyMTg0NjYzMjYiIGxvbj0iNC4zMDkwMDA5Njg5MzMxMDYiLz4KICAgICAgICA8L2dlb21ldHJ5PgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89ImMwZWFjNGRiLWY1ZGEtNDdmMy04MjAyLTg0MzhkMDAwYmQzMiIgaWQ9IjVmNjU1MjBkLTYxZWUtNGY2OC04MDAyLTI3MWY0OGYxZGFlZSIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5IiBuYW1lPSJJbiIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSIxZGZkYzE3Mi05MzU5LTQzNWEtODE1My0wYTY1NzkzMjIyM2EiIGNvbm5lY3RlZFRvPSIyYTg3MzE5NS1mYTZiLTQyNTAtODUxOS0wNDZmMDQwZmVkYjciIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iT3V0Ii8+CiAgICAgICAgPG1hdGVyaWFsIHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyIiBjb21wb3VuZFR5cGU9IkxBWUVSRUQiPgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wMDYzIj4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iNTIuMTUiIG5hbWU9InN0ZWVsIiBpZD0iMzcxYzFkNzItZGUzNS00NTU5LTliMGUtNDcxNzJlNWQxZDgzIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMDgwNSI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjAuMDI3IiBuYW1lPSJQVVIiIGlkPSJkZjMwYmQzNy0yZmM0LTQ5OTMtODI4Zi0xYjdjZjFlODIwMmMiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wMDYiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSIwLjQiIG5hbWU9IkhEUEUiIGlkPSJmNTNkZTM3Yi1hNzM1LTRiMGQtYjIyNi1hNmI3MjIwMjlhMDEiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgIDwvbWF0ZXJpYWw+CiAgICAgICAgPGRhdGFTb3VyY2UgeHNpOnR5cGU9ImVzZGw6RGF0YVNvdXJjZSIgYXR0cmlidXRpb249Imh0dHBzOi8vd3d3LmxvZ3N0b3IuY29tL21lZGlhLzY1MDYvcHJvZHVjdC1jYXRhbG9ndWUtdWstMjAyMDAzLnBkZiIgbmFtZT0iTG9nc3RvciBQcm9kdWN0IENhdGFsb2d1ZSBWZXJzaW9uIDIwMjAuMDMiLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9ImM4MTQwYjNiLTk5ZGMtNGVlMC1iMDM0LTEwNTBiNGZkMTk0NiI+CiAgICAgICAgICA8aW52ZXN0bWVudENvc3RzIHhzaTp0eXBlPSJlc2RsOlNpbmdsZVZhbHVlIiBuYW1lPSJDb21iaW5lZCBpbnZlc3RtZW50IGFuZCBpbnN0YWxsYXRpb24gY29zdHMiIGlkPSJhNDAxNjVlOC04OGJkLTQ5YjktODFkOS0yOTg4MTJhYzAxNzAiIHZhbHVlPSIzNDE3LjkiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiBpZD0iZDBhZWJjNzYtMjAxYi00YjJkLTgxZmUtNTUyNjlmY2VmZTNiIiBkZXNjcmlwdGlvbj0iQ29zdHMgaW4gRVVSL20iIHBlclVuaXQ9Ik1FVFJFIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiB1bml0PSJFVVJPIi8+CiAgICAgICAgICA8L2ludmVzdG1lbnRDb3N0cz4KICAgICAgICA8L2Nvc3RJbmZvcm1hdGlvbj4KICAgICAgPC9hc3NldD4KICAgICAgPGFzc2V0IHhzaTp0eXBlPSJlc2RsOlBpcGUiIHJlbGF0ZWQ9IlBpcGUzX3JldCIgZGlhbWV0ZXI9IkRONDUwIiBuYW1lPSJQaXBlMyIgbGVuZ3RoPSIyNDEuNiIgaW5uZXJEaWFtZXRlcj0iMC40NDQ0IiBpZD0iUGlwZTMiIG91dGVyRGlhbWV0ZXI9IjAuNjMiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpMaW5lIiBDUlM9IldHUzg0Ij4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbGF0PSI1Mi4wNDI3MDg0ODg3NjQ1MDQiIGxvbj0iNC4zMTE3NTgyNzk4MDA0MTYiLz4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbGF0PSI1Mi4wNDA3ODQ4MzA5MzE1NiIgbG9uPSI0LjMxMzM5OTc5MTcxNzUzIi8+CiAgICAgICAgPC9nZW9tZXRyeT4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSJjMGVhYzRkYi1mNWRhLTQ3ZjMtODIwMi04NDM4ZDAwMGJkMzIiIGlkPSI1NzhlYzQxNC0zZjExLTQzMGUtYTg5My02MGVhNzc4NDhmZjUiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iZGMxYmM5NGYtMjZmMi00YTQ5LWEzYmYtZDA2MTRiMWYwZGYyIiBjb25uZWN0ZWRUbz0iZTBhZGY4MGEtYjZmMy00YzEyLWE0MzktZGFiNGU1NTUyMDJhIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9Ik91dCIvPgogICAgICAgIDxtYXRlcmlhbCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlciIgY29tcG91bmRUeXBlPSJMQVlFUkVEIj4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMDA2MyI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjUyLjE1IiBuYW1lPSJzdGVlbCIgaWQ9IjM3MWMxZDcyLWRlMzUtNDU1OS05YjBlLTQ3MTcyZTVkMWQ4MyIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjA4MDUiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSIwLjAyNyIgbmFtZT0iUFVSIiBpZD0iZGYzMGJkMzctMmZjNC00OTkzLTgyOGYtMWI3Y2YxZTgyMDJjIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMDA2Ij4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iMC40IiBuYW1lPSJIRFBFIiBpZD0iZjUzZGUzN2ItYTczNS00YjBkLWIyMjYtYTZiNzIyMDI5YTAxIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICA8L21hdGVyaWFsPgogICAgICAgIDxkYXRhU291cmNlIHhzaTp0eXBlPSJlc2RsOkRhdGFTb3VyY2UiIGF0dHJpYnV0aW9uPSJodHRwczovL3d3dy5sb2dzdG9yLmNvbS9tZWRpYS82NTA2L3Byb2R1Y3QtY2F0YWxvZ3VlLXVrLTIwMjAwMy5wZGYiIG5hbWU9IkxvZ3N0b3IgUHJvZHVjdCBDYXRhbG9ndWUgVmVyc2lvbiAyMDIwLjAzIi8+CiAgICAgICAgPGNvc3RJbmZvcm1hdGlvbiB4c2k6dHlwZT0iZXNkbDpDb3N0SW5mb3JtYXRpb24iIGlkPSI4ODNhZmMxMy0wOThlLTQ3YjQtYWEzMC1hZTNjM2UyNWY5YjEiPgogICAgICAgICAgPGludmVzdG1lbnRDb3N0cyB4c2k6dHlwZT0iZXNkbDpTaW5nbGVWYWx1ZSIgbmFtZT0iQ29tYmluZWQgaW52ZXN0bWVudCBhbmQgaW5zdGFsbGF0aW9uIGNvc3RzIiBpZD0iYTQwMTY1ZTgtODhiZC00OWI5LTgxZDktMjk4ODEyYWMwMTcwIiB2YWx1ZT0iMzQxNy45Ij4KICAgICAgICAgICAgPHByb2ZpbGVRdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgaWQ9ImQwYWViYzc2LTIwMWItNGIyZC04MWZlLTU1MjY5ZmNlZmUzYiIgZGVzY3JpcHRpb249IkNvc3RzIGluIEVVUi9tIiBwZXJVbml0PSJNRVRSRSIgcGh5c2ljYWxRdWFudGl0eT0iQ09TVCIgdW5pdD0iRVVSTyIvPgogICAgICAgICAgPC9pbnZlc3RtZW50Q29zdHM+CiAgICAgICAgPC9jb3N0SW5mb3JtYXRpb24+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpQaXBlIiByZWxhdGVkPSJQaXBlNF9yZXQiIGRpYW1ldGVyPSJETjQ1MCIgbmFtZT0iUGlwZTQiIGxlbmd0aD0iMTg5LjciIGlubmVyRGlhbWV0ZXI9IjAuNDQ0NCIgaWQ9IlBpcGU0IiBvdXRlckRpYW1ldGVyPSIwLjYzIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6TGluZSIgQ1JTPSJXR1M4NCI+CiAgICAgICAgICA8cG9pbnQgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxhdD0iNTIuMDQwNzYxNzMzMzM2MjIiIGxvbj0iNC4zMTMzMjQ2ODk4NjUxMTMiLz4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbGF0PSI1Mi4wNDAwNzIwOTk2MzQ4NyIgbG9uPSI0LjMxMDc4NzMyMDEzNzAyNSIvPgogICAgICAgIDwvZ2VvbWV0cnk+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6SW5Qb3J0IiBjb25uZWN0ZWRUbz0iZWQ3NWIyMTAtNmI1YS00ODhlLThhOGQtZWZlNTcwYzg0OTkwIiBpZD0iNGI5MmU0MTgtNGNhNi00NzY1LTg1YWItY2UzMGY0MTI3YmYwIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9IkluIi8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6T3V0UG9ydCIgaWQ9IjUzYTU0NDQ4LWFiZGItNDFhYi1hNTNlLTQ5ODU1NjA2MjIxNiIgY29ubmVjdGVkVG89ImE0YTdjMjNlLTRkNzctNGJiZS1iOGI0LWRkZjJkMmQ2ZTk3ZSIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5IiBuYW1lPSJPdXQiLz4KICAgICAgICA8bWF0ZXJpYWwgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXIiIGNvbXBvdW5kVHlwZT0iTEFZRVJFRCI+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjAwNjMiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSI1Mi4xNSIgbmFtZT0ic3RlZWwiIGlkPSIzNzFjMWQ3Mi1kZTM1LTQ1NTktOWIwZS00NzE3MmU1ZDFkODMiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wODA1Ij4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iMC4wMjciIG5hbWU9IlBVUiIgaWQ9ImRmMzBiZDM3LTJmYzQtNDk5My04MjhmLTFiN2NmMWU4MjAyYyIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjAwNiI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjAuNCIgbmFtZT0iSERQRSIgaWQ9ImY1M2RlMzdiLWE3MzUtNGIwZC1iMjI2LWE2YjcyMjAyOWEwMSIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgPC9tYXRlcmlhbD4KICAgICAgICA8ZGF0YVNvdXJjZSB4c2k6dHlwZT0iZXNkbDpEYXRhU291cmNlIiBhdHRyaWJ1dGlvbj0iaHR0cHM6Ly93d3cubG9nc3Rvci5jb20vbWVkaWEvNjUwNi9wcm9kdWN0LWNhdGFsb2d1ZS11ay0yMDIwMDMucGRmIiBuYW1lPSJMb2dzdG9yIFByb2R1Y3QgQ2F0YWxvZ3VlIFZlcnNpb24gMjAyMC4wMyIvPgogICAgICAgIDxjb3N0SW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6Q29zdEluZm9ybWF0aW9uIiBpZD0iYjFkZDA0MjctZjhjYS00NTI1LTgxOTItOGE4OTU0ZjJiZTFjIj4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIG5hbWU9IkNvbWJpbmVkIGludmVzdG1lbnQgYW5kIGluc3RhbGxhdGlvbiBjb3N0cyIgaWQ9ImE0MDE2NWU4LTg4YmQtNDliOS04MWQ5LTI5ODgxMmFjMDE3MCIgdmFsdWU9IjM0MTcuOSI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSJkMGFlYmM3Ni0yMDFiLTRiMmQtODFmZS01NTI2OWZjZWZlM2IiIGRlc2NyaXB0aW9uPSJDb3N0cyBpbiBFVVIvbSIgcGVyVW5pdD0iTUVUUkUiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIHVuaXQ9IkVVUk8iLz4KICAgICAgICAgIDwvaW52ZXN0bWVudENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6UGlwZSIgcmVsYXRlZD0iUGlwZTVfcmV0IiBkaWFtZXRlcj0iRE40NTAiIG5hbWU9IlBpcGU1IiBsZW5ndGg9IjI0NC42IiBpbm5lckRpYW1ldGVyPSIwLjQ0NDQiIGlkPSJQaXBlNSIgb3V0ZXJEaWFtZXRlcj0iMC42MyI+CiAgICAgICAgPGdlb21ldHJ5IHhzaTp0eXBlPSJlc2RsOkxpbmUiIENSUz0iV0dTODQiPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsYXQ9IjUyLjA0MDczODYzNTcyODk4IiBsb249IjQuMzEzNDUzNDM1ODk3ODI4Ii8+CiAgICAgICAgICA8cG9pbnQgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxhdD0iNTIuMDM4Nzk4Mzk0MTA5MzgiIGxvbj0iNC4zMTUxMzc4NjMxNTkxODEiLz4KICAgICAgICA8L2dlb21ldHJ5PgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89ImVkNzViMjEwLTZiNWEtNDg4ZS04YThkLWVmZTU3MGM4NDk5MCIgaWQ9ImQxY2UxN2ZlLTU3MmQtNGFkZS1hNmUxLWEzZDNhYTBmYWI2NCIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5IiBuYW1lPSJJbiIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSI4ZjFiZWE1Mi1lMzIyLTRkMzQtYWQ0My03ZDFlOTcyNDNkNjIiIGNvbm5lY3RlZFRvPSIxY2I5MjNiNS0yYTY5LTQ2ZDktODc0Yy02OGQ1NTJlZjU1NzYiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iT3V0Ii8+CiAgICAgICAgPG1hdGVyaWFsIHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyIiBjb21wb3VuZFR5cGU9IkxBWUVSRUQiPgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wMDYzIj4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iNTIuMTUiIG5hbWU9InN0ZWVsIiBpZD0iMzcxYzFkNzItZGUzNS00NTU5LTliMGUtNDcxNzJlNWQxZDgzIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMDgwNSI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjAuMDI3IiBuYW1lPSJQVVIiIGlkPSJkZjMwYmQzNy0yZmM0LTQ5OTMtODI4Zi0xYjdjZjFlODIwMmMiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wMDYiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSIwLjQiIG5hbWU9IkhEUEUiIGlkPSJmNTNkZTM3Yi1hNzM1LTRiMGQtYjIyNi1hNmI3MjIwMjlhMDEiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgIDwvbWF0ZXJpYWw+CiAgICAgICAgPGRhdGFTb3VyY2UgeHNpOnR5cGU9ImVzZGw6RGF0YVNvdXJjZSIgYXR0cmlidXRpb249Imh0dHBzOi8vd3d3LmxvZ3N0b3IuY29tL21lZGlhLzY1MDYvcHJvZHVjdC1jYXRhbG9ndWUtdWstMjAyMDAzLnBkZiIgbmFtZT0iTG9nc3RvciBQcm9kdWN0IENhdGFsb2d1ZSBWZXJzaW9uIDIwMjAuMDMiLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9ImQ5MTMyMzAxLTFmNDktNGMzMS1iMzhmLTRlNjUwYzE4YTk4NCI+CiAgICAgICAgICA8aW52ZXN0bWVudENvc3RzIHhzaTp0eXBlPSJlc2RsOlNpbmdsZVZhbHVlIiBuYW1lPSJDb21iaW5lZCBpbnZlc3RtZW50IGFuZCBpbnN0YWxsYXRpb24gY29zdHMiIGlkPSJhNDAxNjVlOC04OGJkLTQ5YjktODFkOS0yOTg4MTJhYzAxNzAiIHZhbHVlPSIzNDE3LjkiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiBpZD0iZDBhZWJjNzYtMjAxYi00YjJkLTgxZmUtNTUyNjlmY2VmZTNiIiBkZXNjcmlwdGlvbj0iQ29zdHMgaW4gRVVSL20iIHBlclVuaXQ9Ik1FVFJFIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiB1bml0PSJFVVJPIi8+CiAgICAgICAgICA8L2ludmVzdG1lbnRDb3N0cz4KICAgICAgICA8L2Nvc3RJbmZvcm1hdGlvbj4KICAgICAgPC9hc3NldD4KICAgICAgPGFzc2V0IHhzaTp0eXBlPSJlc2RsOlBpcGUiIHJlbGF0ZWQ9IlBpcGU2X3JldCIgZGlhbWV0ZXI9IkRONDUwIiBuYW1lPSJQaXBlNiIgbGVuZ3RoPSIxNzYuNiIgaW5uZXJEaWFtZXRlcj0iMC40NDQ0IiBpZD0iUGlwZTYiIG91dGVyRGlhbWV0ZXI9IjAuNjMiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpMaW5lIiBDUlM9IldHUzg0Ij4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbGF0PSI1Mi4wMzg3NTIxOTY4NTM4OSIgbG9uPSI0LjMxNTA5NDk0NzgxNDk0MiIvPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsYXQ9IjUyLjAzODAxMzAzNDI3MjkyIiBsb249IjQuMzEyODA5NzA1NzM0MjU0Ii8+CiAgICAgICAgPC9nZW9tZXRyeT4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSJhMDJlNDFhYi05OWY4LTQ2ZDMtYjJkMS1iZTQ0YWE1Yjc5MTQiIGlkPSI3ZjE2MmEzMC03ZTQxLTRkN2YtYjAxMS1mZmNmNGMxNjUxZjgiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iMTZiMTMzN2MtNTk3MC00ZWI0LTkwZDMtZTUyZDUxNGExM2RmIiBjb25uZWN0ZWRUbz0iNzcwMDIyZTYtM2U3MS00ZTUxLTg1NDQtMGRiYTg2YzQ2YTViIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9Ik91dCIvPgogICAgICAgIDxtYXRlcmlhbCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlciIgY29tcG91bmRUeXBlPSJMQVlFUkVEIj4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMDA2MyI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjUyLjE1IiBuYW1lPSJzdGVlbCIgaWQ9IjM3MWMxZDcyLWRlMzUtNDU1OS05YjBlLTQ3MTcyZTVkMWQ4MyIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjA4MDUiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSIwLjAyNyIgbmFtZT0iUFVSIiBpZD0iZGYzMGJkMzctMmZjNC00OTkzLTgyOGYtMWI3Y2YxZTgyMDJjIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMDA2Ij4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iMC40IiBuYW1lPSJIRFBFIiBpZD0iZjUzZGUzN2ItYTczNS00YjBkLWIyMjYtYTZiNzIyMDI5YTAxIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICA8L21hdGVyaWFsPgogICAgICAgIDxkYXRhU291cmNlIHhzaTp0eXBlPSJlc2RsOkRhdGFTb3VyY2UiIGF0dHJpYnV0aW9uPSJodHRwczovL3d3dy5sb2dzdG9yLmNvbS9tZWRpYS82NTA2L3Byb2R1Y3QtY2F0YWxvZ3VlLXVrLTIwMjAwMy5wZGYiIG5hbWU9IkxvZ3N0b3IgUHJvZHVjdCBDYXRhbG9ndWUgVmVyc2lvbiAyMDIwLjAzIi8+CiAgICAgICAgPGNvc3RJbmZvcm1hdGlvbiB4c2k6dHlwZT0iZXNkbDpDb3N0SW5mb3JtYXRpb24iIGlkPSI3NjJhZWVjNi1hYzVkLTRlNTQtYjMyZi0zZGE5MjliZDY3MTMiPgogICAgICAgICAgPGludmVzdG1lbnRDb3N0cyB4c2k6dHlwZT0iZXNkbDpTaW5nbGVWYWx1ZSIgbmFtZT0iQ29tYmluZWQgaW52ZXN0bWVudCBhbmQgaW5zdGFsbGF0aW9uIGNvc3RzIiBpZD0iYTQwMTY1ZTgtODhiZC00OWI5LTgxZDktMjk4ODEyYWMwMTcwIiB2YWx1ZT0iMzQxNy45Ij4KICAgICAgICAgICAgPHByb2ZpbGVRdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgaWQ9ImQwYWViYzc2LTIwMWItNGIyZC04MWZlLTU1MjY5ZmNlZmUzYiIgZGVzY3JpcHRpb249IkNvc3RzIGluIEVVUi9tIiBwZXJVbml0PSJNRVRSRSIgcGh5c2ljYWxRdWFudGl0eT0iQ09TVCIgdW5pdD0iRVVSTyIvPgogICAgICAgICAgPC9pbnZlc3RtZW50Q29zdHM+CiAgICAgICAgPC9jb3N0SW5mb3JtYXRpb24+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpIZWF0UHJvZHVjZXIiIHBvd2VyPSIzMDAwMDAwLjAiIG5hbWU9IkhlYXRQcm9kdWNlcl8xIiBpZD0iMzI0YjAzNzEtYjczOC00ZjU1LWE5NzgtMzMwNmVlODE2MzhjIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxhdD0iNTIuMDQ0NzY0MDM4NDc4MjUiIGxvbj0iNC4zMDk5NzcyOTMwMTQ1MjciLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iNDViZmM3ZDAtZWY1OS00ZjQ5LWIzN2EtODY3YjE4ZTA0Yjg2IiBjb25uZWN0ZWRUbz0iYjQ2MmQ1NjQtYThjMC00YWUwLWE0YWYtMzY5NThmMjQ1NWVhIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9Ik91dCIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89ImUzMWUxMmMyLThmODAtNGFlZC05ZTRiLTkxODQ0NWEzMjk5NiIgaWQ9ImJhOWNhMDg0LWI3MWYtNDJhMy04ODRhLWYyZjJiM2FlNDI2NSIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5X3JldCIgbmFtZT0iSW4iLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9IjI4ZTliODUzLWU0MDctNDliMC1iZTY2LTE1NzJjMTJkYzgxMSI+CiAgICAgICAgICA8aW5zdGFsbGF0aW9uQ29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIzMDAwMDAuMCIgaWQ9ImNjYmE0M2E1LWM0YzgtNDgxOC1hMzM5LTc2MmIzMzg1ZjU2MiI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIHVuaXQ9IkVVUk8iIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIGlkPSI2OTI0MDMxYy0wNTQ4LTRiMzMtYTM0MS0zZDAzYzVjMmI1YTAiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUiIvPgogICAgICAgICAgPC9pbnN0YWxsYXRpb25Db3N0cz4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSI5MDAwMDAuMCIgaWQ9ImI2Yzg1MjU5LTkyMTEtNDE3Zi1iOWRiLTg5ZmI0NzNmMmYxYyI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSI0N2ZjYmZmMi1mMGYxLTQ4ZDktYjdjMS03ZTM0YTkwYjE1MzkiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUi9NVyIgcGVyVW5pdD0iV0FUVCIgcGVyTXVsdGlwbGllcj0iTUVHQSIgdW5pdD0iRVVSTyIgcGh5c2ljYWxRdWFudGl0eT0iQ09TVCIvPgogICAgICAgICAgPC9pbnZlc3RtZW50Q29zdHM+CiAgICAgICAgICA8dmFyaWFibGVPcGVyYXRpb25hbEFuZE1haW50ZW5hbmNlQ29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIxNS4wIiBpZD0iYjkwYzY1OWYtNGQ4Ny00NDAyLWIwNDItOTBhNzU5NGU3MDE2Ij4KICAgICAgICAgICAgPHByb2ZpbGVRdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgaWQ9IjBkOTQ4NDA2LTc4NjQtNGVmZi1iYzY1LTc2NzA1MzNiZjE4YiIgZGVzY3JpcHRpb249IkNvc3QgaW4gRVVSL01XaCIgcGVyVW5pdD0iV0FUVEhPVVIiIHBlck11bHRpcGxpZXI9Ik1FR0EiIHVuaXQ9IkVVUk8iIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiLz4KICAgICAgICAgIDwvdmFyaWFibGVPcGVyYXRpb25hbEFuZE1haW50ZW5hbmNlQ29zdHM+CiAgICAgICAgICA8bWFyZ2luYWxDb3N0cyB4c2k6dHlwZT0iZXNkbDpTaW5nbGVWYWx1ZSIgdmFsdWU9IjIuMCIgaWQ9IjgzNzdjNTE0LTc2YTItNDU5Mi04YzljLWYyZTQyOTgzNzA5OCI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSI4OGU3ODM1OC0xMzQ0LTQ1YzItOGJiYy01MWRlMDY2MDAzYjEiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUiIgdW5pdD0iRVVSTyIvPgogICAgICAgICAgPC9tYXJnaW5hbENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6Sm9pbnQiIG5hbWU9IkpvaW50XzEiIGlkPSJmOTZkMDJkNy0xOWQxLTRhMGItODg2OS0yZDE4MGYzOWI3ZTYiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDI3MjA4NjE5Mzg4NTQiIGxvbj0iNC4zMTE2OTUyNDc4ODg1NjYiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSI2NjU5MGY5Ni1hMzk3LTRkNmYtOWNmYi1lN2QzNDIzMmNhZDYgZjk2NmJhZGUtMWZhZC00NTNmLThlYzItNDA2MmVjNzBiYzdiIiBpZD0iNTE4NTI4NjEtYWVlYi00NjFmLWI4ZWMtMDhmMDAwYWJjNmRkIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9IkluIi8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6T3V0UG9ydCIgaWQ9ImMwZWFjNGRiLWY1ZGEtNDdmMy04MjAyLTg0MzhkMDAwYmQzMiIgY29ubmVjdGVkVG89IjVmNjU1MjBkLTYxZWUtNGY2OC04MDAyLTI3MWY0OGYxZGFlZSA1NzhlYzQxNC0zZjExLTQzMGUtYTg5My02MGVhNzc4NDhmZjUgMmNjNzczZWUtYjU2Mi00ZTFmLWExZDEtYTI2NTZlMTA5MDdkIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9Ik91dCIvPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6Sm9pbnQiIG5hbWU9IkpvaW50XzIiIGlkPSJkNzRkYjliYS1iODZjLTQ4NmEtODkxMS0zZmYzNjhhZTYzYTMiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDA3NTY3ODM4NDk5NyIgbG9uPSI0LjMxMzM3Mjk2OTYyNzM4MSIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89ImRjMWJjOTRmLTI2ZjItNGE0OS1hM2JmLWQwNjE0YjFmMGRmMiIgaWQ9ImUwYWRmODBhLWI2ZjMtNGMxMi1hNDM5LWRhYjRlNTU1MjAyYSIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5IiBuYW1lPSJJbiIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSJlZDc1YjIxMC02YjVhLTQ4OGUtOGE4ZC1lZmU1NzBjODQ5OTAiIGNvbm5lY3RlZFRvPSI0YjkyZTQxOC00Y2E2LTQ3NjUtODVhYi1jZTMwZjQxMjdiZjAgZDFjZTE3ZmUtNTcyZC00YWRlLWE2ZTEtYTNkM2FhMGZhYjY0IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9Ik91dCIvPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6Sm9pbnQiIG5hbWU9IkpvaW50XzMiIGlkPSJkYTJmMTJkYy0wYjc0LTQ3MTktYmM1MC0xOGQ4NDc1MjRkYjMiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wMzg3NzAzNDU3ODEzOTQiIGxvbj0iNC4zMTUxMjcxMzQzMjMxMjEiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSI4ZjFiZWE1Mi1lMzIyLTRkMzQtYWQ0My03ZDFlOTcyNDNkNjIiIGlkPSIxY2I5MjNiNS0yYTY5LTQ2ZDktODc0Yy02OGQ1NTJlZjU1NzYiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iYTAyZTQxYWItOTlmOC00NmQzLWIyZDEtYmU0NGFhNWI3OTE0IiBjb25uZWN0ZWRUbz0iN2YxNjJhMzAtN2U0MS00ZDdmLWIwMTEtZmZjZjRjMTY1MWY4IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9Ik91dCIvPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6QVRFUyIgYXF1aWZlck5ldFRvR3Jvc3M9IjEuMCIgbmFtZT0iQVRFU18wMzNjIiBhcXVpZmVyVGhpY2tuZXNzPSI0NS4wIiBtYXhEaXNjaGFyZ2VSYXRlPSIxMTYxMDAwMC4wIiB3ZWxsQ2FzaW5nU2l6ZT0iMTMuMCIgYXF1aWZlckFuaXNvdHJvcHk9IjQuMCIgYXF1aWZlclBvcm9zaXR5PSIwLjMiIGFxdWlmZXJNaWRUZW1wZXJhdHVyZT0iMTcuMCIgYXF1aWZlclRvcERlcHRoPSIzMDAuMCIgaWQ9IjAzM2MyNTk4LTVjMWEtNDhiNy05M2IxLWM3NDZiODE4MTlmZiIgd2VsbERpc3RhbmNlPSIxNTAuMCIgbWF4Q2hhcmdlUmF0ZT0iMTE2MTAwMDAuMCIgc2FsaW5pdHk9IjEwMDAwLjAiIGFxdWlmZXJQZXJtZWFiaWxpdHk9IjEwMDAwLjAiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbG9uPSI0LjMxNDk0NDc0NDExMDEwOCIgbGF0PSI1Mi4wNDM5MjU5OTI3MDYxOSIvPgogICAgICAgIDxkYXRhU291cmNlIHhzaTp0eXBlPSJlc2RsOkRhdGFTb3VyY2UiIGRlc2NyaXB0aW9uPSJUaGlzIGRhdGEgd2FzIGdlbmVyYXRlZCB1c2luZyB0aGUgJ2tvc3Rlbl9wZXJfYXNzZXQueHNseCcgZmlsZSBpbiB0aGUgJ0tlbnRhbGxlbicgZGlyZWN0b3J5IG9mIFdhcm1pbmdVcCBwcm9qZWN0IDFEIiBhdHRyaWJ1dGlvbj0iIiBuYW1lPSJXYXJtaW5nVXAgZmFjdHNoZWV0OiBIVC1BVEVTIChoaWdoKSIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89IjAxYzg4MmY3LWVjMTUtNGQzNC05ZjQzLTgxODE5NzJmMjUwMCIgaWQ9IjZiODNlNzRkLTVmZjEtNGZmYS04YmQ0LWRlMTE1NGI1NDFlMiIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5IiBuYW1lPSJJblBvcnQiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iMTFlMzU4OWItOWEyZC00OTdlLWJjMmYtZmZmM2UzNGQ2ZWZlIiBjb25uZWN0ZWRUbz0iY2FkMTYyNTMtZjAwMS00N2YwLWFlYjAtMWU1MzJmNTIxM2U3IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJPdXRQb3J0Ii8+CiAgICAgICAgPGNvc3RJbmZvcm1hdGlvbiB4c2k6dHlwZT0iZXNkbDpDb3N0SW5mb3JtYXRpb24iPgogICAgICAgICAgPHZhcmlhYmxlT3BlcmF0aW9uYWxDb3N0cyB4c2k6dHlwZT0iZXNkbDpTaW5nbGVWYWx1ZSIgdmFsdWU9IjYuMCIgaWQ9IjdhNzg5Yjk1LTkzYmItNDE1Yi1hYmJkLTRlY2JiNmFkNjBjOSI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSJjNTIzMzRjOS1iYzVkLTQxZjQtYjkzZC0xMGU3Yjc2OWYyODEiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUi9NV2giIHBlclVuaXQ9IldBVFRIT1VSIiBwZXJNdWx0aXBsaWVyPSJNRUdBIiB1bml0PSJFVVJPIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIi8+CiAgICAgICAgICA8L3ZhcmlhYmxlT3BlcmF0aW9uYWxDb3N0cz4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIyMzMzNTkuMCI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSJhM2I1Y2RkOS0zNjRiLTQyNjItYmNlNS00NjU4YzVmMWJhYzkiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUi9NVyIgcGVyVW5pdD0iV0FUVCIgcGVyTXVsdGlwbGllcj0iTUVHQSIgdW5pdD0iRVVSTyIvPgogICAgICAgICAgPC9pbnZlc3RtZW50Q29zdHM+CiAgICAgICAgICA8aW5zdGFsbGF0aW9uQ29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIxMDAwMDAwLjAiIGlkPSIyMjUyODk3Mi0xOTIwLTQyZDgtOWUwYy0xMTVmNDE5YzMxZDEiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiBpZD0iNjIwYTg1MjktNDNlYy00Njc0LThlZDMtMTBiZWZhZmYwNzQyIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiBkZXNjcmlwdGlvbj0iQ29zdCBpbiBFVVIiIHVuaXQ9IkVVUk8iLz4KICAgICAgICAgIDwvaW5zdGFsbGF0aW9uQ29zdHM+CiAgICAgICAgPC9jb3N0SW5mb3JtYXRpb24+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpKb2ludCIgbmFtZT0iSm9pbnRfMV9yZXQiIGlkPSI2ZDk3NzAwYy1hM2Q3LTQxMjctYjY0Yy1mMDhlZTJlMzA4ZjkiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDI4MTA4NjIwMjg4NSIgbG9uPSI0LjMxMTA3NDQwMjY2NTY0OSIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSIyOTEzZTY0NS1iMDI3LTQyOWUtYmY1ZC0yMmFjZTk2YTM5ZmEiIGNvbm5lY3RlZFRvPSJkZDUwZTYwMy1jODdjLTRjZGItODJiYi00ODZlYmVlNzcyNTUgNDJlOWY4NmItZWE5Ni00OTkyLWJmM2YtOWNiYWU4YTRhMzljIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJyZXRfcG9ydCIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89IjA0MzFiOGEwLWE4ZDEtNDM3NS1iMzQ4LTM3YTQ3NWFkZDQ3YSA2YjY1NWViMS0yYjY2LTQ1NWYtOTBhMy0wZGQ2ZjI4NDRmYWIgNmNjYjAwNWMtNDVkNC00MjIwLTkyODYtY2M4Zjc3YjAzZWM2IiBpZD0iNzg5MzEyNWQtZDgyZi00ZmU4LWFhZWEtNWZiNmFmZWNjNjM1IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJyZXRfcG9ydCIvPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6Sm9pbnQiIG5hbWU9IkpvaW50XzJfcmV0IiBpZD0iZTYxNWM3N2EtYmI3NS00MTFiLTkyYzItNTQ5ZWZiZGY4ZWM4Ij4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIENSUz0iV0dTODQiIGxhdD0iNTIuMDQwODQ2NzgzOTM5OTciIGxvbj0iNC4zMTI3NDYyNDU1Mjk1MzYiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSJiMzE4N2VmOS1jZDBiLTRlYTgtOTBlNC1lYWIzOWZhMjI1ZTkgNGIzOTczYWItNmU0Yi00OGFmLTk0N2QtNTJjNmQzMGYyMGVhIiBpZD0iYTFiNzE5Y2ItZjczNS00YTMwLWEwZDItY2Y2OTQ1YjNhZmExIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJyZXRfcG9ydCIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSIyZGQ3OTYxYi00NmNlLTQwMjctODRiNi1jYzI2ODRhMDNhN2IiIGNvbm5lY3RlZFRvPSIwNjUwZDg1MC01OGE5LTQ1YjMtODMxMy1hMzE1NmEwNjE5ODgiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOV9yZXQiIG5hbWU9InJldF9wb3J0Ii8+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpKb2ludCIgbmFtZT0iSm9pbnRfM19yZXQiIGlkPSJhOTBkMTQ2Zi1lMjM0LTQ1OWMtOTc0ZS03ODY3YWZiYmIzZjAiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wMzg4NjAzNDU4NzEzOSIgbG9uPSI0LjMxNDQ5NDM0NzU3NjM0NCIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89IjIwNDVhY2E5LTRlNTAtNDJlYy05OWRlLWZiY2ZmYTYyN2E4NiIgaWQ9ImYzNmI5NzY3LThlNjQtNDc0NC04Y2QwLTA4YWNiMmFlODczYiIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5X3JldCIgbmFtZT0icmV0X3BvcnQiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iNTljY2RkZGMtODkzYi00MTUyLThiYzQtMDE2OGU3ZTc0YmYzIiBjb25uZWN0ZWRUbz0iMmI3YzNhY2ItNjlhNy00OTdkLWE3MmYtYjk4ZGIxODk4NDFjIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJyZXRfcG9ydCIvPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6UGlwZSIgcmVsYXRlZD0iUGlwZTEiIGRpYW1ldGVyPSJETjQ1MCIgbmFtZT0iUGlwZTFfcmV0IiBsZW5ndGg9IjI0NS43IiBpbm5lckRpYW1ldGVyPSIwLjQ0NDQiIGlkPSJQaXBlMV9yZXQiIG91dGVyRGlhbWV0ZXI9IjAuNjMiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpMaW5lIj4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDI4MzE0ODM5Nzg0OSIgbG9uPSI0LjMxMTA5OTk0NDc3OTE4MiIvPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBDUlM9IldHUzg0IiBsYXQ9IjUyLjA0NDc4ODA1MTI4MjE0IiBsb249IjQuMzA5NDM3MzU1MDMzMDA2Ii8+CiAgICAgICAgPC9nZW9tZXRyeT4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSIyOTEzZTY0NS1iMDI3LTQyOWUtYmY1ZC0yMmFjZTk2YTM5ZmEiIGlkPSJkZDUwZTYwMy1jODdjLTRjZGItODJiYi00ODZlYmVlNzcyNTUiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOV9yZXQiIG5hbWU9IkluX3JldCIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSJlMzFlMTJjMi04ZjgwLTRhZWQtOWU0Yi05MTg0NDVhMzI5OTYiIGNvbm5lY3RlZFRvPSJiYTljYTA4NC1iNzFmLTQyYTMtODg0YS1mMmYyYjNhZTQyNjUiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOV9yZXQiIG5hbWU9Ik91dF9yZXQiLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9IjAzYzA3MjkzLWY2ZDQtNGFhNi1hMjk3LTUzMTJjNGQxYzI3ZSI+CiAgICAgICAgICA8aW52ZXN0bWVudENvc3RzIHhzaTp0eXBlPSJlc2RsOlNpbmdsZVZhbHVlIiB2YWx1ZT0iMzQxNy45IiBpZD0iOWI0NDkxNDQtZDBiZi00NWI5LTg4MjItMTVkYmExZDQxMjZkIj4KICAgICAgICAgICAgPHByb2ZpbGVRdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgaWQ9IjZkYmUwOTNmLWY2ZGQtNDliNC05ZDVlLWEyY2Q1Nzg2MTFiZSIgZGVzY3JpcHRpb249IkNvc3QgaW4gRVVSL20iIHBlclVuaXQ9Ik1FVFJFIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiB1bml0PSJFVVJPIi8+CiAgICAgICAgICA8L2ludmVzdG1lbnRDb3N0cz4KICAgICAgICA8L2Nvc3RJbmZvcm1hdGlvbj4KICAgICAgPC9hc3NldD4KICAgICAgPGFzc2V0IHhzaTp0eXBlPSJlc2RsOlBpcGUiIHJlbGF0ZWQ9IlBpcGUyIiBkaWFtZXRlcj0iRE40NTAiIG5hbWU9IlBpcGUyX3JldCIgbGVuZ3RoPSIxOTUuNCIgaW5uZXJEaWFtZXRlcj0iMC40NDQ0IiBpZD0iUGlwZTJfcmV0IiBvdXRlckRpYW1ldGVyPSIwLjYzIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6TGluZSI+CiAgICAgICAgICA8cG9pbnQgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIENSUz0iV0dTODQiIGxhdD0iNTIuMDQyMTEyMTg0NzUzMjYiIGxvbj0iNC4zMDgzNzgwNDUzODY2OTEiLz4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDI4MDE3ODgzNjgwMSIgbG9uPSI0LjMxMTAwODY2MTY0NDYwNiIvPgogICAgICAgIDwvZ2VvbWV0cnk+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6SW5Qb3J0IiBjb25uZWN0ZWRUbz0iZWY3NGVhOGMtODliNC00MmUwLWE5OGMtNDExODYwODc2YzFhIiBpZD0iMThjZTY5MDYtNTk1Yy00NWU0LWFjZjAtZTA3ZjdkNzY0OGM2IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJJbl9yZXQiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iMDQzMWI4YTAtYThkMS00Mzc1LWIzNDgtMzdhNDc1YWRkNDdhIiBjb25uZWN0ZWRUbz0iNzg5MzEyNWQtZDgyZi00ZmU4LWFhZWEtNWZiNmFmZWNjNjM1IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJPdXRfcmV0Ii8+CiAgICAgICAgPGNvc3RJbmZvcm1hdGlvbiB4c2k6dHlwZT0iZXNkbDpDb3N0SW5mb3JtYXRpb24iIGlkPSJiZWM4MzA3MC0yYzUxLTQ4MjUtODJmMy05MjQzNGJkM2U1OWMiPgogICAgICAgICAgPGludmVzdG1lbnRDb3N0cyB4c2k6dHlwZT0iZXNkbDpTaW5nbGVWYWx1ZSIgdmFsdWU9IjM0MTcuOSIgaWQ9IjFjMzMwMjRjLTk5YzgtNDE2OC1iMzUzLTlmMDk5YjU5ZWI2MCI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSIyNmZkYjhiZi02NDEzLTQyNzItYTU2Yi1iMDg0ODIzYWM1NzQiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUi9tIiBwZXJVbml0PSJNRVRSRSIgcGh5c2ljYWxRdWFudGl0eT0iQ09TVCIgdW5pdD0iRVVSTyIvPgogICAgICAgICAgPC9pbnZlc3RtZW50Q29zdHM+CiAgICAgICAgPC9jb3N0SW5mb3JtYXRpb24+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpQaXBlIiByZWxhdGVkPSJQaXBlMyIgZGlhbWV0ZXI9IkRONDUwIiBuYW1lPSJQaXBlM19yZXQiIGxlbmd0aD0iMjQxLjYiIGlubmVyRGlhbWV0ZXI9IjAuNDQ0NCIgaWQ9IlBpcGUzX3JldCIgb3V0ZXJEaWFtZXRlcj0iMC42MyI+CiAgICAgICAgPGdlb21ldHJ5IHhzaTp0eXBlPSJlc2RsOkxpbmUiPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBDUlM9IldHUzg0IiBsYXQ9IjUyLjA0MDg3NDgzMTAyMTU1NCIgbG9uPSI0LjMxMjc3MzE1MjM3MDcwNSIvPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBDUlM9IldHUzg0IiBsYXQ9IjUyLjA0Mjc5ODQ4ODg1NDUiIGxvbj0iNC4zMTExMzczOTc4OTQ4NDU1Ii8+CiAgICAgICAgPC9nZW9tZXRyeT4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSIyZGQ3OTYxYi00NmNlLTQwMjctODRiNi1jYzI2ODRhMDNhN2IiIGlkPSIwNjUwZDg1MC01OGE5LTQ1YjMtODMxMy1hMzE1NmEwNjE5ODgiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOV9yZXQiIG5hbWU9IkluX3JldCIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSI2YjY1NWViMS0yYjY2LTQ1NWYtOTBhMy0wZGQ2ZjI4NDRmYWIiIGNvbm5lY3RlZFRvPSI3ODkzMTI1ZC1kODJmLTRmZTgtYWFlYS01ZmI2YWZlY2M2MzUiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOV9yZXQiIG5hbWU9Ik91dF9yZXQiLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9IjM4ZjJmMGY3LWY4MTQtNGJhZi1hZTNhLTM2NWFmMWI4NzJkYiI+CiAgICAgICAgICA8aW52ZXN0bWVudENvc3RzIHhzaTp0eXBlPSJlc2RsOlNpbmdsZVZhbHVlIiB2YWx1ZT0iMzQxNy45IiBpZD0iNzgyMjE2NTktNzI5NC00ODMwLTgwMmMtNjdlMzgzNjRiMWYwIj4KICAgICAgICAgICAgPHByb2ZpbGVRdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgaWQ9IjE5ZjYzYjYxLTQ1M2QtNDIxMy1iZGM2LTg2ZjY1NDY4ZmVjOSIgZGVzY3JpcHRpb249IkNvc3QgaW4gRVVSL20iIHBlclVuaXQ9Ik1FVFJFIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiB1bml0PSJFVVJPIi8+CiAgICAgICAgICA8L2ludmVzdG1lbnRDb3N0cz4KICAgICAgICA8L2Nvc3RJbmZvcm1hdGlvbj4KICAgICAgPC9hc3NldD4KICAgICAgPGFzc2V0IHhzaTp0eXBlPSJlc2RsOlBpcGUiIHJlbGF0ZWQ9IlBpcGU0IiBkaWFtZXRlcj0iRE40NTAiIG5hbWU9IlBpcGU0X3JldCIgbGVuZ3RoPSIxODkuNyIgaW5uZXJEaWFtZXRlcj0iMC40NDQ0IiBpZD0iUGlwZTRfcmV0IiBvdXRlckRpYW1ldGVyPSIwLjYzIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6TGluZSI+CiAgICAgICAgICA8cG9pbnQgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIENSUz0iV0dTODQiIGxhdD0iNTIuMDQwMTYyMDk5NzI0ODciIGxvbj0iNC4zMTAxNTg1MTk4MTI2ODQiLz4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDA4NTE3MzM0MjYyMTYiIGxvbj0iNC4zMTI2OTc5ODA3MjUwMzYiLz4KICAgICAgICA8L2dlb21ldHJ5PgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89ImJmNmUwYjZiLWJhYWMtNDY4Yi1hOWJhLWY4Mzk3YmFiZjVkNiIgaWQ9ImQxMjZmNzllLWM0M2UtNGQ5ZC1hN2NlLThmNThiZTYzNDY5NSIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5X3JldCIgbmFtZT0iSW5fcmV0Ii8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6T3V0UG9ydCIgaWQ9ImIzMTg3ZWY5LWNkMGItNGVhOC05MGU0LWVhYjM5ZmEyMjVlOSIgY29ubmVjdGVkVG89ImExYjcxOWNiLWY3MzUtNGEzMC1hMGQyLWNmNjk0NWIzYWZhMSIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5X3JldCIgbmFtZT0iT3V0X3JldCIvPgogICAgICAgIDxjb3N0SW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6Q29zdEluZm9ybWF0aW9uIiBpZD0iMmExNTQ1NmUtZDIzZS00MDY0LThkZWUtYzA1ODhkM2IwNWRjIj4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIzNDE3LjkiIGlkPSIwMjk3Yjk2YS1jMzJjLTQxZjgtODY1My0wMDg1NjU5ZGJhMjkiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiBpZD0iOTg2OWIwZDItZGZhMy00MTQ4LTg2YWItZGRkMWNiNDNiN2M3IiBkZXNjcmlwdGlvbj0iQ29zdCBpbiBFVVIvbSIgcGVyVW5pdD0iTUVUUkUiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIHVuaXQ9IkVVUk8iLz4KICAgICAgICAgIDwvaW52ZXN0bWVudENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6UGlwZSIgcmVsYXRlZD0iUGlwZTUiIGRpYW1ldGVyPSJETjQ1MCIgbmFtZT0iUGlwZTVfcmV0IiBsZW5ndGg9IjI0NC42IiBpbm5lckRpYW1ldGVyPSIwLjQ0NDQiIGlkPSJQaXBlNV9yZXQiIG91dGVyRGlhbWV0ZXI9IjAuNjMiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpMaW5lIj4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wMzg4ODgzOTQxOTkzNzUiIGxvbj0iNC4zMTQ1MDUxNjI4NTAxODgiLz4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDA4Mjg2MzU4MTg5NzYiIGxvbj0iNC4zMTI4MjY2NTY5NDg1NzkiLz4KICAgICAgICA8L2dlb21ldHJ5PgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89IjU5Y2NkZGRjLTg5M2ItNDE1Mi04YmM0LTAxNjhlN2U3NGJmMyIgaWQ9IjJiN2MzYWNiLTY5YTctNDk3ZC1hNzJmLWI5OGRiMTg5ODQxYyIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5X3JldCIgbmFtZT0iSW5fcmV0Ii8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6T3V0UG9ydCIgaWQ9IjRiMzk3M2FiLTZlNGItNDhhZi05NDdkLTUyYzZkMzBmMjBlYSIgY29ubmVjdGVkVG89ImExYjcxOWNiLWY3MzUtNGEzMC1hMGQyLWNmNjk0NWIzYWZhMSIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5X3JldCIgbmFtZT0iT3V0X3JldCIvPgogICAgICAgIDxjb3N0SW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6Q29zdEluZm9ybWF0aW9uIiBpZD0iMzg3ZWI0NTgtNGUzZS00ZTBkLWJmMWMtMGNhMmQ3N2FhNGRkIj4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIzNDE3LjkiIGlkPSJiNzhhYzhhNy05ZDBlLTQ2MDMtODIxYi1mZWJmNThiNDhiYjMiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiBpZD0iZDY1NDc4MDEtMGViNy00ZWQ0LTk1OTctMWU3OWNjMDkzNjIyIiBkZXNjcmlwdGlvbj0iQ29zdCBpbiBFVVIvbSIgcGVyVW5pdD0iTUVUUkUiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIHVuaXQ9IkVVUk8iLz4KICAgICAgICAgIDwvaW52ZXN0bWVudENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6UGlwZSIgcmVsYXRlZD0iUGlwZTYiIGRpYW1ldGVyPSJETjQ1MCIgbmFtZT0iUGlwZTZfcmV0IiBsZW5ndGg9IjE3Ni42IiBpbm5lckRpYW1ldGVyPSIwLjQ0NDQiIGlkPSJQaXBlNl9yZXQiIG91dGVyRGlhbWV0ZXI9IjAuNjMiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpMaW5lIj4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wMzgxMDMwMzQzNjI5MiIgbG9uPSI0LjMxMjE3NDU3NTk5NjczMiIvPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBDUlM9IldHUzg0IiBsYXQ9IjUyLjAzODg0MjE5Njk0Mzg5IiBsb249IjQuMzE0NDYyMTA1MTI0OTU1Ii8+CiAgICAgICAgPC9nZW9tZXRyeT4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSI5YzAyNWIxOS01N2QxLTQzYTgtYjJlOC1kYjNlNjg0NzU2ZjIiIGlkPSI1Y2QwZjJlMC1kNDU2LTQ5MDktYTgxYy00YjMxMmIxYmU4NTciIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOV9yZXQiIG5hbWU9IkluX3JldCIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSIyMDQ1YWNhOS00ZTUwLTQyZWMtOTlkZS1mYmNmZmE2MjdhODYiIGNvbm5lY3RlZFRvPSJmMzZiOTc2Ny04ZTY0LTQ3NDQtOGNkMC0wOGFjYjJhZTg3M2IiIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOV9yZXQiIG5hbWU9Ik91dF9yZXQiLz4KICAgICAgICA8Y29zdEluZm9ybWF0aW9uIHhzaTp0eXBlPSJlc2RsOkNvc3RJbmZvcm1hdGlvbiIgaWQ9ImNiYmI3NGJhLWJhNmYtNGYxNy1hNzhmLTNiM2MwN2NlNTMxZCI+CiAgICAgICAgICA8aW52ZXN0bWVudENvc3RzIHhzaTp0eXBlPSJlc2RsOlNpbmdsZVZhbHVlIiB2YWx1ZT0iMzQxNy45IiBpZD0iYWU1ZjRmNWYtMTMyMy00YTNiLTk4YzgtZmFjYTMyMWEwMGM3Ij4KICAgICAgICAgICAgPHByb2ZpbGVRdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgaWQ9IjE4NTcwYjIwLWI4MjAtNDNkMC05NTJhLWI2ZWFmMTY2YzYzOSIgZGVzY3JpcHRpb249IkNvc3QgaW4gRVVSL20iIHBlclVuaXQ9Ik1FVFJFIiBwaHlzaWNhbFF1YW50aXR5PSJDT1NUIiB1bml0PSJFVVJPIi8+CiAgICAgICAgICA8L2ludmVzdG1lbnRDb3N0cz4KICAgICAgICA8L2Nvc3RJbmZvcm1hdGlvbj4KICAgICAgPC9hc3NldD4KICAgICAgPGFzc2V0IHhzaTp0eXBlPSJlc2RsOkhlYXRQcm9kdWNlciIgcG93ZXI9IjI1MDAwMDAuMCIgbmFtZT0iSGVhdFByb2R1Y2VyXzIiIGlkPSJkYTAwZGRmYy1jZmE0LTRmMjEtYjViZS03YzY5ZDJiZjUzYmIiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbG9uPSI0LjMxMTcyNjA5MzI5MjIzNyIgQ1JTPSJXR1M4NCIgbGF0PSI1Mi4wNDQ4NzYyMTY2NDEwMyIvPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOk91dFBvcnQiIGlkPSI4ODZlNTQzMC1iZWMxLTQ0ZTMtYmFiNi0yMjFjNDUxOGM4MTAiIGNvbm5lY3RlZFRvPSJiYmZlZDgzMC0wNzFkLTRkMDItYmRkZC1lNzA5MjQ3YzgzMzciIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iT3V0Ii8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6SW5Qb3J0IiBjb25uZWN0ZWRUbz0iZGY2Zjg5ZDAtNzg3Mi00ODkxLTkzNGYtZGU0MDdmNmFhMTQyIiBpZD0iYzdlZDg5MTUtZGRkMC00N2Y4LTkzZDYtMWRhYmZiNWQzMjBiIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJJbiIvPgogICAgICAgIDxjb3N0SW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6Q29zdEluZm9ybWF0aW9uIiBpZD0iZDU5ZmUwYzQtNTE1Ni00ZGNmLWIyNTktNmFjNjg1NTI0MWM2Ij4KICAgICAgICAgIDx2YXJpYWJsZU9wZXJhdGlvbmFsQ29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSI2LjAiIGlkPSI3YTc4OWI5NS05M2JiLTQxNWItYWJiZC00ZWNiYjZhZDYwYzkiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRUeXBlIiBpZD0iYzUyMzM0YzktYmM1ZC00MWY0LWI5M2QtMTBlN2I3NjlmMjgxIiBkZXNjcmlwdGlvbj0iQ29zdCBpbiBFVVIvTVdoIiBwZXJVbml0PSJXQVRUSE9VUiIgcGVyTXVsdGlwbGllcj0iTUVHQSIgdW5pdD0iRVVSTyIgcGh5c2ljYWxRdWFudGl0eT0iQ09TVCIvPgogICAgICAgICAgPC92YXJpYWJsZU9wZXJhdGlvbmFsQ29zdHM+CiAgICAgICAgICA8aW5zdGFsbGF0aW9uQ29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIxMDAwMDAuMCIgaWQ9IjJiMmY0YjkzLTMyYzctNGYyMC05NzIzLTU5MDBjYzc2ZmUyMCI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSJiMDk3NWVlZi0yZTEzLTRiN2YtYjg5YS02NGE0NzE4M2U4Y2MiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUiIgdW5pdD0iRVVSTyIvPgogICAgICAgICAgPC9pbnN0YWxsYXRpb25Db3N0cz4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSIxMDAwMDAuMCIgaWQ9IjM2MzNjZDA5LTlmODctNGQ4ZC1hNWY4LTA0MzFiYWI5NTc2ZCI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSI4OGEwMDlmZi0wZWViLTQ4YjEtOWViMy02MGRiYTA0YjNlNzkiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUi9NVyIgcGVyVW5pdD0iV0FUVCIgcGVyTXVsdGlwbGllcj0iTUVHQSIgdW5pdD0iRVVSTyIgcGh5c2ljYWxRdWFudGl0eT0iQ09TVCIvPgogICAgICAgICAgPC9pbnZlc3RtZW50Q29zdHM+CiAgICAgICAgICA8bWFyZ2luYWxDb3N0cyB4c2k6dHlwZT0iZXNkbDpTaW5nbGVWYWx1ZSIgdmFsdWU9IjEuMCIgaWQ9IjNmNzNiZDI2LWI5MjMtNGUyYS04ZjhlLTQzNWM4YTc4M2Q4ZCI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSJhMTA4NmE3Ny1hMmQxLTRhOWItYTZmMi1hZGYwZTQzODBlY2EiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIGRlc2NyaXB0aW9uPSJDb3N0IGluIEVVUiIgdW5pdD0iRVVSTyIvPgogICAgICAgICAgPC9tYXJnaW5hbENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6UGlwZSIgZGlhbWV0ZXI9IkRONDUwIiBuYW1lPSJQaXBlX2Y2ZTUiIGxlbmd0aD0iMjM5LjciIGlubmVyRGlhbWV0ZXI9IjAuNDQ0NCIgaWQ9ImY2ZTVhNzYwLTAxZDUtNDM0MS1iZjE1LWI4ZDMzYjdiZWE1MCIgb3V0ZXJEaWFtZXRlcj0iMC42MyI+CiAgICAgICAgPGdlb21ldHJ5IHhzaTp0eXBlPSJlc2RsOkxpbmUiIENSUz0iV0dTODQiPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsb249IjQuMzExNzI2MDkzMjkyMjM3IiBsYXQ9IjUyLjA0NDg3NjIxNjY0MTAzIi8+CiAgICAgICAgICA8cG9pbnQgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxvbj0iNC4zMTE2OTUyNDc4ODg1NjYiIGxhdD0iNTIuMDQyNzIwODYxOTM4ODU0Ii8+CiAgICAgICAgPC9nZW9tZXRyeT4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSI4ODZlNTQzMC1iZWMxLTQ0ZTMtYmFiNi0yMjFjNDUxOGM4MTAiIGlkPSJiYmZlZDgzMC0wNzFkLTRkMDItYmRkZC1lNzA5MjQ3YzgzMzciIGNhcnJpZXI9IjdiMzJlMjg3LWQ3NzUtNDgwYy1iMzE3LTY0ZmZkYWNmMTJjOSIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iZjk2NmJhZGUtMWZhZC00NTNmLThlYzItNDA2MmVjNzBiYzdiIiBjb25uZWN0ZWRUbz0iNTE4NTI4NjEtYWVlYi00NjFmLWI4ZWMtMDhmMDAwYWJjNmRkIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9Ik91dCIvPgogICAgICAgIDxtYXRlcmlhbCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlciIgY29tcG91bmRUeXBlPSJMQVlFUkVEIj4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMDA2MyI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjUyLjE1IiBuYW1lPSJzdGVlbCIgaWQ9IjM3MWMxZDcyLWRlMzUtNDU1OS05YjBlLTQ3MTcyZTVkMWQ4MyIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjA4MDUiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSIwLjAyNyIgbmFtZT0iUFVSIiBpZD0iZGYzMGJkMzctMmZjNC00OTkzLTgyOGYtMWI3Y2YxZTgyMDJjIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMDA2Ij4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iMC40IiBuYW1lPSJIRFBFIiBpZD0iZjUzZGUzN2ItYTczNS00YjBkLWIyMjYtYTZiNzIyMDI5YTAxIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICA8L21hdGVyaWFsPgogICAgICAgIDxkYXRhU291cmNlIHhzaTp0eXBlPSJlc2RsOkRhdGFTb3VyY2UiIGF0dHJpYnV0aW9uPSJodHRwczovL3d3dy5sb2dzdG9yLmNvbS9tZWRpYS82NTA2L3Byb2R1Y3QtY2F0YWxvZ3VlLXVrLTIwMjAwMy5wZGYiIG5hbWU9IkxvZ3N0b3IgUHJvZHVjdCBDYXRhbG9ndWUgVmVyc2lvbiAyMDIwLjAzIi8+CiAgICAgICAgPGNvc3RJbmZvcm1hdGlvbiB4c2k6dHlwZT0iZXNkbDpDb3N0SW5mb3JtYXRpb24iIGlkPSIyMmZiMmU4NS03YTgxLTQzNzEtYjZhYi02ZDUxMDFiOGNhNDUiPgogICAgICAgICAgPGludmVzdG1lbnRDb3N0cyB4c2k6dHlwZT0iZXNkbDpTaW5nbGVWYWx1ZSIgbmFtZT0iQ29tYmluZWQgaW52ZXN0bWVudCBhbmQgaW5zdGFsbGF0aW9uIGNvc3RzIiBpZD0iYTQwMTY1ZTgtODhiZC00OWI5LTgxZDktMjk4ODEyYWMwMTcwIiB2YWx1ZT0iMzQxNy45Ij4KICAgICAgICAgICAgPHByb2ZpbGVRdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgaWQ9ImQwYWViYzc2LTIwMWItNGIyZC04MWZlLTU1MjY5ZmNlZmUzYiIgZGVzY3JpcHRpb249IkNvc3RzIGluIEVVUi9tIiBwZXJVbml0PSJNRVRSRSIgcGh5c2ljYWxRdWFudGl0eT0iQ09TVCIgdW5pdD0iRVVSTyIvPgogICAgICAgICAgPC9pbnZlc3RtZW50Q29zdHM+CiAgICAgICAgPC9jb3N0SW5mb3JtYXRpb24+CiAgICAgIDwvYXNzZXQ+CiAgICAgIDxhc3NldCB4c2k6dHlwZT0iZXNkbDpQaXBlIiBkaWFtZXRlcj0iRE40NTAiIG5hbWU9IlBpcGVfZjZlNV9yZXQiIGxlbmd0aD0iMjMzLjkiIGlubmVyRGlhbWV0ZXI9IjAuNDQ0NCIgaWQ9IjBkYjkxNTE1LTQxOGEtNGJjYi05ZDk5LTkwNDdjMWNhOGJkZiIgb3V0ZXJEaWFtZXRlcj0iMC42MyI+CiAgICAgICAgPGdlb21ldHJ5IHhzaTp0eXBlPSJlc2RsOkxpbmUiIENSUz0iV0dTODQiPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsb249IjQuMzExMDc0NDAyNjY1NjQ5IiBsYXQ9IjUyLjA0MjgxMDg2MjAyODg1Ii8+CiAgICAgICAgICA8cG9pbnQgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxvbj0iNC4zMTE3MjYwOTMyOTIyMzciIGxhdD0iNTIuMDQ0ODc2MjE2NjQxMDMiLz4KICAgICAgICA8L2dlb21ldHJ5PgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89IjI5MTNlNjQ1LWIwMjctNDI5ZS1iZjVkLTIyYWNlOTZhMzlmYSIgaWQ9IjQyZTlmODZiLWVhOTYtNDk5Mi1iZjNmLTljYmFlOGE0YTM5YyIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5X3JldCIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iZGY2Zjg5ZDAtNzg3Mi00ODkxLTkzNGYtZGU0MDdmNmFhMTQyIiBjb25uZWN0ZWRUbz0iYzdlZDg5MTUtZGRkMC00N2Y4LTkzZDYtMWRhYmZiNWQzMjBiIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJPdXQiLz4KICAgICAgICA8bWF0ZXJpYWwgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXIiIGNvbXBvdW5kVHlwZT0iTEFZRVJFRCI+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjAwNjMiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSI1Mi4xNSIgbmFtZT0ic3RlZWwiIGlkPSIzNzFjMWQ3Mi1kZTM1LTQ1NTktOWIwZS00NzE3MmU1ZDFkODMiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wODA1Ij4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iMC4wMjciIG5hbWU9IlBVUiIgaWQ9ImRmMzBiZDM3LTJmYzQtNDk5My04MjhmLTFiN2NmMWU4MjAyYyIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjAwNiI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjAuNCIgbmFtZT0iSERQRSIgaWQ9ImY1M2RlMzdiLWE3MzUtNGIwZC1iMjI2LWE2YjcyMjAyOWEwMSIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgPC9tYXRlcmlhbD4KICAgICAgICA8ZGF0YVNvdXJjZSB4c2k6dHlwZT0iZXNkbDpEYXRhU291cmNlIiBhdHRyaWJ1dGlvbj0iaHR0cHM6Ly93d3cubG9nc3Rvci5jb20vbWVkaWEvNjUwNi9wcm9kdWN0LWNhdGFsb2d1ZS11ay0yMDIwMDMucGRmIiBuYW1lPSJMb2dzdG9yIFByb2R1Y3QgQ2F0YWxvZ3VlIFZlcnNpb24gMjAyMC4wMyIvPgogICAgICAgIDxjb3N0SW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6Q29zdEluZm9ybWF0aW9uIiBpZD0iN2NiYzljMzItM2Q3ZC00NGUxLWFiNzMtNTk4NDU5Mjk0ZjBjIj4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIG5hbWU9IkNvbWJpbmVkIGludmVzdG1lbnQgYW5kIGluc3RhbGxhdGlvbiBjb3N0cyIgaWQ9ImE0MDE2NWU4LTg4YmQtNDliOS04MWQ5LTI5ODgxMmFjMDE3MCIgdmFsdWU9IjM0MTcuOSI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSJkMGFlYmM3Ni0yMDFiLTRiMmQtODFmZS01NTI2OWZjZWZlM2IiIGRlc2NyaXB0aW9uPSJDb3N0cyBpbiBFVVIvbSIgcGVyVW5pdD0iTUVUUkUiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIHVuaXQ9IkVVUk8iLz4KICAgICAgICAgIDwvaW52ZXN0bWVudENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6UGlwZSIgZGlhbWV0ZXI9IkRONDAwIiBuYW1lPSJQaXBlX2IyYTQiIG91dGVyRGlhbWV0ZXI9IjAuNjMiIGlkPSJiMmE0MTQ5Yi1hYjVjLTQ2ZmItODA3ZS1hYjU2N2Q4NTljMmEiIGlubmVyRGlhbWV0ZXI9IjAuMzkzOCIgbGVuZ3RoPSIyNTkuNSI+CiAgICAgICAgPGdlb21ldHJ5IHhzaTp0eXBlPSJlc2RsOkxpbmUiIENSUz0iV0dTODQiPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsb249IjQuMzExNjk1MjQ3ODg4NTY2IiBsYXQ9IjUyLjA0MjcyMDg2MTkzODg1NCIvPgogICAgICAgICAgPHBvaW50IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsb249IjQuMzE0OTQ0NzQ0MTEwMTA4IiBsYXQ9IjUyLjA0MzkyNTk5MjcwNjE5Ii8+CiAgICAgICAgPC9nZW9tZXRyeT4KICAgICAgICA8bWF0ZXJpYWwgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXIiIGNvbXBvdW5kVHlwZT0iTEFZRVJFRCI+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjAwNjMiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSI1Mi4xNSIgaWQ9ImFlMzJkMzBiLTRlMGQtNDQ3MC1hNGYwLTRiYTdiZDI1ODA3MCIgbmFtZT0ic3RlZWwiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4xMDUyIj4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iMC4wMjciIGlkPSI1ZDU5MWI1OC0yY2Y4LTRkOTQtOTFlYi1iZTc3M2UxYzI1ZWUiIG5hbWU9IlBVUiIvPgogICAgICAgICAgPC9jb21wb25lbnQ+CiAgICAgICAgICA8Y29tcG9uZW50IHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyQ29tcG9uZW50IiBsYXllcldpZHRoPSIwLjAwNjYiPgogICAgICAgICAgICA8bWF0dGVyIHhzaTp0eXBlPSJlc2RsOk1hdGVyaWFsIiB0aGVybWFsQ29uZHVjdGl2aXR5PSIwLjQiIGlkPSI4YTAyNzljYy1hZmJmLTQ2ZmItYTU5MC0zMzk2MGNlMzA2MTMiIG5hbWU9IkhEUEUiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgIDwvbWF0ZXJpYWw+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6SW5Qb3J0IiBjb25uZWN0ZWRUbz0iYzBlYWM0ZGItZjVkYS00N2YzLTgyMDItODQzOGQwMDBiZDMyIiBpZD0iMmNjNzczZWUtYjU2Mi00ZTFmLWExZDEtYTI2NTZlMTA5MDdkIiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzkiIG5hbWU9IkluIi8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6T3V0UG9ydCIgaWQ9IjAxYzg4MmY3LWVjMTUtNGQzNC05ZjQzLTgxODE5NzJmMjUwMCIgY29ubmVjdGVkVG89IjZiODNlNzRkLTVmZjEtNGZmYS04YmQ0LWRlMTE1NGI1NDFlMiIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5IiBuYW1lPSJPdXQiLz4KICAgICAgICA8ZGF0YVNvdXJjZSB4c2k6dHlwZT0iZXNkbDpEYXRhU291cmNlIiBhdHRyaWJ1dGlvbj0iaHR0cHM6Ly93d3cubG9nc3Rvci5jb20vbWVkaWEvNjUwNi9wcm9kdWN0LWNhdGFsb2d1ZS11ay0yMDIwMDMucGRmIiBuYW1lPSJMb2dzdG9yIFByb2R1Y3QgQ2F0YWxvZ3VlIFZlcnNpb24gMjAyMC4wMyIvPgogICAgICAgIDxjb3N0SW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6Q29zdEluZm9ybWF0aW9uIiBpZD0iZmFjYjYxMGEtMWJiYy00NTAzLThlMDItOWE3Njc1NThlY2RmIj4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIG5hbWU9IkNvbWJpbmVkIGludmVzdG1lbnQgYW5kIGluc3RhbGxhdGlvbiBjb3N0cyIgaWQ9IjU2NmQzZjI2LWY4NWEtNDhiNC1iMDZhLTVmZDYyYWM2ZmE2MSIgdmFsdWU9IjI4NDAuNiI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSI1YjEwODVlNC01NjQyLTRjMWQtYWE3Yy1iZmI3NzkzZDRlNjQiIGRlc2NyaXB0aW9uPSJDb3N0cyBpbiBFVVIvbSIgcGVyVW5pdD0iTUVUUkUiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIHVuaXQ9IkVVUk8iLz4KICAgICAgICAgIDwvaW52ZXN0bWVudENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6UGlwZSIgZGlhbWV0ZXI9IkRONDAwIiBuYW1lPSJQaXBlX2IyYTRfcmV0IiBvdXRlckRpYW1ldGVyPSIwLjYzIiBpZD0iYTUyNzYwMzAtYTM0Ny00NWI1LTliOGItMWNkYTNhZGE0NTkwIiBpbm5lckRpYW1ldGVyPSIwLjM5MzgiIGxlbmd0aD0iMjU5LjEiPgogICAgICAgIDxnZW9tZXRyeSB4c2k6dHlwZT0iZXNkbDpMaW5lIiBDUlM9IldHUzg0Ij4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbG9uPSI0LjMxNDUwNDg2MTgzMTY2NiIgbGF0PSI1Mi4wNDQwMzE1NzQxNDEwNjYiLz4KICAgICAgICAgIDxwb2ludCB4c2k6dHlwZT0iZXNkbDpQb2ludCIgbG9uPSI0LjMxMTE4OTY1MTQ4OTI1OSIgbGF0PSI1Mi4wNDI5MDMxNTk2NDM5MiIvPgogICAgICAgIDwvZ2VvbWV0cnk+CiAgICAgICAgPG1hdGVyaWFsIHhzaTp0eXBlPSJlc2RsOkNvbXBvdW5kTWF0dGVyIiBjb21wb3VuZFR5cGU9IkxBWUVSRUQiPgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wMDYzIj4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iNTIuMTUiIGlkPSJhZTMyZDMwYi00ZTBkLTQ0NzAtYTRmMC00YmE3YmQyNTgwNzAiIG5hbWU9InN0ZWVsIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICAgIDxjb21wb25lbnQgeHNpOnR5cGU9ImVzZGw6Q29tcG91bmRNYXR0ZXJDb21wb25lbnQiIGxheWVyV2lkdGg9IjAuMTA1MiI+CiAgICAgICAgICAgIDxtYXR0ZXIgeHNpOnR5cGU9ImVzZGw6TWF0ZXJpYWwiIHRoZXJtYWxDb25kdWN0aXZpdHk9IjAuMDI3IiBpZD0iNWQ1OTFiNTgtMmNmOC00ZDk0LTkxZWItYmU3NzNlMWMyNWVlIiBuYW1lPSJQVVIiLz4KICAgICAgICAgIDwvY29tcG9uZW50PgogICAgICAgICAgPGNvbXBvbmVudCB4c2k6dHlwZT0iZXNkbDpDb21wb3VuZE1hdHRlckNvbXBvbmVudCIgbGF5ZXJXaWR0aD0iMC4wMDY2Ij4KICAgICAgICAgICAgPG1hdHRlciB4c2k6dHlwZT0iZXNkbDpNYXRlcmlhbCIgdGhlcm1hbENvbmR1Y3Rpdml0eT0iMC40IiBpZD0iOGEwMjc5Y2MtYWZiZi00NmZiLWE1OTAtMzM5NjBjZTMwNjEzIiBuYW1lPSJIRFBFIi8+CiAgICAgICAgICA8L2NvbXBvbmVudD4KICAgICAgICA8L21hdGVyaWFsPgogICAgICAgIDxwb3J0IHhzaTp0eXBlPSJlc2RsOkluUG9ydCIgY29ubmVjdGVkVG89IjExZTM1ODliLTlhMmQtNDk3ZS1iYzJmLWZmZjNlMzRkNmVmZSIgaWQ9ImNhZDE2MjUzLWYwMDEtNDdmMC1hZWIwLTFlNTMyZjUyMTNlNyIgY2Fycmllcj0iN2IzMmUyODctZDc3NS00ODBjLWIzMTctNjRmZmRhY2YxMmM5X3JldCIgbmFtZT0iSW4iLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpPdXRQb3J0IiBpZD0iNmNjYjAwNWMtNDVkNC00MjIwLTkyODYtY2M4Zjc3YjAzZWM2IiBjb25uZWN0ZWRUbz0iNzg5MzEyNWQtZDgyZi00ZmU4LWFhZWEtNWZiNmFmZWNjNjM1IiBjYXJyaWVyPSI3YjMyZTI4Ny1kNzc1LTQ4MGMtYjMxNy02NGZmZGFjZjEyYzlfcmV0IiBuYW1lPSJPdXQiLz4KICAgICAgICA8ZGF0YVNvdXJjZSB4c2k6dHlwZT0iZXNkbDpEYXRhU291cmNlIiBhdHRyaWJ1dGlvbj0iaHR0cHM6Ly93d3cubG9nc3Rvci5jb20vbWVkaWEvNjUwNi9wcm9kdWN0LWNhdGFsb2d1ZS11ay0yMDIwMDMucGRmIiBuYW1lPSJMb2dzdG9yIFByb2R1Y3QgQ2F0YWxvZ3VlIFZlcnNpb24gMjAyMC4wMyIvPgogICAgICAgIDxjb3N0SW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6Q29zdEluZm9ybWF0aW9uIiBpZD0iMGRkNTcxY2ItYjdkYS00ZGU0LWJkZWMtNmFkNWE0MjMzNTU4Ij4KICAgICAgICAgIDxpbnZlc3RtZW50Q29zdHMgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIG5hbWU9IkNvbWJpbmVkIGludmVzdG1lbnQgYW5kIGluc3RhbGxhdGlvbiBjb3N0cyIgaWQ9IjU2NmQzZjI2LWY4NWEtNDhiNC1iMDZhLTVmZDYyYWM2ZmE2MSIgdmFsdWU9IjI4NDAuNiI+CiAgICAgICAgICAgIDxwcm9maWxlUXVhbnRpdHlBbmRVbml0IHhzaTp0eXBlPSJlc2RsOlF1YW50aXR5QW5kVW5pdFR5cGUiIGlkPSI1YjEwODVlNC01NjQyLTRjMWQtYWE3Yy1iZmI3NzkzZDRlNjQiIGRlc2NyaXB0aW9uPSJDb3N0cyBpbiBFVVIvbSIgcGVyVW5pdD0iTUVUUkUiIHBoeXNpY2FsUXVhbnRpdHk9IkNPU1QiIHVuaXQ9IkVVUk8iLz4KICAgICAgICAgIDwvaW52ZXN0bWVudENvc3RzPgogICAgICAgIDwvY29zdEluZm9ybWF0aW9uPgogICAgICA8L2Fzc2V0PgogICAgPC9hcmVhPgogIDwvaW5zdGFuY2U+CjwvZXNkbDpFbmVyZ3lTeXN0ZW0+Cg=="
-
-print("Application started")
-
-app = Celery(
- "omotes",
- broker="amqp://user:bitnami@rabbitmq",
- backend="rpc://user:bitnami@rabbitmq",
- worker_prefetch_multiplier=1,
- task_acks_late=True,
- task_reject_on_worker_lost=True,
- # task_serializer="pickle",
- # result_serializer="pickle",
- # accept_content=["application/json", "application/x-python-serialize"],
-)
-print("Celery started")
-
-
-def task_monitor():
- def on_event(event):
- print("EVENT HAPPENED: ", event["type"])
-
- def on_progress_update(event):
- print("################################ TASK PROGRESS UPDATED: ", event["progress"]["fraction"] * 100)
-
- while True:
- try:
- with app.connection() as conn:
- recv = app.events.Receiver(
- conn,
- handlers={
- "task-failed": on_event,
- "task-succeeded": on_event,
- "task-sent": on_event,
- "task-received": on_event,
- "task-revoked": on_event,
- "task-started": on_event,
- "task-progress-update": on_progress_update,
- # OR: '*' : on_event
- },
- )
- recv.capture(limit=None, timeout=None)
- except (KeyboardInterrupt, SystemExit):
- print("EXCEPTION KEYBOARD INTERRUPT")
- sys.exit()
-
-
-t = threading.Thread(target=task_monitor)
-t.daemon = True
-t.start()
-
-q_name = "grow"
-optimizer_job_id: uuid4 = uuid4()
-
-optimizer_task = app.signature("optimizer-task", (optimizer_job_id, input_esdl_no_influx), queue=q_name).delay()
-
-test_simulator = False # takes a long time
-simulator_task = None
-if test_simulator:
- simulator_job_id: uuid4 = uuid4()
- simulator_task = app.signature("simulator-task", (simulator_job_id, input_esdl_no_influx), queue=q_name).delay()
-
-print("waiting for tasks...")
-
-
-def print_result(result, task_name):
- if "error_message" in result:
- print(f"Error message: {result['error_message']}, exit code: {result['exit_code']} from task: {task_name}")
- print(f"logs: {result['logs']} from task: {task_name}")
- else:
- print(f"Received logs: '{result['logs']}' from task: {task_name}")
- print(f"Output ESDL: '{result['output_esdl']}' from task: {task_name}")
-
-
-print_result(jsonpickle.decode(optimizer_task.get()), "optimizer-task")
-
-if simulator_task:
- print("waiting for simulator task...")
- print_result(jsonpickle.decode(simulator_task.get()), "simulator-task")
diff --git a/pyproject.toml b/pyproject.toml
index 020ca7e..0b8c830 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,7 @@
[project]
-name = "omotes-grow-worker"
-dynamic = ["version"]
-authors = [
- { name = "Sebastiaan la Fleur", email = "sebastiaan.lafleur@tno.nl" },
- { name = "Mark Vrijlandt", email = "mark.vrijlandt@tno.nl" },
-]
+name = "omotes-optimizer-worker"
+version = "0.0.1"
+authors = [{ name = "Mark Vrijlandt", email = "mark.vrijlandt@tno.nl" }]
description = "Nieuwe Warmte Nu - Optimizer Worker"
classifiers = [
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
@@ -21,31 +18,24 @@ classifiers = [
]
readme = "README.md"
license = { file = "LICENSE" }
-requires-python = ">=3.10"
+requires-python = "==3.11.*"
dependencies = [
"python-dotenv ~= 1.0.0",
"mesido ~= 0.1.20.3",
- "omotes-sdk-python ~= 4.3.6",
+ "omotes-sdk-python==5.0.1",
+ "pyesdl~=26.7",
]
-[project.optional-dependencies]
+[dependency-groups]
dev = [
"setuptools ~= 75.6.0",
"wheel ~= 0.45.1",
- "setuptools-git-versioning >= 2.0, < 3",
- "black ~= 24.10.0",
- "flake8 == 7.1.1",
- "flake8-pyproject ~= 1.2.3",
- "flake8-docstrings ~= 1.7.0",
- "flake8-quotes ~= 3.4.0",
- "flake8-bugbear ~= 24.10.31",
- "flake8-mock ~= 0.4",
- "flake8-tuple ~= 0.4.1",
+ "pip-tools ~= 7.4.0",
+ "ruff ~= 0.15.22",
+ "ty ~= 0.0.61",
"pytest ~= 8.3.4",
"pytest-cov ~= 6.0.0",
- "mypy ~= 1.13.0",
- "isort == 5.13.2",
"build ~= 1.2.2",
]
@@ -57,58 +47,46 @@ repository = "https://github.com/Nieuwe-Warmte-Nu/optimizer-worker"
changelog = "https://github.com/Nieuwe-Warmte-Nu/optimizer-worker/blob/main/CHANGELOG.md"
[build-system]
-build-backend = "setuptools.build_meta"
-requires = [
- "setuptools ~= 75.6.0",
- "wheel ~= 0.45.1",
- "setuptools-git-versioning >= 2.0, < 3",
-]
+requires = ["uv_build>=0.11.29,<0.12"]
+build-backend = "uv_build"
-[tool.setuptools-git-versioning]
-enabled = true
-starting_version = "0.0.1"
+[tool.uv.build-backend]
+module-name = "omotes_optimizer_worker"
[tool.pytest.ini_options]
-addopts = "--cov=grow_worker --cov-report html --cov-report term-missing --cov-fail-under 30"
+pythonpath = ["src"]
+addopts = "--cov=src --cov-report html --cov-report term-missing --cov-fail-under 50"
[tool.coverage.run]
source = ["src"]
-[tool.flake8]
-exclude = ['.venv/*', 'venv/*', 'doc/*']
+[tool.ruff]
+line-length = 120
+preview = true
+
+[tool.ruff.lint]
+select = [
+ "E", # pycodestyle
+ "W",
+ "F", # Pyflakes
+ "UP", # pyupgrade
+ "B", # flake8-bugbear
+ "SIM", # flake8-simplify
+ "I", # isort
+ "D", # pydocstyle
+ "ANN", # flake8-annotations
+ "DOC", # flake8-docstrings
+]
ignore = [
- 'Q000', # Remove bad quotes
- 'D401', # Docstring First line should be imperative
- 'E203', # Space before colon (not PEP-8 compliant, and conflicts with black)
- 'C408', # Suggestion to use dict() over {}
- 'W503', # Starting lines with operators.
- 'D104', # Missing docstring in public package
- 'D100', # Missing docstring in public module
+ "D100", # Missing docstring in public module
+ "D104", # Missing docstring in public package
]
-per-file-ignores = ['__init__.py:F401', './unit_test/*:D100,D101,D102,D103']
-max-line-length = 100
-count = true
-
-[tool.black]
-line-length = 100
-
-[tool.isort]
-profile = "black"
+exclude = ["justfile", ".editorconfig"]
-[tool.mypy]
-python_version = "3.10"
-warn_return_any = true
-warn_unused_configs = true
-disallow_untyped_defs = true
-disallow_incomplete_defs = true
-exclude = ['.venv/*', 'venv/*', 'doc/*', 'ci/*']
+[tool.ruff.lint.pydocstyle]
+convention = "google"
-# mypy per-module options:
-[[tool.mypy.overrides]]
-module = "unit_test.*"
-check_untyped_defs = true
-ignore_missing_imports = true
-
-[[tool.mypy.overrides]]
-module = "mesido.*"
-ignore_missing_imports = true
+[tool.ruff.lint.per-file-ignores]
+"src/env.py" = [
+ "DOC201", # Simple getter methods in EnvSettings use concise one-line docstrings.
+]
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index ce36bda..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,169 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.10
-# by the following command:
-#
-# pip-compile --output-file=requirements.txt pyproject.toml
-#
-aio-pika==9.4.3
- # via omotes-sdk-python
-aiormq==6.8.1
- # via aio-pika
-amqp==5.3.1
- # via kombu
-antlr4-python3-runtime==4.13.2
- # via pymoca
-billiard==4.2.4
- # via celery
-casadi-gil-comp==3.6.7
- # via
- # mesido
- # rtc-tools-gil-comp
-celery==5.6.3
- # via omotes-sdk-python
-certifi==2026.6.17
- # via requests
-charset-normalizer==3.4.9
- # via requests
-click==8.4.2
- # via
- # celery
- # click-didyoumean
- # click-plugins
- # click-repl
-click-didyoumean==0.3.1
- # via celery
-click-plugins==1.1.1.2
- # via celery
-click-repl==0.3.0
- # via celery
-coolprop==6.6.0
- # via mesido
-defusedxml==0.7.1
- # via rtc-tools-gil-comp
-et-xmlfile==2.0.0
- # via openpyxl
-exceptiongroup==1.3.1
- # via celery
-future-fstrings==1.2.0
- # via pyecore
-idna==3.18
- # via
- # requests
- # yarl
-influxdb==5.3.1
- # via
- # mesido
- # pyesdl
-kombu==5.6.2
- # via celery
-lxml==6.1.1
- # via pyecore
-mesido==0.1.20.3
- # via omotes-grow-worker (pyproject.toml)
-msgpack==1.2.1
- # via influxdb
-multidict==6.7.1
- # via yarl
-numpy==1.25.2
- # via
- # casadi-gil-comp
- # pandas
- # pymoca
- # rtc-tools-gil-comp
- # scipy
-omotes-sdk-protocol==1.2.0
- # via omotes-sdk-python
-omotes-sdk-python==4.3.6
- # via omotes-grow-worker (pyproject.toml)
-openpyxl==3.1.2
- # via pyesdl
-ordered-set==4.1.0
- # via pyecore
-packaging==26.2
- # via kombu
-pamqp==3.3.0
- # via
- # aiormq
- # omotes-sdk-python
-pandas==1.5.3
- # via mesido
-prompt-toolkit==3.0.52
- # via click-repl
-propcache==0.5.2
- # via yarl
-protobuf==5.29.6
- # via omotes-sdk-protocol
-psycopg[binary]==3.3.3
- # via pyesdl
-psycopg-binary==3.3.3
- # via
- # psycopg
- # pyesdl
-pyecore==0.13.2
- # via
- # mesido
- # pyesdl
-pyesdl[profiles]==26.7
- # via
- # mesido
- # omotes-sdk-python
-pymoca==0.9.2
- # via
- # mesido
- # rtc-tools-channel-flow
- # rtc-tools-gil-comp
-python-dateutil==2.9.0.post0
- # via
- # celery
- # influxdb
- # pandas
-python-dotenv==1.0.1
- # via omotes-grow-worker (pyproject.toml)
-pytz==2026.2
- # via
- # influxdb
- # pandas
-requests==2.34.2
- # via influxdb
-restrictedpython==8.4
- # via pyecore
-rtc-tools-channel-flow==1.3.1
- # via rtc-tools-gil-comp
-rtc-tools-gil-comp==2.6.1
- # via mesido
-scipy==1.10.1
- # via rtc-tools-gil-comp
-six==1.17.0
- # via
- # influxdb
- # python-dateutil
-streamcapture==1.2.7
- # via omotes-sdk-python
-strenum==0.4.15
- # via mesido
-typing-extensions==4.16.0
- # via
- # exceptiongroup
- # multidict
- # omotes-sdk-python
- # psycopg
-tzdata==2026.3
- # via kombu
-tzlocal==5.4.4
- # via celery
-urllib3==2.7.0
- # via requests
-vine==5.1.0
- # via
- # amqp
- # celery
- # kombu
-wcwidth==0.8.2
- # via prompt-toolkit
-yarl==1.24.2
- # via
- # aio-pika
- # aiormq
-
-# The following packages are considered to be unsafe in a requirements file:
-# setuptools
diff --git a/run.bat b/run.bat
deleted file mode 100644
index 588b6a7..0000000
--- a/run.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-call .\venv\Scripts\activate
-mkdir .\temp\input_files
-mkdir .\temp\output_files
-
-
-set PYTHONPATH=.\src\;%$PYTHONPATH%
-set INPUT_FILES_DIR=.\temp\input_files
-set OUTPUT_FILES_DIR=.\temp\output_files
-python -m optimizer_worker.main
diff --git a/run.sh b/run.sh
deleted file mode 100755
index 4403dae..0000000
--- a/run.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-. .venv/bin/activate
-. ci/linux/_load_dot_env.sh .env
-
-export DIR_TO_ROOT="$PWD"
-
-export GUROBI_HOME="${DIR_TO_ROOT}/gurobi"
-export PATH="${GUROBI_HOME}/bin:$PATH"
-export LD_LIBRARY_PATH="${GUROBI_HOME}/lib"
-export CASADI_GUROBI_VERSION="110"
-export GUROBI_VERSION_URL="11.0.3"
-export GUROBI_VERSION_URL_MAJOR="11.0"
-
-export GUROBI_VERSION="$CASADI_GUROBI_VERSION"
-export GRB_LICENSE_FILE="${DIR_TO_ROOT}/gurobi.lic"
-
-PYTHONPATH="src/" python3 -m grow_worker.worker
diff --git a/run_windows.sh b/run_windows.sh
deleted file mode 100644
index 52b14b4..0000000
--- a/run_windows.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-source ./venv/Scripts/activate
-set -a
-source .env
-set +a
-
-mkdir -p ./temp/input_files
-mkdir -p ./temp/output_files
-
-export INPUT_FILES_DIR=./temp/input_files
-export OUTPUT_FILES_DIR=./temp/output_files
-
-export PYTHONPATH=./src/
-python -m grow_worker.worker
diff --git a/src/grow_worker/__init__.py b/src/grow_worker/__init__.py
deleted file mode 100644
index 47c3204..0000000
--- a/src/grow_worker/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import os
-
-from omotes_sdk import setup_logging, LogLevel
-
-setup_logging(LogLevel.parse(os.environ.get("LOG_LEVEL", "INFO")), "grow_worker")
diff --git a/src/grow_worker/worker.py b/src/grow_worker/worker.py
deleted file mode 100644
index 5a35110..0000000
--- a/src/grow_worker/worker.py
+++ /dev/null
@@ -1,163 +0,0 @@
-import base64
-import logging
-import os
-from pathlib import Path
-from typing import Dict, List, Optional, Tuple, cast
-
-from dotenv import load_dotenv
-from mesido.esdl.esdl_mixin import DBAccessType, ESDLOutputProfilesType
-from mesido.esdl.esdl_parser import ESDLStringParser
-from mesido.esdl.profile_parser import ESDLProfileReader
-from mesido.exceptions import MesidoAssetIssueError
-from omotes_sdk.internal.orchestrator_worker_events.esdl_messages import (
- EsdlMessage,
- MessageSeverity,
-)
-from omotes_sdk.internal.worker.worker import UpdateProgressHandler, initialize_worker
-from omotes_sdk.types import ProtobufDict
-
-from grow_worker.worker_types import (
- GROWProblem,
- GrowTaskType,
- get_problem_function,
- get_problem_type,
- get_solver_class,
-)
-
-logger = logging.getLogger("grow_worker")
-
-load_dotenv() # Load environment variables from .env file
-
-GROW_TASK_TYPES = [GrowTaskType(task_type) for task_type in os.environ["GROW_TASK_TYPE"].split(",")]
-
-
-class EarlySystemExit(Exception):
- """Wrapper for `SystemExit` exception.
-
- To ensure that the worker process does not shut down but rather handles the `SystemExit` as an
- error
- """
-
- ...
-
-
-def grow_worker_task(
- input_esdl: str,
- workflow_config: ProtobufDict,
- update_progress_handler: UpdateProgressHandler,
- workflow_type_name: str,
-) -> Tuple[Optional[str], List[EsdlMessage]]:
- """Run the grow worker task and run configured specific problem type for this worker instance.
-
- Note: Be careful! This spawns within a subprocess and gains a copy of memory from parent
- process. You cannot open sockets and other resources in the main process and expect
- it to be copied to subprocess. Any resources e.g. connections/sockets need to be opened
- in this task by the subprocess.
-
- :param input_esdl: The input ESDL XML string.
- :param workflow_config: Extra parameters to configure this run.
- :param update_progress_handler: Handler to notify of any progress changes.
- :param workflow_type_name: Name of the workflow.
- :return: GROW optimized or simulated ESDL and a list of ESDL feedback messages.
- """
- workflow_type = GrowTaskType(workflow_type_name)
- mesido_func = get_problem_function(workflow_type)
- mesido_workflow = get_problem_type(workflow_type)
- mesido_solver = get_solver_class(workflow_type)
-
- base_folder = Path(__file__).resolve().parent.parent
- esdl_output_profiles_type_str = os.environ.get(
- "ESDL_OUTPUT_PROFILES_TYPE", "POSTGRESQL"
- ).upper()
- esdl_output_profiles_type = getattr(ESDLOutputProfilesType, esdl_output_profiles_type_str, None)
- if esdl_output_profiles_type is None:
- logger.warning(
- "Unknown ESDL_OUTPUT_PROFILES_TYPE '%s', defaulting to POSTGRESQL",
- esdl_output_profiles_type_str,
- )
- esdl_output_profiles_type = ESDLOutputProfilesType.POSTGRESQL
-
- db_host = os.environ.get("DB_HOSTNAME")
- db_port = int(os.environ.get("DB_PORT", "5432"))
- db_username = os.environ.get("DB_USERNAME", "")
- db_password = os.environ.get("DB_PASSWORD", "")
-
- logger.info(
- "Will write result profiles to '%s' database at %s:%s",
- esdl_output_profiles_type_str,
- db_host,
- db_port,
- )
-
- database_connection = []
-
- database_connection.append(
- {
- "access_type": DBAccessType.READ_WRITE,
- "host": db_host,
- "port": db_port,
- "username": db_username,
- "password": db_password,
- "ssl": False,
- "verify_ssl": False,
- }
- )
-
- esdl_str = None
- esdl_messages = []
- try:
- solution: GROWProblem = mesido_func(
- mesido_workflow,
- solver_class=mesido_solver,
- base_folder=base_folder,
- esdl_string=base64.encodebytes(input_esdl.encode("utf-8")),
- esdl_parser=ESDLStringParser,
- esdl_output_profiles_type=esdl_output_profiles_type,
- database_connections=database_connection,
- update_progress_function=update_progress_handler,
- profile_reader=ESDLProfileReader,
- )
- esdl_str = cast(str, solution.optimized_esdl_string)
- # TODO get esdl_messages from successful run after mesido update.
- except MesidoAssetIssueError as mesido_issues_error:
- esdl_messages = parse_mesido_esdl_messages(
- mesido_issues_error.general_issue, mesido_issues_error.message_per_asset_id
- )
- except SystemExit as e:
- raise EarlySystemExit(e)
- except Exception:
- # in case of general mesido error, make sure to return esdl_str and esdl_messages
- pass
-
- return esdl_str, esdl_messages
-
-
-def parse_mesido_esdl_messages(
- general_message: str, object_messages: Dict[str, str]
-) -> List[EsdlMessage]:
- """Convert mesido messages to a list of esdl messages in omotes format.
-
- :param general_message: general message (not related to a specific ESDL object).
- :param object_messages: esdl object messages per object id.
- :return: list of EsdlMessage dataclass objects.
- """
- # TODO get severity from esdl message and add list of general messages after mesido update.
- esdl_messages = []
-
- if general_message:
- esdl_messages.append(
- EsdlMessage(technical_message=general_message, severity=MessageSeverity.ERROR)
- )
- for object_id, message in object_messages.items():
- esdl_messages.append(
- EsdlMessage(
- technical_message=message,
- severity=MessageSeverity.ERROR,
- esdl_object_id=object_id,
- )
- )
- return esdl_messages
-
-
-if __name__ == "__main__":
- initialize_worker([task_type.value for task_type in GROW_TASK_TYPES], grow_worker_task)
diff --git a/src/omotes_optimizer_worker/__init__.py b/src/omotes_optimizer_worker/__init__.py
new file mode 100644
index 0000000..bf6bd6c
--- /dev/null
+++ b/src/omotes_optimizer_worker/__init__.py
@@ -0,0 +1,3 @@
+from dotenv import load_dotenv
+
+load_dotenv()
diff --git a/src/omotes_optimizer_worker/env.py b/src/omotes_optimizer_worker/env.py
new file mode 100644
index 0000000..97ea1eb
--- /dev/null
+++ b/src/omotes_optimizer_worker/env.py
@@ -0,0 +1,111 @@
+import os
+
+
+def require_env(name: str) -> str:
+ """Return a required environment variable.
+
+ Returns:
+ str: The configured environment variable value.
+
+ Raises:
+ RuntimeError: If the environment variable is missing.
+
+ """
+ value = os.getenv(name)
+ if value is None:
+ raise RuntimeError(f"Missing required environment variable: '{name}'")
+ return value
+
+
+class EnvSettings:
+ """Helper class to access environment variables."""
+
+ @staticmethod
+ def log_level() -> str:
+ """Return configured log level in upper-case."""
+ return require_env("LOG_LEVEL").upper()
+
+ @staticmethod
+ def esdl_output_profiles_type() -> str:
+ """Return ESDL output profiles type."""
+ return require_env("ESDL_OUTPUT_PROFILES_TYPE")
+
+ @staticmethod
+ def db_hostname() -> str:
+ """Return database host name."""
+ return require_env("DB_HOSTNAME")
+
+ @staticmethod
+ def db_port() -> str:
+ """Return database port."""
+ return require_env("DB_PORT")
+
+ @staticmethod
+ def db_username() -> str:
+ """Return database user name."""
+ return require_env("DB_USERNAME")
+
+ @staticmethod
+ def db_password() -> str:
+ """Return database password."""
+ return require_env("DB_PASSWORD")
+
+ @staticmethod
+ def prefect_api_url() -> str:
+ """Return Prefect API URL."""
+ return require_env("PREFECT_API_URL")
+
+ @staticmethod
+ def prefect_api_url_for_worker() -> str:
+ """Return Prefect API URL to be used inside worker."""
+ return require_env("PREFECT_API_URL_FOR_WORKER")
+
+ @staticmethod
+ def prefect_work_pool_name() -> str:
+ """Return Prefect work pool name."""
+ return require_env("PREFECT_WORK_POOL_NAME")
+
+ @staticmethod
+ def prefect_use_local_code_and_image() -> bool:
+ """Return whether local code and image should be used for deployment."""
+ return os.getenv("PREFECT_USE_LOCAL_CODE_AND_IMAGE", "false").lower() == "true"
+
+ @staticmethod
+ def prefect_use_local_sdk_and_mesido() -> bool:
+ """Return whether local code for sdk and mesido should be used for deployment."""
+ return os.getenv("PREFECT_USE_LOCAL_SDK_AND_MESIDO", "false").lower() == "true"
+
+ @staticmethod
+ def prefect_api_auth_string() -> str:
+ """Return Prefect server API URL."""
+ return require_env("PREFECT_API_AUTH_STRING")
+
+ @staticmethod
+ def prefect_flow_max_concurrent_runs() -> int:
+ """Return the maximum number of concurrent Prefect flow runs."""
+ return int(require_env("PREFECT_FLOW_MAX_CONCURRENT_RUNS"))
+
+ @staticmethod
+ def minio_host() -> str:
+ """Return MinIO host."""
+ return require_env("MINIO_HOST")
+
+ @staticmethod
+ def minio_external_host() -> str | None:
+ """Return optional external MinIO host."""
+ return os.getenv("MINIO_EXTERNAL_HOST", None)
+
+ @staticmethod
+ def minio_access_key() -> str:
+ """Return MinIO access key."""
+ return require_env("MINIO_ACCESS_KEY")
+
+ @staticmethod
+ def minio_secret() -> str:
+ """Return MinIO secret key."""
+ return require_env("MINIO_SECRET")
+
+ @staticmethod
+ def optimizer_worker_version() -> str | None:
+ """Return optional optimizer worker version."""
+ return os.getenv("OPTIMIZER_WORKER_VERSION", None)
diff --git a/src/omotes_optimizer_worker/prefect_deploy_flow.py b/src/omotes_optimizer_worker/prefect_deploy_flow.py
new file mode 100644
index 0000000..1998fbd
--- /dev/null
+++ b/src/omotes_optimizer_worker/prefect_deploy_flow.py
@@ -0,0 +1,88 @@
+import asyncio
+import subprocess
+from pathlib import Path
+
+from omotes_sdk.prefect_util import deploy_flow
+
+from omotes_optimizer_worker.env import EnvSettings
+from omotes_optimizer_worker.prefect_flow import optimizer_flow
+
+deployment_base_name = "omotes-optimizer"
+
+prefect_use_local_code_and_image = EnvSettings.prefect_use_local_code_and_image()
+optimizer_version = EnvSettings.optimizer_worker_version()
+if prefect_use_local_code_and_image:
+ optimizer_version = "local"
+ optimizer_image = f"{deployment_base_name}:{optimizer_version}"
+else:
+ optimizer_image = f"ghcr.io/project-omotes/{deployment_base_name}:{optimizer_version}"
+
+job_variables = {
+ "imagePullPolicy": "Always",
+ "env": {
+ "PREFECT_LOGGING_EXTRA_LOGGERS": "root",
+ "PREFECT_LOGGING_LEVEL": EnvSettings.log_level(),
+ "PREFECT_LOGGING_ROOT_LEVEL": EnvSettings.log_level(),
+ "LOG_LEVEL": EnvSettings.log_level(),
+ "PREFECT_API_AUTH_STRING": EnvSettings.prefect_api_auth_string(),
+ "PREFECT_API_URL": EnvSettings.prefect_api_url_for_worker(),
+ "ESDL_OUTPUT_PROFILES_TYPE": EnvSettings.esdl_output_profiles_type(),
+ "DB_HOSTNAME": EnvSettings.db_hostname(),
+ "DB_PORT": EnvSettings.db_port(),
+ "DB_USERNAME": EnvSettings.db_username(),
+ "DB_PASSWORD": EnvSettings.db_password(),
+ "MINIO_HOST": EnvSettings.minio_host(),
+ "MINIO_EXTERNAL_HOST": EnvSettings.minio_external_host(),
+ "MINIO_ACCESS_KEY": EnvSettings.minio_access_key(),
+ "MINIO_SECRET": EnvSettings.minio_secret(),
+ "PREFECT_MINIO_HOST": EnvSettings.minio_host(),
+ "PREFECT_MINIO_EXTERNAL_HOST": EnvSettings.minio_external_host(),
+ "PREFECT_MINIO_ACCESS_KEY": EnvSettings.minio_access_key(),
+ "PREFECT_MINIO_SECRET": EnvSettings.minio_secret(),
+ },
+ "pod_watch_timeout_seconds": 24 * 3600,
+ "networks": ["omotes"], # for docker worker
+ "auto_remove": True, # for docker worker, uncomment for debugging
+}
+
+
+async def main() -> None:
+ """Deploy training and prediction flows to Prefect."""
+ if prefect_use_local_code_and_image:
+ # create/update local classification docker image
+ if EnvSettings.prefect_use_local_sdk_and_mesido():
+ repo_root = Path(__file__).resolve().parents[2]
+ monorepo_root = repo_root.parent
+ subprocess.run(
+ [
+ "docker",
+ "build",
+ "-f",
+ "optimizer-worker/dev.Dockerfile",
+ "--provenance=false",
+ "-t",
+ optimizer_image,
+ ".",
+ ],
+ check=True,
+ cwd=monorepo_root,
+ )
+ else:
+ cmd_build_classification_image = f"docker build --provenance=false -t {optimizer_image} .."
+ subprocess.run(cmd_build_classification_image, shell=True, check=True)
+ # When not using local code and image, a publised image is used with tag OPTIMIZER_WORKER_IMAGE_TAG.
+
+ await deploy_flow(
+ flow_function=optimizer_flow,
+ deployment_name=f"{deployment_base_name}:{optimizer_version}",
+ image_name=optimizer_image,
+ job_variables=job_variables,
+ prefect_work_pool_name=EnvSettings.prefect_work_pool_name(),
+ max_concurrent_runs=EnvSettings.prefect_flow_max_concurrent_runs(),
+ )
+
+ print("Omotes optimizer deployment registered successfully")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/src/omotes_optimizer_worker/prefect_flow.py b/src/omotes_optimizer_worker/prefect_flow.py
new file mode 100644
index 0000000..cae3db2
--- /dev/null
+++ b/src/omotes_optimizer_worker/prefect_flow.py
@@ -0,0 +1,206 @@
+import base64
+import logging
+import os
+from contextlib import nullcontext
+from pathlib import Path
+from typing import Any, cast
+
+from esdl import EnergySystem
+from esdl.esdl_handler import EnergySystemHandler
+from mesido.esdl.esdl_mixin import DBAccessType, ESDLOutputProfilesType
+from mesido.esdl.esdl_parser import ESDLStringParser
+from mesido.esdl.profile_parser import ESDLProfileReader
+from mesido.exceptions import MesidoAssetIssueError
+from omotes_sdk.esdl_messages import (
+ EsdlMessage,
+ MessageSeverity,
+)
+from omotes_sdk.log_forwarding import StdCaptureToLogSession
+from omotes_sdk.prefect_util import (
+ create_flow_progress_updater,
+ in_prefect_flow_context,
+ load_gurobi_license,
+ write_flow_return_artifact_to_minio,
+)
+from prefect import flow
+from prefect.runtime import flow_run
+from prefect.states import Failed, State
+from pydantic import BaseModel, Field
+
+from omotes_optimizer_worker.worker_types import (
+ GrowTaskType,
+ get_problem_function,
+ get_problem_type,
+ get_solver_class,
+)
+
+
+class OptimizerFlowResult(BaseModel):
+ """Flow result payload written as artifact output."""
+
+ output_esdl: str | None = Field(default=None, json_schema_extra={"file_extension": ".esdl"})
+ esdl_messages: list[dict[str, Any]] = Field(default_factory=list, json_schema_extra={"file_extension": ".json"})
+
+
+@flow
+def optimizer_flow(
+ input_esdl: str,
+ workflow_config: dict,
+ workflow_type_name: str,
+) -> OptimizerFlowResult | State[Any] | None:
+ """Prefect flow function for the optimizer worker.
+
+ Args:
+ input_esdl: The input ESDL XML string.
+ workflow_config: Extra parameters to configure this run.
+ workflow_type_name: Name of the workflow.
+
+ Returns:
+ OptimizerFlowResult | State[Any] | None: Failed state when execution fails; otherwise no value is
+ returned from this flow function.
+
+ Raises:
+ ValueError: If MinIO credentials are not fully set.
+
+ """
+ logging.info("Starting optimizer flow with workflow type: %s", workflow_type_name)
+ _update_flow_progress = create_flow_progress_updater(
+ start_progress_fraction=0.0,
+ start_description="Starting optimizer flow",
+ )
+
+ # Capture and forward solver output only during orchestrated Prefect flow runs.
+ capture_session = StdCaptureToLogSession() if in_prefect_flow_context() else nullcontext()
+ with capture_session:
+ minio_host = os.environ.get("MINIO_HOST")
+ minio_access_key = os.environ.get("MINIO_ACCESS_KEY")
+ minio_secret = os.environ.get("MINIO_SECRET")
+
+ db_host = os.environ.get("DB_HOSTNAME")
+ db_port = int(os.environ.get("DB_PORT", "5432"))
+ db_username = os.environ.get("DB_USERNAME", "")
+ db_password = os.environ.get("DB_PASSWORD", "")
+
+ if minio_host is None or minio_access_key is None or minio_secret is None:
+ raise ValueError(
+ f"MinIO credentials are not fully set. MinIO host: {minio_host}, "
+ f"access key: {minio_access_key}, secret key: {minio_secret}"
+ )
+ try:
+ workflow_type = GrowTaskType(workflow_type_name)
+ mesido_func = get_problem_function(workflow_type)
+ mesido_workflow = get_problem_type(workflow_type)
+ mesido_solver = get_solver_class(workflow_type)
+
+ if "gurobi" in workflow_type_name.lower():
+ load_gurobi_license()
+
+ base_folder = Path(__file__).resolve().parent.parent
+ esdl_output_profiles_type_str = os.environ.get("ESDL_OUTPUT_PROFILES_TYPE", "POSTGRESQL").upper()
+ esdl_output_profiles_type = getattr(ESDLOutputProfilesType, esdl_output_profiles_type_str, None)
+ if esdl_output_profiles_type is None:
+ logging.warning(
+ "Unknown ESDL_OUTPUT_PROFILES_TYPE '%s', defaulting to POSTGRESQL",
+ esdl_output_profiles_type_str,
+ )
+ esdl_output_profiles_type = ESDLOutputProfilesType.POSTGRESQL
+
+ logging.info(
+ "Will write result profiles to '%s' database at %s:%s",
+ esdl_output_profiles_type_str,
+ db_host,
+ db_port,
+ )
+
+ database_connection = []
+
+ database_connection.append({
+ "access_type": DBAccessType.READ_WRITE,
+ "host": db_host,
+ "port": db_port,
+ "username": db_username,
+ "password": db_password,
+ "ssl": False,
+ "verify_ssl": False,
+ })
+
+ esdl_messages: list[EsdlMessage] = []
+
+ solution: Any = mesido_func(
+ mesido_workflow,
+ solver_class=mesido_solver,
+ base_folder=base_folder,
+ esdl_string=base64.encodebytes(input_esdl.encode("utf-8")),
+ esdl_parser=ESDLStringParser,
+ esdl_output_profiles_type=esdl_output_profiles_type,
+ database_connections=database_connection,
+ update_progress_function=_update_flow_progress,
+ profile_reader=ESDLProfileReader,
+ )
+ output_esdl = cast(str, solution.optimized_esdl_string)
+
+ # update name of output ESDL
+ input_esh = EnergySystemHandler()
+ input_esh.load_from_string(input_esdl)
+
+ new_name = input_esh.energy_system.name + "_"
+ new_name += flow_run.name if flow_run and flow_run.name else workflow_type_name
+
+ output_esh = EnergySystemHandler()
+ output_esh.load_from_string(output_esdl)
+ output_energy_system: EnergySystem = output_esh.energy_system
+ output_energy_system.name = new_name
+
+ # TODO get esdl_messages from successful run after mesido update.
+ esdl_messages_as_dicts = [message.model_dump(mode="json") for message in esdl_messages]
+ success_result = OptimizerFlowResult(
+ output_esdl=output_esh.to_string(),
+ esdl_messages=esdl_messages_as_dicts,
+ )
+
+ write_flow_return_artifact_to_minio(success_result, minio_host, minio_access_key, minio_secret)
+
+ # return only for local runs and testing, not persisted for containerized runs: artifacts are used
+ return success_result
+ except Exception as e:
+ logging.exception("Exception during optimizer flow")
+
+ esdl_messages: list[EsdlMessage] = []
+ if isinstance(e, MesidoAssetIssueError):
+ esdl_messages = parse_mesido_esdl_messages(e.general_issue, e.message_per_asset_id)
+ logging.info(f"ESDL Messages: {esdl_messages}")
+
+ failed_result = OptimizerFlowResult(
+ output_esdl=None,
+ esdl_messages=[message.model_dump(mode="json") for message in esdl_messages],
+ )
+ write_flow_return_artifact_to_minio(failed_result, minio_host, minio_access_key, minio_secret)
+
+ return Failed(message=f"Optimizer flow failed: {e}")
+
+
+def parse_mesido_esdl_messages(general_message: str, object_messages: dict[str, str]) -> list[EsdlMessage]:
+ """Convert mesido messages to a list of esdl messages in omotes format.
+
+ Args:
+ general_message: General message (not related to a specific ESDL object).
+ object_messages: ESDL object messages per object id.
+
+ Returns:
+ list[EsdlMessage]: List of EsdlMessage dataclass objects.
+
+ """
+ # TODO get severity from esdl message and add list of general messages after mesido update.
+ esdl_messages = []
+
+ if general_message:
+ esdl_messages.append(EsdlMessage(technical_message=general_message, severity=MessageSeverity.ERROR))
+ for object_id, message in object_messages.items():
+ esdl_messages.append(
+ EsdlMessage(
+ technical_message=message,
+ severity=MessageSeverity.ERROR,
+ esdl_object_id=object_id,
+ )
+ )
+ return esdl_messages
diff --git a/src/grow_worker/worker_types.py b/src/omotes_optimizer_worker/worker_types.py
similarity index 81%
rename from src/grow_worker/worker_types.py
rename to src/omotes_optimizer_worker/worker_types.py
index b3b83f0..4f12623 100644
--- a/src/grow_worker/worker_types.py
+++ b/src/omotes_optimizer_worker/worker_types.py
@@ -1,18 +1,19 @@
+from collections.abc import Callable
from enum import Enum
-from typing import Type, Union, Callable
+from typing import Any
-from mesido.workflows import NetworkSimulatorHIGHSWeeklyTimeStep
+from mesido.workflows import (
+ NetworkSimulatorHIGHSWeeklyTimeStep,
+ run_end_scenario_sizing,
+ run_end_scenario_sizing_no_heat_losses,
+)
from mesido.workflows.grow_workflow import (
+ EndScenarioSizingDiscountedStaged,
EndScenarioSizingHeadLossStaged,
EndScenarioSizingStaged,
- EndScenarioSizingDiscountedStaged,
SolverGurobi,
SolverHIGHS,
)
-from mesido.workflows import (
- run_end_scenario_sizing,
- run_end_scenario_sizing_no_heat_losses,
-)
class GrowTaskType(Enum):
@@ -41,18 +42,28 @@ class GrowTaskType(Enum):
"""Run the Grow Optimizer with minimum equivalent annual cost goal with Gurobi solver."""
-GROWProblem = Union[
- Type[EndScenarioSizingHeadLossStaged],
- Type[EndScenarioSizingStaged],
- Type[NetworkSimulatorHIGHSWeeklyTimeStep],
-]
+GROWProblem = (
+ type[EndScenarioSizingHeadLossStaged]
+ | type[EndScenarioSizingStaged]
+ | type[EndScenarioSizingDiscountedStaged]
+ | type[NetworkSimulatorHIGHSWeeklyTimeStep]
+)
+
+GROWProblemFunction = Callable[..., Any]
def get_problem_type(task_type: GrowTaskType) -> GROWProblem:
"""Convert the Grow task type to the Grow problem that should be run.
- :param task_type: Grow task type.
- :return: Grow problem class.
+ Args:
+ task_type: Grow task type.
+
+ Returns:
+ GROWProblem: Grow problem class.
+
+ Raises:
+ RuntimeError: If the task type is unknown.
+
"""
result: GROWProblem
if task_type in [
@@ -88,13 +99,20 @@ def get_problem_type(task_type: GrowTaskType) -> GROWProblem:
def get_problem_function(
task_type: GrowTaskType,
-) -> Callable[..., GROWProblem]:
+) -> GROWProblemFunction:
"""Convert the Grow task type to the Grow function that should be run.
- :param task_type: Grow task type.
- :return: Grow problem function.
+ Args:
+ task_type: Grow task type.
+
+ Returns:
+ GROWProblemFunction: Grow problem function.
+
+ Raises:
+ RuntimeError: If the task type is unknown.
+
"""
- result: GROWProblem
+ result: GROWProblemFunction
if task_type in [
GrowTaskType.GROW_OPTIMIZER_DEFAULT,
GrowTaskType.GROW_SIMULATOR,
@@ -117,13 +135,20 @@ def get_problem_function(
return result
-def get_solver_class(task_type: GrowTaskType) -> Union[Type[SolverHIGHS], Type[SolverGurobi]]:
+def get_solver_class(task_type: GrowTaskType) -> type[SolverHIGHS] | type[SolverGurobi]:
"""Convert the Grow task type to the Grow solver that should be run.
- :param task_type: Grow task type.
- :return: Grow solver class.
+ Args:
+ task_type: Grow task type.
+
+ Returns:
+ type[SolverHIGHS] | type[SolverGurobi]: Grow solver class.
+
+ Raises:
+ RuntimeError: If the task type is unknown.
+
"""
- result: Union[Type[SolverHIGHS], Type[SolverGurobi]]
+ result: type[SolverHIGHS] | type[SolverGurobi]
if task_type in [
GrowTaskType.GROW_OPTIMIZER_DEFAULT,
GrowTaskType.GROW_SIMULATOR,
diff --git a/tests/test_prefect_deploy_flow.py b/tests/test_prefect_deploy_flow.py
new file mode 100644
index 0000000..9debfae
--- /dev/null
+++ b/tests/test_prefect_deploy_flow.py
@@ -0,0 +1,35 @@
+from collections.abc import Mapping
+from importlib import import_module, reload
+from os import environ
+from unittest import TestCase
+from unittest.mock import patch
+
+
+class TestDeployFlowJobVariables(TestCase):
+ """Tests for the job_variables structure built at module level."""
+
+ def _get_job_variables(self) -> Mapping[str, object]:
+ required_env = {
+ "LOG_LEVEL": "INFO",
+ "ESDL_OUTPUT_PROFILES_TYPE": "POSTGRESQL",
+ "DB_HOSTNAME": "db",
+ "DB_PORT": "5432",
+ "DB_USERNAME": "user",
+ "DB_PASSWORD": "pass",
+ "PREFECT_API_AUTH_STRING": "token",
+ "PREFECT_API_URL_FOR_WORKER": "http://prefect:4200/api",
+ "MINIO_HOST": "minio:9000",
+ "MINIO_ACCESS_KEY": "access",
+ "MINIO_SECRET": "secret",
+ "PREFECT_WORK_POOL_NAME": "default",
+ "PREFECT_FLOW_MAX_CONCURRENT_RUNS": "1",
+ }
+ with patch.dict(environ, required_env, clear=False):
+ m = import_module("omotes_optimizer_worker.prefect_deploy_flow")
+ m = reload(m)
+
+ return m.job_variables
+
+ def test_job_variables_auto_remove_is_set(self) -> None:
+ """auto_remove should be True, not left over missing from testing."""
+ self.assertTrue(self._get_job_variables()["auto_remove"])
diff --git a/unit_test/test_worker_types.py b/tests/test_worker_types.py
similarity index 70%
rename from unit_test/test_worker_types.py
rename to tests/test_worker_types.py
index a167a0d..818ad7b 100644
--- a/unit_test/test_worker_types.py
+++ b/tests/test_worker_types.py
@@ -1,13 +1,17 @@
import unittest
-from grow_worker.worker_types import (
- get_problem_type,
- GrowTaskType,
+
+from omotes_optimizer_worker.worker_types import (
EndScenarioSizingStaged,
+ GrowTaskType,
+ get_problem_type,
)
class TestModule(unittest.TestCase):
+ """Tests for worker type conversion helpers."""
+
def test__get_problem_type__is_correct_grow_optimizer(self) -> None:
+ """Verify optimizer default task maps to the staged sizing problem class."""
# Arrange
task_type = GrowTaskType.GROW_OPTIMIZER_DEFAULT
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 0000000..7d77dcf
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,2357 @@
+version = 1
+revision = 2
+requires-python = "==3.11.*"
+
+[[package]]
+name = "aiobotocore"
+version = "3.8.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "aioitertools" },
+ { name = "botocore" },
+ { name = "jmespath" },
+ { name = "multidict" },
+ { name = "python-dateutil" },
+ { name = "wrapt" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d8/a7/bc31b7046c610471f0630819ca5d2a57ac4efa8d47135cb53e43f2785390/aiobotocore-3.8.0.tar.gz", hash = "sha256:80a1eb64ea915f3af3c1518669975bae74a17b2f37c14eb0fa2f83b915974670", size = 131368, upload-time = "2026-07-17T03:10:30.258Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6d/f4/5a7d76dc844d3ff8ed1f1a043158aa393794aebb787d3e2f8c0fe87f674f/aiobotocore-3.8.0-py3-none-any.whl", hash = "sha256:8bc605132cadfe844a3f334635a0a64fa5e360a4a206e915d99d53db5b6deeba", size = 91169, upload-time = "2026-07-17T03:10:28.771Z" },
+]
+
+[[package]]
+name = "aiohappyeyeballs"
+version = "2.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ce/f4/eec0465c2f67b2664688d0240b3212d5196fd89e741df67ddb81f8d35658/aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d", size = 24757, upload-time = "2026-07-01T17:11:55.501Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472", size = 15038, upload-time = "2026-07-01T17:11:54.055Z" },
+]
+
+[[package]]
+name = "aiohttp"
+version = "3.14.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohappyeyeballs" },
+ { name = "aiosignal" },
+ { name = "attrs" },
+ { name = "frozenlist" },
+ { name = "multidict" },
+ { name = "propcache" },
+ { name = "typing-extensions" },
+ { name = "yarl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f8/5c/b3e4ff8ad43a8afef9602c5e90285936da1beaea8b029016b793891f03c3/aiohttp-3.14.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e568e14940c09955aa51f4e645b6daa18a581c5dcfcd73744dcc86a856e3ced3", size = 764250, upload-time = "2026-07-23T01:52:48.525Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/da/f1b384465e51449d844056b75070461da03a9a23e6c1747003695bf4172a/aiohttp-3.14.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54cfcdee2770dac994417cbb0ee1f3eb0e7cb6b30c79bf44f2c02ff79ec5124a", size = 516281, upload-time = "2026-07-23T01:52:51.047Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/3f/01264f820ee2e3712a827892b1cd6ff80f3300c1fcbffbb45714a915d47a/aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:21c016079415ed3fd676963e9793700a566d85dbbd6bfc564b9b2d209147dcc8", size = 514742, upload-time = "2026-07-23T01:52:53.779Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/8d/a71c6f2db52ac1ed142b133f7feddaa6b70539c3f4de24d7e226c95b794c/aiohttp-3.14.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6088ec9894113802bddb3c09e974929aed2c7b3a8c456219b8aab4481f1a239", size = 1780613, upload-time = "2026-07-23T01:52:56.948Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/11/3dd9b3fb3a170f6ec9011b5291d876a6fab4086714c9e158600edf01b4fd/aiohttp-3.14.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:16ea7e24c309fb7c0bbd505d149abe4fe4dccfb8db911db7dbec0921bc889a6f", size = 1737688, upload-time = "2026-07-23T01:52:59.294Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/3e/834c26918be7d88068822b40e0db30fca50b5f4fe79104aa16a93f1d74e6/aiohttp-3.14.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56f355e79f71aef2a85c80305cc915f894b170dba76de5fe84f6351939b83c06", size = 1845742, upload-time = "2026-07-23T01:53:01.641Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/c9/49ab8572df7d66bc13d11e31f781292badb04180dd87ba98733066c6aed7/aiohttp-3.14.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:18c441d0a8fca6de8d1f546849b9f0ab20d435993e2c5b59562b2fae6be2f929", size = 1928412, upload-time = "2026-07-23T01:53:04.018Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/b9/2b8f0c0ce09c87a1daf80fd483431b56b1435d3f62789bc86f572e1245de/aiohttp-3.14.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53e7b4ce82b54a8bcc71b3b67a5cbd177ca1d7f592cbc92cd38b7349f73482db", size = 1786220, upload-time = "2026-07-23T01:53:06.481Z" },
+ { url = "https://files.pythonhosted.org/packages/85/00/9c45f81de11710460edfa1dc81317b6e882703b160926c879a9d20da9fcc/aiohttp-3.14.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f55119f7bf25f49ed210f6096090715da24f2943c62102448915fde3c62877ce", size = 1637231, upload-time = "2026-07-23T01:53:10.258Z" },
+ { url = "https://files.pythonhosted.org/packages/19/ce/967d628e910756f3539c6107cb7844a1b69440dcb3029a5ee7871b09ab63/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9aa6e61fdf20105c4144e755bd586008ff450791d67b1c8146fdc15959c4d51c", size = 1753161, upload-time = "2026-07-23T01:53:13.817Z" },
+ { url = "https://files.pythonhosted.org/packages/11/b2/0c3d4114f0aee4f580f5b3b4eb71b24d7a23b834ea506a4dfebe76513f35/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ccd4893707b3e2a13e39c90d43cf80edf2e4d0457935bcc103bf2346214c3f15", size = 1756356, upload-time = "2026-07-23T01:53:16.211Z" },
+ { url = "https://files.pythonhosted.org/packages/63/5d/99e7d91c82f1399d1ae2a854e080bd1493fbc31e5e959dbc4ec33dac3bec/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2466434105a4e03113c36ec775cc2ebe6676b62eae326fa670bb607ef788c1c", size = 1819846, upload-time = "2026-07-23T01:53:18.289Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/05/d5e1cb6480eeffd3f901d40a2c5e2d1e7effdc797837da3b490272699f13/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ba59d59aba08ac02fc03b0c8983ccd5ee39a199d0552ce9e6d2b4845b34d59ae", size = 1628531, upload-time = "2026-07-23T01:53:23.86Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/90/b934682bcaefae18a9e04f3dff5b68522ba810906358ae5029b68110ea3b/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ed099d105449c4f9e84f24af203cd131349d4761d8813fa7e02c32e7128cd910", size = 1832712, upload-time = "2026-07-23T01:53:27.551Z" },
+ { url = "https://files.pythonhosted.org/packages/21/df/6061679faaf81fac746e7307c7adb71e858071a5d34c27583afefc64f543/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:152516815ef926786a0b6ae2b8f1fd2e0c71582dee0b435636865316fd4891b7", size = 1775014, upload-time = "2026-07-23T01:53:30.223Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/1d/f854878bbc69b88faefe924b619a34a6f59ec05fd387c77690667eaa75eb/aiohttp-3.14.3-cp311-cp311-win32.whl", hash = "sha256:a4af35c443e0b1a1bd6a8af3f3485d7fda15c142751a00f3ff8090f0b93346fa", size = 456006, upload-time = "2026-07-23T01:53:34.97Z" },
+ { url = "https://files.pythonhosted.org/packages/73/0c/2af9d1674baccd1dbd47282a93d660a22e57ef6167c856deb24b4214fbab/aiohttp-3.14.3-cp311-cp311-win_amd64.whl", hash = "sha256:e1e74298bab6ee0d6e749ed4fd1901c7e604bdda32c03d787a2cc71c46d0433d", size = 481069, upload-time = "2026-07-23T01:53:39.673Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/76/88401ff3fc95e85c5fc38d588f36f55e61ecb64343b2bc8d69326f453cc0/aiohttp-3.14.3-cp311-cp311-win_arm64.whl", hash = "sha256:03cd2bde3d7f085b64e549c985f4bb928cad7e8ecf5323bfca320db548d81b39", size = 453021, upload-time = "2026-07-23T01:53:43.749Z" },
+]
+
+[[package]]
+name = "aioitertools"
+version = "0.13.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fd/3c/53c4a17a05fb9ea2313ee1777ff53f5e001aefd5cc85aa2f4c2d982e1e38/aioitertools-0.13.0.tar.gz", hash = "sha256:620bd241acc0bbb9ec819f1ab215866871b4bbd1f73836a55f799200ee86950c", size = 19322, upload-time = "2025-11-06T22:17:07.609Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/a1/510b0a7fadc6f43a6ce50152e69dbd86415240835868bb0bd9b5b88b1e06/aioitertools-0.13.0-py3-none-any.whl", hash = "sha256:0be0292b856f08dfac90e31f4739432f4cb6d7520ab9eb73e143f4f2fa5259be", size = 24182, upload-time = "2025-11-06T22:17:06.502Z" },
+]
+
+[[package]]
+name = "aiosignal"
+version = "1.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "frozenlist" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
+]
+
+[[package]]
+name = "aiosqlite"
+version = "0.22.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4e/8a/64761f4005f17809769d23e518d915db74e6310474e733e3593cfc854ef1/aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650", size = 14821, upload-time = "2025-12-23T19:25:43.997Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload-time = "2025-12-23T19:25:42.139Z" },
+]
+
+[[package]]
+name = "alembic"
+version = "1.18.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mako" },
+ { name = "sqlalchemy" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1a/cc/ac0bed8e562e7407fe55c3ba85a4dce86e6dbd8730887bd1e406a6c5c18a/alembic-1.18.5.tar.gz", hash = "sha256:1554982221dd17e9a749b53902407578eb305e453f71999e8c7f0a48389fff8e", size = 2060480, upload-time = "2026-06-25T15:20:54.888Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/96/78/5fe6dc3a3a5b2f5a2a4faef8bfe336d5fa049a38884ab3172e0098160c01/alembic-1.18.5-py3-none-any.whl", hash = "sha256:06d8ba9d04558022f5395e9317de03d270f3dced49cee01f89fe7a13c26f14bc", size = 264664, upload-time = "2026-06-25T15:20:56.673Z" },
+]
+
+[[package]]
+name = "amplitude-analytics"
+version = "1.2.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6e/f7/b23d28b1c405c22a25375e2c638c8cdcd054cbc4b43b76cf77bd358a0540/amplitude_analytics-1.2.3.tar.gz", hash = "sha256:4c9525847c391c19675d6e026f4601c27204ffeec71cb92252770d84d4538404", size = 22413, upload-time = "2026-03-31T18:33:20.291Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3f/56/83af6ef6a8bac9fdf2059de0276008e9eab40a315b8b732eba466bf6cc74/amplitude_analytics-1.2.3-py3-none-any.whl", hash = "sha256:ba2092c1d37ce8a2e3f69d023da145f4e322d02429e20436a5227178b1e594e9", size = 24762, upload-time = "2026-03-31T18:33:19.032Z" },
+]
+
+[[package]]
+name = "annotated-doc"
+version = "0.0.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" },
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" },
+]
+
+[[package]]
+name = "antlr4-python3-runtime"
+version = "4.13.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/33/5f/2cdf6f7aca3b20d3f316e9f505292e1f256a32089bd702034c29ebde6242/antlr4_python3_runtime-4.13.2.tar.gz", hash = "sha256:909b647e1d2fc2b70180ac586df3933e38919c85f98ccc656a96cd3f25ef3916", size = 117467, upload-time = "2024-08-03T19:00:12.757Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/89/03/a851e84fcbb85214dc637b6378121ef9a0dd61b4c65264675d8a5c9b1ae7/antlr4_python3_runtime-4.13.2-py3-none-any.whl", hash = "sha256:fe3835eb8d33daece0e799090eda89719dbccee7aa39ef94eed3818cafa5a7e8", size = 144462, upload-time = "2024-08-03T19:00:11.134Z" },
+]
+
+[[package]]
+name = "anyio"
+version = "4.14.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "idna" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
+]
+
+[[package]]
+name = "apprise"
+version = "1.12.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "click" },
+ { name = "markdown" },
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "requests-oauthlib" },
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ff/f7/95a52cda9355f32c5db9ef77bac18e85977472d29c555fafd825cf60c309/apprise-1.12.0.tar.gz", hash = "sha256:ffe9860d99cbde05fd156c610d4bcb49d953200c4ed3cb2db001ed50722fc142", size = 2477874, upload-time = "2026-07-04T16:15:36.67Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d3/e9/acfea54abdd66a059ff82995d3703eca3a27df3dc1bdc6afaf8a30a854fe/apprise-1.12.0-py3-none-any.whl", hash = "sha256:28edabfec5a9d5dbcd9aa28bdfd8928ecb68764e40214b6e648eab6d974b5a93", size = 1797824, upload-time = "2026-07-04T16:15:34.228Z" },
+]
+
+[[package]]
+name = "asgi-lifespan"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "sniffio" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6a/da/e7908b54e0f8043725a990bf625f2041ecf6bfe8eb7b19407f1c00b630f7/asgi-lifespan-2.1.0.tar.gz", hash = "sha256:5e2effaf0bfe39829cf2d64e7ecc47c7d86d676a6599f7afba378c31f5e3a308", size = 15627, upload-time = "2023-03-28T17:35:49.126Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2f/f5/c36551e93acba41a59939ae6a0fb77ddb3f2e8e8caa716410c65f7341f72/asgi_lifespan-2.1.0-py3-none-any.whl", hash = "sha256:ed840706680e28428c01e14afb3875d7d76d3206f3d5b2f2294e059b5c23804f", size = 10895, upload-time = "2023-03-28T17:35:47.772Z" },
+]
+
+[[package]]
+name = "async-timeout"
+version = "5.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" },
+]
+
+[[package]]
+name = "asyncpg"
+version = "0.31.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fe/cc/d18065ce2380d80b1bcce927c24a2642efd38918e33fd724bc4bca904877/asyncpg-0.31.0.tar.gz", hash = "sha256:c989386c83940bfbd787180f2b1519415e2d3d6277a70d9d0f0145ac73500735", size = 993667, upload-time = "2025-11-24T23:27:00.812Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/08/17/cc02bc49bc350623d050fa139e34ea512cd6e020562f2a7312a7bcae4bc9/asyncpg-0.31.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eee690960e8ab85063ba93af2ce128c0f52fd655fdff9fdb1a28df01329f031d", size = 643159, upload-time = "2025-11-24T23:25:36.443Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/62/4ded7d400a7b651adf06f49ea8f73100cca07c6df012119594d1e3447aa6/asyncpg-0.31.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2657204552b75f8288de08ca60faf4a99a65deef3a71d1467454123205a88fab", size = 638157, upload-time = "2025-11-24T23:25:37.89Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/5b/4179538a9a72166a0bf60ad783b1ef16efb7960e4d7b9afe9f77a5551680/asyncpg-0.31.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a429e842a3a4b4ea240ea52d7fe3f82d5149853249306f7ff166cb9948faa46c", size = 2918051, upload-time = "2025-11-24T23:25:39.461Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/35/c27719ae0536c5b6e61e4701391ffe435ef59539e9360959240d6e47c8c8/asyncpg-0.31.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0807be46c32c963ae40d329b3a686356e417f674c976c07fa49f1b30303f109", size = 2972640, upload-time = "2025-11-24T23:25:41.512Z" },
+ { url = "https://files.pythonhosted.org/packages/43/f4/01ebb9207f29e645a64699b9ce0eefeff8e7a33494e1d29bb53736f7766b/asyncpg-0.31.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e5d5098f63beeae93512ee513d4c0c53dc12e9aa2b7a1af5a81cddf93fe4e4da", size = 2851050, upload-time = "2025-11-24T23:25:43.153Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/f4/03ff1426acc87be0f4e8d40fa2bff5c3952bef0080062af9efc2212e3be8/asyncpg-0.31.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37fc6c00a814e18eef51833545d1891cac9aa69140598bb076b4cd29b3e010b9", size = 2962574, upload-time = "2025-11-24T23:25:44.942Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/39/cc788dfca3d4060f9d93e67be396ceec458dfc429e26139059e58c2c244d/asyncpg-0.31.0-cp311-cp311-win32.whl", hash = "sha256:5a4af56edf82a701aece93190cc4e094d2df7d33f6e915c222fb09efbb5afc24", size = 521076, upload-time = "2025-11-24T23:25:46.486Z" },
+ { url = "https://files.pythonhosted.org/packages/28/fc/735af5384c029eb7f1ca60ccb8fa95521dbdaeef788edf4cecfc604c3cab/asyncpg-0.31.0-cp311-cp311-win_amd64.whl", hash = "sha256:480c4befbdf079c14c9ca43c8c5e1fe8b6296c96f1f927158d4f1e750aacc047", size = 584980, upload-time = "2025-11-24T23:25:47.938Z" },
+]
+
+[[package]]
+name = "attrs"
+version = "26.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
+]
+
+[[package]]
+name = "beartype"
+version = "0.22.9"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/94/1009e248bbfbab11397abca7193bea6626806be9a327d399810d523a07cb/beartype-0.22.9.tar.gz", hash = "sha256:8f82b54aa723a2848a56008d18875f91c1db02c32ef6a62319a002e3e25a975f", size = 1608866, upload-time = "2025-12-13T06:50:30.72Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl", hash = "sha256:d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2", size = 1333658, upload-time = "2025-12-13T06:50:28.266Z" },
+]
+
+[[package]]
+name = "botocore"
+version = "1.43.46"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "jmespath" },
+ { name = "python-dateutil" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7d/f1/1917891851ac5ac09bb9f4862b8fc9252a009d7c24e8688bb67e4383d9e7/botocore-1.43.46.tar.gz", hash = "sha256:59f2e1ac3cdc66d191cae91c0804bc41847ce817dc8147cf43eaada8f76a5533", size = 15694635, upload-time = "2026-07-10T19:32:00.437Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0e/f2/4bd8f2f419088feb3ce55f0ca91040ff902f402edfd197450b20a2e1d533/botocore-1.43.46-py3-none-any.whl", hash = "sha256:cb673891e623ae6e6a1bf24d94ef169504f3eb02584adb5d5bee2f6aae819b60", size = 15380350, upload-time = "2026-07-10T19:31:57.616Z" },
+]
+
+[[package]]
+name = "build"
+version = "1.2.2.post1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "os_name == 'nt'" },
+ { name = "packaging" },
+ { name = "pyproject-hooks" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7d/46/aeab111f8e06793e4f0e421fcad593d547fb8313b50990f31681ee2fb1ad/build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7", size = 46701, upload-time = "2024-10-06T17:22:25.251Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5", size = 22950, upload-time = "2024-10-06T17:22:23.299Z" },
+]
+
+[[package]]
+name = "burner-redis"
+version = "0.1.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/52/89/54706febafc135095b2a9d797cfbd4eed2ab1ad7819808b99b587020471b/burner_redis-0.1.7.tar.gz", hash = "sha256:7474ff092669fd11ef765411572cdafcc3d89b8054aef4ca0617be6d6be4c680", size = 638644, upload-time = "2026-05-08T15:01:42.961Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6c/5d/198bd1d22e504b3034353430703afbdb3efe6e25cb90bf52d896e1d266a7/burner_redis-0.1.7-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f80c866996e0455d584eb3c0f3b067e411c632fb0519eab454e0968edf01e62c", size = 1288888, upload-time = "2026-05-08T15:01:26.103Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/4e/ce5c91b884ac37fcd380756402536f8810964014097950900517ce8bd30c/burner_redis-0.1.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:a3d9569a376b690fb5876d454e4904443332dc3ad5c0057e149fc2ad220bf599", size = 1234282, upload-time = "2026-05-08T15:01:28.286Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/c0/31c25cc88143eac2dddcc394151a0db627923d44c94376a83768552c9f13/burner_redis-0.1.7-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20eba1917e3bca9eea5957d5700ff8defcb5a209e57a7841d005549aa0151f44", size = 1337341, upload-time = "2026-05-08T15:01:30.397Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/32/95cfa1833316ca2b6b2e58150a4900bc1ad256043cdd36198f1887618ccc/burner_redis-0.1.7-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39111467059b8a28f15ea061d2414ec25c3e57c65759983f90f4d358e7d6a72d", size = 1366800, upload-time = "2026-05-08T15:01:32.891Z" },
+ { url = "https://files.pythonhosted.org/packages/34/ad/93c3916f053f89b7b5760da5bf855cd78b7885d480f9cfcc64f3732c1dc2/burner_redis-0.1.7-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9b5adfe99aeb8407f468078f3769b2a63e9168fea12f7709df5d2a3b152706e4", size = 1538160, upload-time = "2026-05-08T15:01:34.667Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/b9/19bae42cb124932d71168bc8e5bcb1da33aa62b908e5e632b3d298d7cb15/burner_redis-0.1.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:591a9d20685f9d6d22bf0c863b50b12dfcf328b06111b3f62c33cd3185d48ce0", size = 1591491, upload-time = "2026-05-08T15:01:36.708Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/30/207f47f406619a5b564355d2946c3171f84231a28b800709b5645b06a5ae/burner_redis-0.1.7-cp310-abi3-win_amd64.whl", hash = "sha256:f6cf4ac666766b32fd63940aad0c120847905fd3102c17e5b6b305f91a21d079", size = 1117564, upload-time = "2026-05-08T15:01:39.221Z" },
+ { url = "https://files.pythonhosted.org/packages/76/6f/e9beaf46c5e9fd10dfcdb889ebf7d3aa85142c650c0ab17ab284194f58e1/burner_redis-0.1.7-cp310-abi3-win_arm64.whl", hash = "sha256:458f88feeddfb40a586cc3fcbd8e9384bbdfd2a4512a695af4900e06052570d4", size = 1040407, upload-time = "2026-05-08T15:01:41.235Z" },
+]
+
+[[package]]
+name = "cachetools"
+version = "7.1.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/55/af/861ebc2e318a5c3300e3eb63bc4d30f3d70a46d13b360093728ac0705eed/cachetools-7.1.6.tar.gz", hash = "sha256:c7a79e7f30ba9943c1cefd08cc36f006aaae086e017af9166f1d59d6170c47e1", size = 40572, upload-time = "2026-07-23T22:47:53.737Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9f/f2/2086ba18a925a73586c4d4e61d25f4a6058e56fd00d77ce8f1d361ab4c9b/cachetools-7.1.6-py3-none-any.whl", hash = "sha256:2c12e255780330af28b91bb7fb96cce4c766f04e38396b9a24510190a5827096", size = 16954, upload-time = "2026-07-23T22:47:52.397Z" },
+]
+
+[[package]]
+name = "casadi-gil-comp"
+version = "3.6.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/23/e3f4e2c0a6ba06190f3d012cd0044251493661abf957a9765a23bf779558/casadi_gil_comp-3.6.7-cp311-none-macosx_10_13_intel.macosx_10_13_x86_64.whl", hash = "sha256:b2bd00e1657aab9aa6843be1c5727348ed9c71edbd9ba3a167312850c19018df", size = 44853123, upload-time = "2025-02-12T13:24:05.514Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/f4/73bff136577777adc7d3cf21a064dfdfb920db798e1380a8565f68a103df/casadi_gil_comp-3.6.7-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:577bf44952e6ff2be87e0f118ec2b6fa663d93f91b14e279fee57c4a041bfa73", size = 41021579, upload-time = "2025-02-12T13:24:21.243Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/54/e678166424eb3ee1f5bb411ccab5da008156f74283f934051d44097ba707/casadi_gil_comp-3.6.7-cp311-none-manylinux2014_aarch64.whl", hash = "sha256:6d4c50fa33f93356be26146189a116bcf8385877b4d3caf71056f1ad89d63793", size = 45174703, upload-time = "2025-02-12T13:24:37.95Z" },
+ { url = "https://files.pythonhosted.org/packages/99/23/0790be85c64674a21e8d5c2d6a7c0c828a8a2fef3f829156364bdd1fd258/casadi_gil_comp-3.6.7-cp311-none-manylinux2014_i686.whl", hash = "sha256:473f8ad13f7ec164c3c7f3edcc2c7e52250ba52f55365648cc73e79686f735ca", size = 71299379, upload-time = "2025-02-12T13:25:02.303Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/0f/a063cee015484bff556b49783f3662c86ebb30ad07baf5b7d1a11fbca014/casadi_gil_comp-3.6.7-cp311-none-manylinux2014_x86_64.whl", hash = "sha256:bfb48b4aea6d6cb27f83cea555f9484b15f4fbe997c41c17c3227f677807d536", size = 74276171, upload-time = "2025-02-12T13:26:03.033Z" },
+ { url = "https://files.pythonhosted.org/packages/66/34/a26f053c51ac637344118369f0c8a648ef2486d418df3e00b2ca5cc524f6/casadi_gil_comp-3.6.7-cp311-none-win_amd64.whl", hash = "sha256:f74e443b4555fd036297b8e5e19e4c0b91de77a6883712035d528714ef893691", size = 44951925, upload-time = "2025-02-12T13:26:21.016Z" },
+]
+
+[[package]]
+name = "certifi"
+version = "2026.5.20"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" },
+]
+
+[[package]]
+name = "cffi"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pycparser", marker = "implementation_name != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/57/5f/ff100cae70ebe9d8df1c01a00e510e45d9adb5c1fdda84791b199141de97/cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9", size = 531036, upload-time = "2026-07-06T21:34:30.382Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d3/67/85c89a59ba36a671e79638f44d466749f08179266a57e4f2ffdf92174072/cffi-2.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:02cb7ff33ded4f1532476731f89ede53e2e488a8e6205515a82144246ffa7dcc", size = 183845, upload-time = "2026-07-06T21:32:26.32Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/dd/e3b0baa2d3d6a857ac72b7efbf18e32e487c9cdafcc13049ad765495b15e/cffi-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f5bce581e6b8c235e566a14768a943b172ada3ed73537bb0c0be1edee312d4e7", size = 184186, upload-time = "2026-07-06T21:32:28.025Z" },
+ { url = "https://files.pythonhosted.org/packages/65/68/9f3ef890cf3c6ab97bd531c5677f67613d302165d16f8142b2811782a614/cffi-2.1.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:30b65779d598c370374fefabf138d456fd6f3216bfa7bedfab1ba82025b0cd93", size = 211892, upload-time = "2026-07-06T21:32:29.565Z" },
+ { url = "https://files.pythonhosted.org/packages/22/d7/1a74539db16d8bfd839ff1515948948efbb162e574650fd3d846896eea95/cffi-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88023dfe18799507b73f1dbb0d14326a17465de1bc9c9c7655c22845e9ddc3a2", size = 218793, upload-time = "2026-07-06T21:32:30.951Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/d1/9a5b7169499e8e8d8e636de70b97ac7c9447104d2ff1a2cd94790cea5162/cffi-2.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0a96b74cda968eebbad56d973efe5098974f0a9fb323865bf99ea1fd24e3e64c", size = 205737, upload-time = "2026-07-06T21:32:32.216Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/b0/e131a9c41f10607926278453d9596163594fe1c4ebc46efe3b5e5b34eb84/cffi-2.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a5781494d4d400a3f47f8f1da94b324f6e6b440a53387774002890a2a2f4b50f", size = 204909, upload-time = "2026-07-06T21:32:33.655Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/d2/4398416cd699b35167947c6e22aca52c47e69ad5695073c9f1f2c52e04aa/cffi-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aa7a1b53a2a4452ada2d1b5dade9960b2522f1e61293a811a077439e39029565", size = 217883, upload-time = "2026-07-06T21:32:35.173Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/a5/d4fe77b589e5e82d43ebc809bf2e6474afe8e48e32ea050b9357645b6471/cffi-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d8272c0e483b024e1b9ad029821470ed8ec65631dbd90217469da0e7cd89f1c", size = 221251, upload-time = "2026-07-06T21:32:36.527Z" },
+ { url = "https://files.pythonhosted.org/packages/22/f0/a2fc43084c0433caf7f461bccc013e28f848d04ee1c5ed7fce71423cf4d9/cffi-2.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7762faa47e8ff7eb80bd261d9a7d8eea2d8baa69de5e95b70c1f338bbe712f02", size = 214250, upload-time = "2026-07-06T21:32:37.852Z" },
+ { url = "https://files.pythonhosted.org/packages/04/8c/b925975448cf20634a9fbd5efceb807219db452653648d2897c0989cab2d/cffi-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89095c1968b4ba8285840e131bf2891b09ae137fe2146905acae0354fbce1b5e", size = 219441, upload-time = "2026-07-06T21:32:39.146Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/da/5c4918a2d61d86fa927d716cb3d8e4626ef8dc8f605a599d32f33897f59a/cffi-2.1.0-cp311-cp311-win32.whl", hash = "sha256:64c753a0f87a256020004f37a1c8c02c480e725f910f0b2a0f3f07debd1b2479", size = 174496, upload-time = "2026-07-06T21:32:40.467Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/c8/6c2de1d55cf35ef8b92885d5ef280790f0fb9634d87ea1cc315176aecd61/cffi-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:4f26194e3d95e06501b942642855aed4f953d55e95d7d01b7c4483db3ecff458", size = 185113, upload-time = "2026-07-06T21:32:41.761Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/4e/e8d7cb5783f1841a3c8fb3a7735838d7484d08ec08c9f984b14cac1ac0e9/cffi-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:35aaea0c7ee0e58a5cd8c2fd1a48fdf7ece0d2699b7ecdda08194e9ce5dd9b3d", size = 179927, upload-time = "2026-07-06T21:32:42.961Z" },
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.4.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" },
+ { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" },
+ { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" },
+ { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" },
+ { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" },
+ { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" },
+ { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
+]
+
+[[package]]
+name = "click"
+version = "8.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" },
+]
+
+[[package]]
+name = "cloudpickle"
+version = "3.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" },
+]
+
+[[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 = "coolname"
+version = "5.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fe/45/deae12f31934301a488df985880240a200119aca2e4b5ceba71d73bc5e86/coolname-5.0.0.tar.gz", hash = "sha256:594bc6c98ebc75ddd51c0ce10efbb5d2556c14eac60b5b36900dfdd5db20eecf", size = 45800, upload-time = "2026-04-23T06:04:50.824Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/97/35/cf824e535233c432048bd7455b28808776471ab5861375772b2c98ea4cbd/coolname-5.0.0-py3-none-any.whl", hash = "sha256:b86eea9670aa0620965167d1bfadfe654fabec839a5b51e8da611c4a64f86192", size = 47368, upload-time = "2026-04-23T06:04:49.374Z" },
+]
+
+[[package]]
+name = "coolprop"
+version = "6.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/13/88/35c88960cf20cf483f1e2127ad999fce4528451ad37173064cdcb3834ebf/CoolProp-6.6.0.tar.gz", hash = "sha256:cf6fad704b3ae00f4df309cfd1e2ee48d155886b569a73f2cc38a57eda463082", size = 13995226, upload-time = "2023-11-29T15:09:38.459Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/97/0d/f2bb30a984bfac131f31973dc6e03952393c418b7f82dacbdc8286e3d973/CoolProp-6.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cfe23e785e27ac4d12e0b13708a8bdc087caee8133fa0840509efaaf1ad311ba", size = 2787489, upload-time = "2023-11-29T15:08:10.756Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/cf/5aa6cf66554703a9b5a2a24deceb5784b9b7a1fd6eb55220bb61b8f1183e/CoolProp-6.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f374a948bc42babdf644f912958c79effa8ccc4f3f461a0f822715dcdf819c6b", size = 2552683, upload-time = "2023-11-29T15:08:12.468Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/83/5aa63e8638acad76b5cc468f9c4594f27fb969dcb10c7fd6918f40d29f37/CoolProp-6.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b43e70dfd9825a4de138ce76365978e24532711fb2f4781dacf2b92b96985ed", size = 7068222, upload-time = "2023-11-29T15:08:15.645Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/03/c1ade6e9be334bb1ce94583b3f6e4796e097a83ef3c43830ab98908600ac/CoolProp-6.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c46edd2dad3b99402ad2bff227a53182e0aba954847cac12686e78abd37ae1d", size = 7297130, upload-time = "2023-11-29T15:08:17.513Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/7e/e446c7b7767b69892b9f64c06368f793ff9952915ffdbb51ab5afd814d57/CoolProp-6.6.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b83370f50f85cf80ad6c010175b99d6ed7485e647ab70ca85772fecebdcfce86", size = 7314607, upload-time = "2023-11-29T15:08:19.415Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/3d/89ad9faf684e6c0171d13d2a2232dfad4fa59ff51a6f3dd2fc44368454af/CoolProp-6.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9bf37b539640e787250075e9042590f89bf83a1859c62d1695d2269d95fe7cff", size = 7549917, upload-time = "2023-11-29T15:08:21.178Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/46/f97c8fc66653996d92483478ed86944ed3be569b53c28c94321e698630ff/CoolProp-6.6.0-cp311-cp311-win32.whl", hash = "sha256:7b72406779cb17b4197d8bfbb90601f60a5ebb44b8c0c5882e8353021163783a", size = 1863473, upload-time = "2023-11-29T15:08:22.846Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/80/97d1ac40b23e953a25b3085a4c3194975d48f76a5dddeaf41869ffd6610d/CoolProp-6.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:b22c30a23603ce3df88a18a445fad14f93fd9757720f43d3b8041549e93c4b93", size = 2023020, upload-time = "2023-11-29T15:08:24.907Z" },
+]
+
+[[package]]
+name = "coverage"
+version = "7.14.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/54/fd/0ab2772530e946e1be1abd0bc09e647ec9b02e88f0867857601fefca8953/coverage-7.14.1.tar.gz", hash = "sha256:30c08f7d90415aa98b3c990385dea2939b0da55f38515e5b369b83655f8523be", size = 920132, upload-time = "2026-05-26T20:41:36.783Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7d/d7/477ad149490e6cb849f28abea1dabb9c823cea72e7500c81b4240ce619c0/coverage-7.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:478b5bcd63c2e1357c5c7e16c070690df7b07f676b1c114d7b93e533c664309f", size = 219848, upload-time = "2026-05-26T20:38:38.715Z" },
+ { url = "https://files.pythonhosted.org/packages/91/82/a5eb47257c50601bb7b9a9d2857c67b7a3a85ad74180eb2c98bb1fbe0ce5/coverage-7.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a24a81f9715ee42ef59a316cc11611c98fe23920f7c81861315c9f3ff4a230f4", size = 220354, upload-time = "2026-05-26T20:38:40.232Z" },
+ { url = "https://files.pythonhosted.org/packages/43/8b/78419b5391a5cb706b6544390507e469d83ffc9a8248b02c4011aceb9365/coverage-7.14.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:196a13319ad88d6d8ef5ab489ec4f44ddde2143c0c7d5b27786f6c3ffd56a7e1", size = 250771, upload-time = "2026-05-26T20:38:41.782Z" },
+ { url = "https://files.pythonhosted.org/packages/77/63/e77aaacd491182210d639636b7a8bba23ffffa9b82aa3762da9431855fa9/coverage-7.14.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d452fd08b5c72c5167c93e6867b5c08500bd40f2a21e1e854a500550b6cc36f", size = 252683, upload-time = "2026-05-26T20:38:43.305Z" },
+ { url = "https://files.pythonhosted.org/packages/65/1c/a022e3cfbec2ac241640003cb3a817e161d9c7f5aa9b49173756cdc03204/coverage-7.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23bf7fa51ac02e07fc7c96849b82946da47ae862dc8f86d183b2a4864fc38129", size = 254791, upload-time = "2026-05-26T20:38:45.361Z" },
+ { url = "https://files.pythonhosted.org/packages/61/d6/967e408aca4c1ceb88cb0cc677169110ae7f5995fb5eaf5fb1f5a1bb8f5d/coverage-7.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcaa50684dcaadfa599ac48f81103c756d791cfd85c97203d2217c593d48b860", size = 256748, upload-time = "2026-05-26T20:38:46.91Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/be/869188f7fe28638078ec479331ace6dc5f7b40b7153eb616f47ab79404d8/coverage-7.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4ea1c034f95c9b056e856b794630b17f9fa3d57e4800ff1e503d3be0f9c9078c", size = 250907, upload-time = "2026-05-26T20:38:48.493Z" },
+ { url = "https://files.pythonhosted.org/packages/07/aa/adb7d3b4278d690e68703abcd76ab1b948242e3668d921711551b78f9ddb/coverage-7.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7e057326434e441306226fbeb5d1aaf14a2637efe97ba668306635835f32ad7", size = 252483, upload-time = "2026-05-26T20:38:50.074Z" },
+ { url = "https://files.pythonhosted.org/packages/43/61/331c74103c62dcb0c4b9b3a0de9a61aca016208b0a90f109592a9f9ecc28/coverage-7.14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:59baf88468dbc8d63b1887afd92bda52e40bb1561696e5819670601403810cec", size = 250545, upload-time = "2026-05-26T20:38:51.613Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/b6/c5dae3c104d89be04828f61810e6b3473825482e4c288cc4ed04553e08ae/coverage-7.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d34d75f892b3ab73ba11cab5442cce7b3e168fd64162b16f0e1e0d09c508edef", size = 254310, upload-time = "2026-05-26T20:38:53.503Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/a1/2b9d5863e3b83c01ad8199e3c597802fbb3a9dc90b058885804c20296d31/coverage-7.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3a56abc20a472baf0304c455721bc601477440d28ecfde8a03dde79ede07e0df", size = 250266, upload-time = "2026-05-26T20:38:55.414Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/5e/0e511fbdb269359be26fe678a1c3fa1f2aa2a01573cc3f54268c8d6d4797/coverage-7.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6a3cb83d1552c0cd1b4906655b6a33fd4a8473229633a901c6b73bf86914dee9", size = 251174, upload-time = "2026-05-26T20:38:57.141Z" },
+ { url = "https://files.pythonhosted.org/packages/85/10/e55307b622b3dd9671cb321824502dc10f93e72f2802b9946159a8edadeb/coverage-7.14.1-cp311-cp311-win32.whl", hash = "sha256:10274a1fbeb8ec5d72966e17bb198a3104257aca4ac09d98667c5f8aca8c8548", size = 222354, upload-time = "2026-05-26T20:38:58.727Z" },
+ { url = "https://files.pythonhosted.org/packages/71/cf/107421693cfb71e4f1ca5bf70443f64d4161878068d07a3e51c7ad21d17b/coverage-7.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:87ebdf787d4888e3f3f2d523eadc6e18c6d18c6d0eb173801a189641627fb37e", size = 223290, upload-time = "2026-05-26T20:39:00.413Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/1d/3e3644585eb29e9dafefb19555078529a4d7cce12bd21929664eea989277/coverage-7.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:dd34767fa19848d35659ffc0a75314f58c7af3f1cd87ec521e8292a1238398a3", size = 221953, upload-time = "2026-05-26T20:39:02.159Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/3c/1a983b9a745d7f83d53f057bcc5bf79ba6a2bbc08266b3f0c7d6fe630c9b/coverage-7.14.1-py3-none-any.whl", hash = "sha256:a252f21c27e38347e60111a3266b03827422a7d5525951aceee313aa68bab1d2", size = 211815, upload-time = "2026-05-26T20:41:34.078Z" },
+]
+
+[package.optional-dependencies]
+toml = [
+ { name = "tomli", marker = "python_full_version <= '3.11'" },
+]
+
+[[package]]
+name = "cronsim"
+version = "2.7"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/1a/02f105147f7f2e06ed4f734ff5a6439590bb275a53dd91fc73df6312298a/cronsim-2.7-py3-none-any.whl", hash = "sha256:1e1431fa08c51dc7f72e67e571c7c7a09af26420169b607badd4ca9677ffad1e", size = 14213, upload-time = "2025-10-21T16:38:20.431Z" },
+]
+
+[[package]]
+name = "cryptography"
+version = "49.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1f/99/d1c90d6041656cc6ee229dc99cd67fd0cd5aec3c5f7d72fffc27cc750054/cryptography-49.0.0.tar.gz", hash = "sha256:f89660a348f4f78a92366240a61404e337586ef7f5909a2fef59ca88ef505493", size = 854345, upload-time = "2026-06-12T20:02:30.512Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:966fe0e9c67490071f14c0d2b1cb2dfb3023c5ce39457343931415f08382f2db", size = 4032100, upload-time = "2026-06-12T20:02:32.143Z" },
+ { url = "https://files.pythonhosted.org/packages/09/41/3797cfaf69cae04a13ee78ebd83f0678d9c02b4779d21ce24445326f1a69/cryptography-49.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:36d1709f992593689b45bda411498d62c6e365f2ca00b84657d4dadd24de16db", size = 4692978, upload-time = "2026-06-12T20:01:21.305Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/8b/43011f7ebe515a8aa20d61f290a326cd890c2e738e16e59eaff8d9c3a412/cryptography-49.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0e959b578856a3924bc0cbb710fc12c387b9412a951389f3ca61704a9e25f325", size = 4716422, upload-time = "2026-06-12T20:01:48.566Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/91/01ce7303a4579e6d3a6abef01bd322848e9ea7a219adcabc5048b9033571/cryptography-49.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:53ecee2e23f7169b6117e99fc8a944e5e50f79e69758a83b52a00cb98ab2b2d2", size = 4700503, upload-time = "2026-06-12T20:02:47.091Z" },
+ { url = "https://files.pythonhosted.org/packages/62/99/a2c95cf8293f07491e9e27c20cc4dcd18176d944e674679adeb1d0173fd6/cryptography-49.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:2eda353d8a27bcbcaa4cbed18994a74ab4d19a2ca897db188ea269ab9b71419b", size = 5309779, upload-time = "2026-06-12T20:02:08.987Z" },
+ { url = "https://files.pythonhosted.org/packages/20/2c/0622f20ff02b2ef32558733443805dc82fd4c275be01b2d19d14676f3a1b/cryptography-49.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2afe9051da7ae7bd5905da5a949280c7d2bb75682e188f650a9d0f2756b834c6", size = 4749683, upload-time = "2026-06-12T20:02:03.335Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/5b/c5246635d5fd3b64e0d45ae10e99fd32fe9676a79915ccfe5a61ba9af1a5/cryptography-49.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:0b82e28ee398a386f0807bba7884d30f25218855690f45115831bcce5d90822c", size = 4337874, upload-time = "2026-06-12T20:02:54.323Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/88/05563c7fe2e914e87d1a536d06fe83e66b4e1d95cb593e05aea375531da8/cryptography-49.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ccac2bfebc306b862133e3bb71f3f6ee8bb525240089b2d952e4144b3a6d5da7", size = 4700283, upload-time = "2026-06-12T20:01:34.822Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/b6/d7696e4e890d6ae1469935164c9e5215c557671cb78d6e3f458ccceaa632/cryptography-49.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:d0527ce944105f257f605a827d6ebead966c752038b6e8656abb9c5edee6fc68", size = 5265844, upload-time = "2026-06-12T20:01:24.09Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/3c/f3ad17eecc1a57b0ba236dc01f90e783c51f4a2f35f64777cc4f47a184b2/cryptography-49.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:cbc77da8c523d5abd028635ba850a6966fcee2c82e2bf65a41d1d8afe0f98be9", size = 4749290, upload-time = "2026-06-12T20:01:30.848Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/01/339573cf1023163a400b0b5d16f6d507de413b9f60be6fd1b77feeaf6737/cryptography-49.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b87e65d263b3e5d3bb92a57e2a6638e2f31110fa7aa890c7b2dbba42248d0a3f", size = 4834612, upload-time = "2026-06-12T20:01:29.246Z" },
+ { url = "https://files.pythonhosted.org/packages/71/fd/577302e213a1be9468f92d1afef66fcf1ef83d516819d9992ca547f592bd/cryptography-49.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:66ec79c3904820572d7e987abdf304281f141d37ad9a489b8e97066e7b9b6459", size = 4980804, upload-time = "2026-06-12T20:01:42.853Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/09/f42b1d190c5ba75f72062a387f8030d1d75f6ab035788f1d9c4b01de6525/cryptography-49.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:e5dfc1e64de5677cec922ffa8da89c546d0415bf6efdf081842e5d44c84e1f0e", size = 3810026, upload-time = "2026-06-12T20:02:39.262Z" },
+ { url = "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ec5e529fb80935c94fe7b729f9972b50e351a0e6b50aa294fd5cabb109fcc29a", size = 4025947, upload-time = "2026-06-12T20:01:25.745Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/df/40577043ca124e17012f408ddddaeb213b856336ac82ddb3bc915f39e29f/cryptography-49.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f78ff2c9ed8dc2d036b0f4d640e22522213d047c1b14e61205a7e55c80a494d4", size = 4692429, upload-time = "2026-06-12T20:01:53.628Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/99/2d13299eb3dd27b02dcfaafcc91d6b5cb3329f7cbd6d8f51921acd566c1a/cryptography-49.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:35b151772baff2c74cba7fa290ceaff4c3b11c0c881eb93eb5dbc05a7cfbba18", size = 4700968, upload-time = "2026-06-12T20:02:45.383Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/4d/9c0cd02f95e2602dd5e563da149ee0830abef3537be8b34dc56281ebe27a/cryptography-49.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0f21641cf4b30fca7aee061ced0ec7ad7b073518088b7c9969a297c0ae796c69", size = 4697758, upload-time = "2026-06-12T20:01:41.13Z" },
+ { url = "https://files.pythonhosted.org/packages/24/01/186c825898477d77e2324d5360fefe622ff1d8d1963ec0554e2cada8ec77/cryptography-49.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9e82dcc8e56052715fb18b2429e3bca4823b1629136a2084fc45a9a5cecb9b64", size = 5298863, upload-time = "2026-06-12T20:02:24.579Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/7b/62cbbab75d0659865bf0273790031544a0b16c8072d258f9428dcd8190dc/cryptography-49.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6f2debedf9ca60cf1d5bd466475638af5130f89965605cd818484d19987d3a21", size = 4735983, upload-time = "2026-06-12T20:01:50.14Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/72/3e798c064bc39e471008075d0f9bc9daf77a80879c092e4a8e170c585ed4/cryptography-49.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:8c25ceb16df5b9435f3f6a9829204985b0e0cbee3b48aacd432c7d2c850b44d9", size = 4334173, upload-time = "2026-06-12T20:01:44.743Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/ee/6fca21d1ac73e06f8bef71940abfd4d2f6472b4bca284d770f32bd4086f6/cryptography-49.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:28d8b15e6275f12c8a207dc309dfa957903c927d08d0cc937ee3f63f200693cc", size = 4697298, upload-time = "2026-06-12T20:02:20.918Z" },
+ { url = "https://files.pythonhosted.org/packages/67/d0/a5fcd3515f0bae49a7b6d0413cc1bdccdcc1fc0047037a0d480642cdc5d6/cryptography-49.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6fc361c34fb6aac015ce19435876635e5c6d21db31998b0920f675f131e043b8", size = 5254338, upload-time = "2026-06-12T20:02:22.737Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/84/84fe36f19caf857d61cb7fc9c63035a47ffabd84ea12d1d393148efa3615/cryptography-49.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2400ef9c9e2299a25614eb1dea3db54a69b1349efd043bfac9c67630d136df36", size = 4735650, upload-time = "2026-06-12T20:02:41.389Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/a0/db537264e234f7273a73ec020873d6d6b39dfd8a53db78b550ca8320440e/cryptography-49.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:67e1d20ad9ef3a563c59ef22e7a8a0b8210bd26604369ea4a30a7c66aefe504e", size = 4834820, upload-time = "2026-06-12T20:01:51.847Z" },
+ { url = "https://files.pythonhosted.org/packages/93/77/8df9eb486495979bccecd1062e2eaf435250e84437040295b57d09048b0b/cryptography-49.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:42b0684e0e40cf26122427802486f6d93aea593612603a94fbf260c7eb1e9c1b", size = 4967968, upload-time = "2026-06-12T20:02:12.524Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/e6/f60198ea8d9dfa15fff9ed4ca02ce362f6eadd9ba757dcc50634c4257b63/cryptography-49.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:026ac7423e6fa66872d3bf889be5974507da3944f866f704fa200eadacd00001", size = 3785547, upload-time = "2026-06-12T20:02:26.847Z" },
+ { url = "https://files.pythonhosted.org/packages/63/d3/4a83af35d65e3fad632c926fad684c193ea4398569ccb0bbbc7fe8f5dc9a/cryptography-49.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc1e275c2f1d97b1a6450b8b0ea3ebfa6e087a611c2b26cb2404d48588abab7b", size = 3993685, upload-time = "2026-06-12T20:02:14.883Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/a7/f9dac0ab7f80368c56993a7bf638ef9935f825c91902798481fac0898138/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83782480a4a9da4d0feb51950131ba32e12e70813848b3343f6e18c28a66838", size = 4676239, upload-time = "2026-06-12T20:02:28.793Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/70/2ba3769dd0ae167e2f33dfa9592d45db6ff9a61d62ca1a5b3d1bdd09068f/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b39efa323140595abd3ecca8529d321ae50f55f3aa3ba9cc81ea56a6011953d5", size = 4715584, upload-time = "2026-06-12T20:01:27.495Z" },
+ { url = "https://files.pythonhosted.org/packages/94/64/2923570ac1c0bd3a737aa366ac3abbbbde273042308b8cde95e2364a6e6a/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:b47db11c2c3525083296069b98ac5221907455e989ae0c2e3008bde851921615", size = 4675885, upload-time = "2026-06-12T20:01:55.49Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/f8/614dc7e051418cfe53d55173c1e24c6b0085e89996fe90508c2fdf769aef/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:084ef1af862eb07ec46d25f68689f2102a9fc0e05ce7b80f14f5fe51e4eef0f6", size = 4715449, upload-time = "2026-06-12T20:02:05.469Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/50/a9caea39ad19c431c1a3f8a31114df65b260cdfe67786b6c7e7c040c4c44/cryptography-49.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be9fcb48a55f023493482827d4f459bd263cc20efde64f204b97c123201850c6", size = 3783731, upload-time = "2026-06-12T20:02:43.319Z" },
+]
+
+[[package]]
+name = "cyclopts"
+version = "4.22.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "docstring-parser" },
+ { name = "rich" },
+ { name = "rich-rst" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/69/98/ca72a91d5c25a2ae1baf19d27b31f12288cb9d8a3168b65b3cd54d40d277/cyclopts-4.22.2.tar.gz", hash = "sha256:0721e90e7209885e78f7637cfba255c12e89206b633e35d185305e349ba20ecd", size = 194511, upload-time = "2026-07-24T20:53:08.739Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/75/a11bfb5045e58b4ef69337b848985918e829fe9a90572a761d17c1a992f5/cyclopts-4.22.2-py3-none-any.whl", hash = "sha256:9c2cdf6a621886cd0af631a67437eb7d0084f33f9e8fba2d2562a1aecf75f2ff", size = 233906, upload-time = "2026-07-24T20:53:07.064Z" },
+]
+
+[[package]]
+name = "dateparser"
+version = "1.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "python-dateutil" },
+ { name = "pytz" },
+ { name = "regex" },
+ { name = "tzlocal" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d3/f4/561c49bca97af561d34eed27e3e831135eb5cb88e754c1150be41820f5c6/dateparser-1.4.1.tar.gz", hash = "sha256:f265df13c0380e2e07543ba74b67c0681aaa1096981ffcd35227e1aa0cb81c7c", size = 314734, upload-time = "2026-06-15T08:45:47.659Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8b/7c/2e5dcf53909deddd0bf38cbe277ad9806be038276b1c6c436561b4d9b2e2/dateparser-1.4.1-py3-none-any.whl", hash = "sha256:f25d4e051a84be27a35bd297e3e1dc59ff78373701b89be352ba80372d22d0d0", size = 300503, upload-time = "2026-06-15T08:45:45.951Z" },
+]
+
+[[package]]
+name = "defusedxml"
+version = "0.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" },
+]
+
+[[package]]
+name = "docker"
+version = "7.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pywin32", marker = "sys_platform == 'win32'" },
+ { name = "requests" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/88/7f/731ff914b0255d3d065f45fd4e626d4b8c95dbcbaada049f337a6ac16410/docker-7.2.0.tar.gz", hash = "sha256:cebb93773d334f778e023a7ee352a8d6e13ab1bd3b863a4d4a59dec897df43ac", size = 118731, upload-time = "2026-07-09T14:53:46.39Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/75/23/529140fe1aab80fc6992f93a706deec709140a6397439139a054e1515c45/docker-7.2.0-py3-none-any.whl", hash = "sha256:a3f45fdeb9165e2d25d9a1d02ddf3bc70fb572cf5ebbf9b58558c22caf29b71f", size = 148775, upload-time = "2026-07-09T14:53:45.224Z" },
+]
+
+[[package]]
+name = "docstring-parser"
+version = "0.18.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e0/4d/f332313098c1de1b2d2ff91cf2674415cc7cddab2ca1b01ae29774bd5fdf/docstring_parser-0.18.0.tar.gz", hash = "sha256:292510982205c12b1248696f44959db3cdd1740237a968ea1e2e7a900eeb2015", size = 29341, upload-time = "2026-04-14T04:09:19.867Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl", hash = "sha256:b3fcbed555c47d8479be0796ef7e19c2670d428d72e96da63f3a40122860374b", size = 22484, upload-time = "2026-04-14T04:09:18.638Z" },
+]
+
+[[package]]
+name = "et-xmlfile"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" },
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+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 = "fastapi"
+version = "0.140.10"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-doc" },
+ { name = "pydantic" },
+ { name = "starlette" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/60/3a/4734b861d4471653ad4c3c86af25904bde8adabc6357e9b400f7f80451bc/fastapi-0.140.10.tar.gz", hash = "sha256:e05c183a57e1084708c34e43b5305494046c28a798b753f94ba96691f5394262", size = 423129, upload-time = "2026-07-28T14:21:30.866Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/bf/19aaed94c5f893555520cd539f08b4eebe6741154a3fd8b4a4216448ab95/fastapi-0.140.10-py3-none-any.whl", hash = "sha256:d545b4a3a3a0d5a1ce99d28b38568b0b228bcc47490af150f7c87691df6bc7a5", size = 131128, upload-time = "2026-07-28T14:21:29.445Z" },
+]
+
+[[package]]
+name = "frozenlist"
+version = "1.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" },
+ { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" },
+ { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" },
+ { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" },
+ { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" },
+ { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" },
+ { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
+]
+
+[[package]]
+name = "fsspec"
+version = "2026.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/10/a1/ae4e3e5003468d6391d2c77b6fa1cd73bd5d13511d81c642d7b28ac90ed4/fsspec-2026.6.0.tar.gz", hash = "sha256:f5bac145310fe30e16e1471bd6840b2d990d609e872251d7e674241822abf01a", size = 313646, upload-time = "2026-06-16T01:57:28.105Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl", hash = "sha256:02e0b71817df9b2169dc30a16832045764def1191b43dcff5bb85bdee212d2a1", size = 203949, upload-time = "2026-06-16T01:57:26.358Z" },
+]
+
+[[package]]
+name = "future-fstrings"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5d/e2/3874574cce18a2e3608abfe5b4b5b3c9765653c464f5da18df8971cf501d/future_fstrings-1.2.0.tar.gz", hash = "sha256:6cf41cbe97c398ab5a81168ce0dbb8ad95862d3caf23c21e4430627b90844089", size = 5786, upload-time = "2019-06-16T03:04:42.651Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ab/6d/ea1d52e9038558dd37f5d30647eb9f07888c164960a5d4daa5f970c6da25/future_fstrings-1.2.0-py2.py3-none-any.whl", hash = "sha256:90e49598b553d8746c4dc7d9442e0359d038c3039d802c91c0a55505da318c63", size = 6138, upload-time = "2019-06-16T03:04:40.395Z" },
+]
+
+[[package]]
+name = "graphviz"
+version = "0.21"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f8/b3/3ac91e9be6b761a4b30d66ff165e54439dcd48b83f4e20d644867215f6ca/graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78", size = 200434, upload-time = "2025-06-15T09:35:05.824Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" },
+]
+
+[[package]]
+name = "greenlet"
+version = "3.5.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a3/74/b13368064b09053253555d3f2839cc2684d22d5aed0d2ccffbf7a6736558/greenlet-3.5.4.tar.gz", hash = "sha256:0232ae1de90a8e07867bb127d7a6ba2301e859145489f25cda8a6096dabe1d20", size = 206538, upload-time = "2026-07-22T12:47:14.468Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/61/16/71eefcf68267bbf06a9b6bff57d0b222e49432326e85d74348b67694b8d4/greenlet-3.5.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e883de250e299654b1f1680f72a1a9f9ba62c9bd1bce84099c90657349a8dfbb", size = 294266, upload-time = "2026-07-22T11:37:56.142Z" },
+ { url = "https://files.pythonhosted.org/packages/36/ea/a0b19adfc35d07e10acb626e9d22a3893b95f1309c42c4a20161dec16800/greenlet-3.5.4-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32802705c2c1ff25e8237b3bdacf2594fa02be80af8a66703eb7853ea7e68686", size = 613712, upload-time = "2026-07-22T12:26:39.375Z" },
+ { url = "https://files.pythonhosted.org/packages/54/76/a121978b3337407d05a1ce5f79b4aa5998a43a9d8422f9726029b90b4471/greenlet-3.5.4-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57aa201b351f7c7c75627c60d29e4d5b97a07d37efeb62b903466fca42c097d7", size = 625582, upload-time = "2026-07-22T12:29:00.814Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/4a/f301f1d85c69a86b90b5d581a73e8927bba4e79450037e6e2cbca05eb4fd/greenlet-3.5.4-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9667862a2e38ad379f11b845daeda22c8989186def44f06962c9c4c05e556da7", size = 633429, upload-time = "2026-07-22T12:43:42.073Z" },
+ { url = "https://files.pythonhosted.org/packages/34/c2/080f16cf870e929e592f55767f01d6c98d2ee83bfdc36c3b892f2d0459ab/greenlet-3.5.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c3fe76c2cac86b4f7a1e92865ac0a54384deb05c92986287c1a7110d9bd53071", size = 624663, upload-time = "2026-07-22T11:51:08.016Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/2e/26884072b0eb343a4d5fee903341bfe5171b32b7f14553886e2b6349135a/greenlet-3.5.4-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:ae53534b5dec0f4c2ec26f898f538dc8ea1ca3ef2927d597a9439e40a09da937", size = 428238, upload-time = "2026-07-22T12:39:49.973Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/bb/8f3ca88370b817369008faeceeee85970adc16c92a70a3e5fe5fea495a57/greenlet-3.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1e1a4a684b16c45ba324e60b32a4386a87722bcb815d2a149d2182f9b401ca72", size = 1585010, upload-time = "2026-07-22T12:25:02.539Z" },
+ { url = "https://files.pythonhosted.org/packages/51/c2/45877154689709ebce9a0b83c2235e6ca0f31577889b02af308c8cc5f8fb/greenlet-3.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e849e6e139b9671adeac505f72fc05f4af7fd1921faef40295e214fc3b361b59", size = 1651283, upload-time = "2026-07-22T11:51:10.408Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/7d/8711a75cb61d85246277c07ff6e1a6504621ba473d808c11ad225ffca43f/greenlet-3.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:dc418cf4c873357964d6624445ed09472e50def990c65dd4e76fc3ba8cd9cef6", size = 246434, upload-time = "2026-07-22T11:43:15.557Z" },
+ { url = "https://files.pythonhosted.org/packages/00/62/e290b3bce433da8f0324ac02da0b128d683482229f1a8b789fa47818a4cd/greenlet-3.5.4-cp311-cp311-win_arm64.whl", hash = "sha256:c38c902a0986eba1f6e7ba1ab39ad5195926abde90f3fe080e08212db62176da", size = 244990, upload-time = "2026-07-22T11:39:22.626Z" },
+]
+
+[[package]]
+name = "griffe"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "griffecli" },
+ { name = "griffelib" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/00/44/63913c007814cab5ba9d36f25ad40dfc640c2e2931d195bd2d05f774a5d6/griffe-2.1.0.tar.gz", hash = "sha256:c58845df5a364feaabd05ee8c767b97b03e478da8aa18b9923553c812fb0d955", size = 244879, upload-time = "2026-06-19T12:05:41.262Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6b/fb/3c65d392feae6c36dc2b55a14dd8270b7b35a3171c93b71a4d2ee4abf241/griffe-2.1.0-py3-none-any.whl", hash = "sha256:2ccdab17fb9cd76f278d7b5611cfc8f68cbe846d8d48df63dff80b62ecfa6f65", size = 5140, upload-time = "2026-06-19T12:05:39.913Z" },
+]
+
+[[package]]
+name = "griffecli"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama" },
+ { name = "griffelib" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8e/c6/90f85d47af96300d629b38c25b71aad9467a620cac964a39280e822efc8a/griffecli-2.1.0.tar.gz", hash = "sha256:2ff68dbee9395fdb668b10374c51683392d697b226ac60159798f4add1ee716c", size = 56913, upload-time = "2026-06-19T12:05:43.119Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/80/2f/513232ec1d5f5da182e4ce45a11427e37dd210844a9e2bca451fc9661fb3/griffecli-2.1.0-py3-none-any.whl", hash = "sha256:6e22b1423d562ddc510997b4be1fe89de59e19dcff78831c0f4bfc3b8134a718", size = 9500, upload-time = "2026-06-19T12:05:37.517Z" },
+]
+
+[[package]]
+name = "griffelib"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/33/e4/8d187ea29c2e30b3a09505c567513077d6117861bde1fbd997a167f262ec/griffelib-2.1.0.tar.gz", hash = "sha256:762a186d2c6fd6794d4ea20d428d597ffb857cb56b66421651cbba15bdd5e813", size = 216234, upload-time = "2026-06-19T12:05:42.278Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e4/d3/5268aeabf2ad82658c4e2ff3a060648d0f02f3926cb53247c0e4d0dab49e/griffelib-2.1.0-py3-none-any.whl", hash = "sha256:cc7b3d2d2865ad0b909fcc38086e3f554b5ea7acbaa7bbb7ecaa3f5dfb7d9f00", size = 142560, upload-time = "2026-06-19T12:05:38.742Z" },
+]
+
+[[package]]
+name = "h11"
+version = "0.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
+]
+
+[[package]]
+name = "h2"
+version = "4.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "hpack" },
+ { name = "hyperframe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/30/d4/a7d6fb3f58be99d65cbf2d3f766896217a2921d0f3ab10711c45dc1519ee/h2-4.4.0.tar.gz", hash = "sha256:46b551bdcdc7e83cf5c04d0bf93badb8a939bd2287d9fee1abb23a445b9e0580", size = 2156691, upload-time = "2026-07-23T19:14:19.442Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f6/df/5b14a118322d6097cb9bb30ec6bacad268e546a8ecfcb1f6d0de618dac2f/h2-4.4.0-py3-none-any.whl", hash = "sha256:6acffe1aeab79098d7eb0f8385c1add11f2c7a94815f6fa2b7060eeddee3d87c", size = 62368, upload-time = "2026-07-23T19:14:16.143Z" },
+]
+
+[[package]]
+name = "hpack"
+version = "4.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/26/5b/fcabf6028144a8723726318b07a32c2f3314acdff6265743cf08a344b18e/hpack-4.2.0.tar.gz", hash = "sha256:0895cfa3b5531fc65fe439c05eb65144f123bf7a394fcaa56aa423548d8e45c0", size = 51300, upload-time = "2026-06-23T18:34:46.667Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl", hash = "sha256:858ac0b02280fa582b5080d68db0899c62a80375e0e5413a74970c5e518b6986", size = 34246, upload-time = "2026-06-23T18:34:45.472Z" },
+]
+
+[[package]]
+name = "httpcore"
+version = "1.0.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
+]
+
+[[package]]
+name = "httpx"
+version = "0.28.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "certifi" },
+ { name = "httpcore" },
+ { name = "idna" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
+]
+
+[package.optional-dependencies]
+http2 = [
+ { name = "h2" },
+]
+
+[[package]]
+name = "humanize"
+version = "4.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0a/ea/13a1ef3c12d12662905801495283530251918b70d62d368f1d2e0272c70d/humanize-4.16.0.tar.gz", hash = "sha256:7dc2244a2f84a4bfb1d36c37bac80cd78e35cdc5c119206d87b018e1445f3a3f", size = 89515, upload-time = "2026-06-30T16:17:29.859Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b0/aa/0b7365d30fed43e7a3449aba1fe20a0a7174d9cf13e282af4e69ac825441/humanize-4.16.0-py3-none-any.whl", hash = "sha256:353eb2f34c09d098b2880eee8bef21832eae6d174f48c5762fff7e5fcb74d01d", size = 137209, upload-time = "2026-06-30T16:17:28.36Z" },
+]
+
+[[package]]
+name = "hyperframe"
+version = "6.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" },
+]
+
+[[package]]
+name = "idna"
+version = "3.18"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" },
+]
+
+[[package]]
+name = "influxdb"
+version = "5.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "msgpack" },
+ { name = "python-dateutil" },
+ { name = "pytz" },
+ { name = "requests" },
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/86/4f/a9c524576677c1694b149e09d4fd6342e4a1d9a5f409e437168a14d6d150/influxdb-5.3.1.tar.gz", hash = "sha256:46f85e7b04ee4b3dee894672be6a295c94709003a7ddea8820deec2ac4d8b27a", size = 67385, upload-time = "2020-11-11T21:23:44.167Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/01/95/3a72ea5e19df828d27af0a50092f2b24114a5f89922efb4d8a0960bf13ef/influxdb-5.3.1-py2.py3-none-any.whl", hash = "sha256:65040a1f53d1a2a4f88a677e89e3a98189a7d30cf2ab61c318aaa89733280747", size = 77906, upload-time = "2020-11-11T21:23:41.567Z" },
+]
+
+[[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 = "jinja2-humanize-extension"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "humanize" },
+ { name = "jinja2" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/74/77/0bba383819dd4e67566487c11c49479ced87e77c3285d8e7f7a3401cf882/jinja2_humanize_extension-0.4.0.tar.gz", hash = "sha256:e7d69b1c20f32815bbec722330ee8af14b1287bb1c2b0afa590dbf031cadeaa0", size = 4746, upload-time = "2023-09-01T12:52:42.781Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/26/b4/08c9d297edd5e1182506edecccbb88a92e1122a057953068cadac420ca5d/jinja2_humanize_extension-0.4.0-py3-none-any.whl", hash = "sha256:b6326e2da0f7d425338bebf58848e830421defbce785f12ae812e65128518156", size = 4769, upload-time = "2023-09-01T12:52:41.098Z" },
+]
+
+[[package]]
+name = "jmespath"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" },
+]
+
+[[package]]
+name = "jsonpatch"
+version = "1.33"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "jsonpointer" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" },
+]
+
+[[package]]
+name = "jsonpointer"
+version = "3.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/18/c7/af399a2e7a67fd18d63c40c5e62d3af4e67b836a2107468b6a5ea24c4304/jsonpointer-3.1.1.tar.gz", hash = "sha256:0b801c7db33a904024f6004d526dcc53bbb8a4a0f4e32bfd10beadf60adf1900", size = 9068, upload-time = "2026-03-23T22:32:32.458Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl", hash = "sha256:8ff8b95779d071ba472cf5bc913028df06031797532f08a7d5b602d8b2a488ca", size = 7659, upload-time = "2026-03-23T22:32:31.568Z" },
+]
+
+[[package]]
+name = "jsonschema"
+version = "4.26.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "jsonschema-specifications" },
+ { name = "referencing" },
+ { name = "rpds-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" },
+]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2025.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "referencing" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
+]
+
+[[package]]
+name = "lxml"
+version = "6.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40", size = 4197430, upload-time = "2026-05-18T19:19:06.424Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/62/b0/83f481780d1548750b8ce2ec824073deef2f452d9cd1a6faff8507e3d16d/lxml-6.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:53b7d2b7a10b1c35c0a5e21e9224accf60c1bbfba523990732e521b2b73adef2", size = 8526461, upload-time = "2026-05-18T19:17:25.862Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/d5/30fa0f808002c7329397bfbb24e306789c0b29f04aa5842c07b174b4216f/lxml-6.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ff3f333630ab480244a1bff72043e511a91eb22e7595dead8653ee5612dd8f3d", size = 4595375, upload-time = "2026-05-18T19:17:34.555Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/d2/edb71cf0e561581a7c5eb2626244320eb04e9f8ce6d563184fd668b45073/lxml-6.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a4bbea04c97f6d78a48e3fbc1cb9116d2780b1b39e03a23f6eb9b603fd61f510", size = 4923654, upload-time = "2026-05-18T19:17:42.917Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/77/1bc7eeb0de4577d783fb625aa092cc9357883bba35845a3666bf1259f3dc/lxml-6.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db1d75f6617a49c1c01bc7023713e0ff59ab32c9579ae62a7674c0e34f3b0b0a", size = 5067921, upload-time = "2026-05-18T19:17:49.175Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/3c/c0690d74bd2bc17bc03b5b0d093569ead597dd0bfa088bf99eef8c24e19c/lxml-6.1.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a12689be69a28ddaa0ab99a5a1137da2afd5f8f16df7b5680b66f616d3eda1d", size = 5002456, upload-time = "2026-05-18T19:17:59.715Z" },
+ { url = "https://files.pythonhosted.org/packages/66/8d/d1b3271af0c0f1e27e8472a849e4d2c65bc7766884b9ad2da9e76e145c88/lxml-6.1.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b73c339ae29b90fd2d06e58ebd555a751bde9cd6bbd36cc0281b9a2c94e9d8", size = 5202776, upload-time = "2026-05-18T19:18:08.924Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/45/689824ffb237fd10125ad273f32b28ff04dc6203c2822c85ff65a93df65e/lxml-6.1.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:752d3bbfe874715ccd0aec7f88d7fc623c0f1fd7aa7b3238a084e017bad2a009", size = 5329945, upload-time = "2026-05-18T19:18:13.673Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/c0/ef73af53767e958fd87d437c170f272e2f6e6c0f854939f133a895f1e711/lxml-6.1.1-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:6b1761fbf9ec984e2e9d9c589ef5f5fd684b7c19f92aadd567a26c5224958db6", size = 4659237, upload-time = "2026-05-18T19:18:18.657Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/5e/e1158e40397585e91cb0472374a1f63d0926a1ddeaa92f13d1a1ffe306d5/lxml-6.1.1-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d680fbcb768404c601ecb43519ecd8461f6954cb11c06a78962f666832ccfca8", size = 5265904, upload-time = "2026-05-18T19:18:24.883Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/16/8687e5d1400ed1c0bc41dace232ebb7553952b618ea1f2e5fb6e2cfbbe23/lxml-6.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:162af1091cd785f2f27e62d3547ae9bc58ec5c86dd314d67021fd02463708d83", size = 5045225, upload-time = "2026-05-18T19:17:20.073Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/18/d877bd1ae2e5ffdfd4836565aba350db31feb2f2656d6ce70316ed66a05e/lxml-6.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e9308ff8241c532df3f3e570f9a5aeed6c853f888512ba4b75638d7c11c95ef6", size = 4712721, upload-time = "2026-05-18T19:17:40.512Z" },
+ { url = "https://files.pythonhosted.org/packages/44/4d/1f44fd1d770b10dacbf6b5c6e520f4d6e0708744930f719dc04e67cab981/lxml-6.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5f6994074ebae6ffb04447268e37dc16edc304f9859cf91acb86e0af6c1b395c", size = 5252549, upload-time = "2026-05-18T19:17:51.236Z" },
+ { url = "https://files.pythonhosted.org/packages/64/5d/1d66b84f850089254c230ef6ea6b267a5a54e2e179a5d960036a05d501d7/lxml-6.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80c2dfadb855da477cf73373ad29a333535dedb9b12bad02c9814c8e2b43bf08", size = 5226877, upload-time = "2026-05-18T19:18:00.875Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/00/84c4b5302d42a2d0184f38d538c8a197f33b52a50bd4f7bcfe990bce3036/lxml-6.1.1-cp311-cp311-win32.whl", hash = "sha256:30a89d3ac8faec007453fb541f3f46807eeec88edd5826f6e3fe001752a2c621", size = 3594072, upload-time = "2026-05-18T19:17:12.714Z" },
+ { url = "https://files.pythonhosted.org/packages/61/9d/2e2f7d876349f45e0f3e29f72da311668853d59b58d473a2dea4f0160135/lxml-6.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:abbefa31eee84842140f67acef1c828e28bba8bbf0c3bc6e5492a9af88152c28", size = 4025469, upload-time = "2026-05-18T19:17:50.566Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/d5/570e6390e4110331e6208b2ba83d1482cc9146808ee118b22824a34c1070/lxml-6.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:dcb292aa7fe485ceff7af4f92e46c5af397daec5dff64871a528f0fc47a3cc5b", size = 3667640, upload-time = "2026-05-19T19:22:48.293Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/32/86a3f0f724a3a402d4627937a7fc27b160e45e7012b4adf47f6e1e844511/lxml-6.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:31033dc34636ea6b7d5cc11b1ddbda78a14de858ba9d3e1ed4b69a3085bc521e", size = 3930127, upload-time = "2026-05-18T19:19:02.27Z" },
+ { url = "https://files.pythonhosted.org/packages/40/44/d832e82af08723761556d004b1d04d281c09f9a8cecd7d3148548c9941a3/lxml-6.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3893c14c4b6ac5b2d54ba8cf03e99fe5104e592de491f19bd6b82756c09f8004", size = 4210769, upload-time = "2026-05-18T19:20:41.427Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/39/0dc5949f759ed7d951e0bb8c2f2d9d7aca1908d22352fa84a8afd2ea54af/lxml-6.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c07da4cebf6889f03ebac8d238f62318e29f495de0aa18a51ea14e61ae907e2e", size = 4318163, upload-time = "2026-05-18T19:20:44.702Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/fb/8ab3845fe046ba4cbf74536bcf6801a774b7caf4350de1c5d37f1f0a9e90/lxml-6.1.1-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6f0ce10945fab9c4c06ce14e22af9059d1a87493a9af4501a5b0b9187e21cf2", size = 4250945, upload-time = "2026-05-18T19:20:47.385Z" },
+ { url = "https://files.pythonhosted.org/packages/68/1b/7553ab136894374ffae8851ec06f98f511cd8e66246e41b6be059d0a7289/lxml-6.1.1-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f8844cd288697c6425c9beba919302241e3278871dc6519515e72b04e987abcf", size = 4401664, upload-time = "2026-05-18T19:20:50.489Z" },
+ { url = "https://files.pythonhosted.org/packages/db/a4/441aee36c6f6b249823d20fd91f9be9ab89d7c5a8ae542a4a4ca6d342d56/lxml-6.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:ed21202aec73cda4d55d1ce57b389aadb90ffb044e6cd1080b8347efe1b1ec84", size = 3508989, upload-time = "2026-05-18T19:18:38.158Z" },
+]
+
+[[package]]
+name = "mako"
+version = "1.3.12"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markupsafe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/00/62/791b31e69ae182791ec67f04850f2f062716bbd205483d63a215f3e062d3/mako-1.3.12.tar.gz", hash = "sha256:9f778e93289bd410bb35daadeb4fc66d95a746f0b75777b942088b7fd7af550a", size = 400219, upload-time = "2026-04-28T19:01:08.512Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bc/b1/a0ec7a5a9db730a08daef1fdfb8090435b82465abbf758a596f0ea88727e/mako-1.3.12-py3-none-any.whl", hash = "sha256:8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9", size = 78521, upload-time = "2026-04-28T19:01:10.393Z" },
+]
+
+[[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 = "markdown-it-py"
+version = "4.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mdurl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" },
+ { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" },
+ { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" },
+ { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" },
+ { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" },
+ { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" },
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
+]
+
+[[package]]
+name = "mesido"
+version = "0.1.20.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "casadi-gil-comp" },
+ { name = "coolprop" },
+ { name = "influxdb" },
+ { name = "pandas" },
+ { name = "pyecore" },
+ { name = "pyesdl", extra = ["profiles"] },
+ { name = "pymoca" },
+ { name = "rtc-tools-gil-comp" },
+ { name = "setuptools" },
+ { name = "strenum" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1b/ca/071cb7540708108f3f72f5f692d4df80f91d327314861873383b869761ae/mesido-0.1.20.3.tar.gz", hash = "sha256:82302e5b4a7c09cf2353facbd48a8000ee94420f5ad8461d15fe117150f83b93", size = 441829, upload-time = "2026-07-15T14:33:04.584Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/91/14/f54fe73742a29c7ac97473c964db40d2ca1fe3a5d44229dd0082a199d582/mesido-0.1.20.3-py3-none-any.whl", hash = "sha256:a2f87495cd9f32964ebf3ed3b8651261568fe33d834bc66c3b4531e39e60007d", size = 384963, upload-time = "2026-07-15T14:33:03.281Z" },
+]
+
+[[package]]
+name = "msgpack"
+version = "1.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" },
+ { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" },
+ { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" },
+ { url = "https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", size = 426183, upload-time = "2025-10-08T09:14:53.477Z" },
+ { url = "https://files.pythonhosted.org/packages/25/98/6a19f030b3d2ea906696cedd1eb251708e50a5891d0978b012cb6107234c/msgpack-1.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", size = 411454, upload-time = "2025-10-08T09:14:54.648Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/cd/9098fcb6adb32187a70b7ecaabf6339da50553351558f37600e53a4a2a23/msgpack-1.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", size = 422341, upload-time = "2025-10-08T09:14:56.328Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/ae/270cecbcf36c1dc85ec086b33a51a4d7d08fc4f404bdbc15b582255d05ff/msgpack-1.1.2-cp311-cp311-win32.whl", hash = "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", size = 64747, upload-time = "2025-10-08T09:14:57.882Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/79/309d0e637f6f37e83c711f547308b91af02b72d2326ddd860b966080ef29/msgpack-1.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", size = 71633, upload-time = "2025-10-08T09:14:59.177Z" },
+ { url = "https://files.pythonhosted.org/packages/73/4d/7c4e2b3d9b1106cd0aa6cb56cc57c6267f59fa8bfab7d91df5adc802c847/msgpack-1.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", size = 64755, upload-time = "2025-10-08T09:15:00.48Z" },
+]
+
+[[package]]
+name = "multidict"
+version = "6.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" },
+ { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" },
+ { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" },
+ { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" },
+ { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" },
+]
+
+[[package]]
+name = "numpy"
+version = "1.25.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a0/41/8f53eff8e969dd8576ddfb45e7ed315407d27c7518ae49418be8ed532b07/numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760", size = 10805282, upload-time = "2023-07-31T15:17:43.198Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c9/57/3cb8131a0e6d559501e088d3e685f4122e9ff9104c4b63e4dfd3a577b491/numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418", size = 20801693, upload-time = "2023-07-31T14:53:53.29Z" },
+ { url = "https://files.pythonhosted.org/packages/86/a1/b8ef999c32f26a97b5f714887e21f96c12ae99a38583a0a96e65283ac0a1/numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f", size = 14004130, upload-time = "2023-07-31T14:54:16.413Z" },
+ { url = "https://files.pythonhosted.org/packages/50/67/3e966d99a07d60a21a21d7ec016e9e4c2642a86fea251ec68677daf71d4d/numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2", size = 14158219, upload-time = "2023-07-31T14:54:39.032Z" },
+ { url = "https://files.pythonhosted.org/packages/32/6a/65dbc57a89078af9ff8bfcd4c0761a50172d90192eaeb1b6f56e5fbf1c3d/numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf", size = 18209344, upload-time = "2023-07-31T14:55:08.584Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/fe/e900cb2ebafae04b7570081cefc65b6fdd9e202b9b353572506cea5cafdf/numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364", size = 18072378, upload-time = "2023-07-31T14:55:39.551Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/e4/990c6cb09f2cd1a3f53bcc4e489dad903faa01b058b625d84bb62d2e9391/numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d", size = 12654351, upload-time = "2023-07-31T14:56:10.623Z" },
+ { url = "https://files.pythonhosted.org/packages/72/b2/02770e60c4e2f7e158d923ab0dea4e9f146a2dbf267fec6d8dc61d475689/numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4", size = 15546748, upload-time = "2023-07-31T14:57:13.015Z" },
+]
+
+[[package]]
+name = "oauthlib"
+version = "3.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" },
+]
+
+[[package]]
+name = "omotes-optimizer-worker"
+version = "0.0.1"
+source = { editable = "." }
+dependencies = [
+ { name = "mesido" },
+ { name = "omotes-sdk-python" },
+ { name = "pyesdl" },
+ { name = "python-dotenv" },
+]
+
+[package.dev-dependencies]
+dev = [
+ { name = "build" },
+ { name = "pip-tools" },
+ { name = "pytest" },
+ { name = "pytest-cov" },
+ { name = "ruff" },
+ { name = "setuptools" },
+ { name = "ty" },
+ { name = "wheel" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "mesido", specifier = "~=0.1.20.3" },
+ { name = "omotes-sdk-python", specifier = "==5.0.1" },
+ { name = "pyesdl", specifier = "~=26.7" },
+ { name = "python-dotenv", specifier = "~=1.0.0" },
+]
+
+[package.metadata.requires-dev]
+dev = [
+ { name = "build", specifier = "~=1.2.2" },
+ { name = "pip-tools", specifier = "~=7.4.0" },
+ { name = "pytest", specifier = "~=8.3.4" },
+ { name = "pytest-cov", specifier = "~=6.0.0" },
+ { name = "ruff", specifier = "~=0.15.22" },
+ { name = "setuptools", specifier = "~=75.6.0" },
+ { name = "ty", specifier = "~=0.0.61" },
+ { name = "wheel", specifier = "~=0.45.1" },
+]
+
+[[package]]
+name = "omotes-sdk-python"
+version = "5.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "prefect" },
+ { name = "s3fs" },
+ { name = "streamcapture" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fa/48/0e2dc6faf0dbe4115f3aa3205fb4252ce30e111cff2403c2daea212301c4/omotes_sdk_python-5.0.1.tar.gz", hash = "sha256:c4dd22943d1cdde29a96f0b6f416e699c56a51abd0f13ec482ff238f36d32535", size = 24840, upload-time = "2026-07-28T15:57:58.87Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/19/ea/bdb96e4371ae46171e05615c57c102faa25a946805164d2c560c0715d922/omotes_sdk_python-5.0.1-py3-none-any.whl", hash = "sha256:990affd855439fe01f50a64e1b782f410b718f5d05f2cd233018cae650ecfc4d", size = 21613, upload-time = "2026-07-28T15:57:57.696Z" },
+]
+
+[[package]]
+name = "openpyxl"
+version = "3.1.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "et-xmlfile" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/e8/af028681d493814ca9c2ff8106fc62a4a32e4e0ae14602c2a98fc7b741c8/openpyxl-3.1.2.tar.gz", hash = "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184", size = 185977, upload-time = "2023-03-11T16:58:38.78Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6a/94/a59521de836ef0da54aaf50da6c4da8fb4072fb3053fa71f052fd9399e7a/openpyxl-3.1.2-py2.py3-none-any.whl", hash = "sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5", size = 249985, upload-time = "2023-03-11T16:58:36.257Z" },
+]
+
+[[package]]
+name = "opentelemetry-api"
+version = "1.44.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ee/8b/aa9e2d8b8dfa7c946f7dec5d1f8f6ba8eca062f43509a06bdb5ce93d26c0/opentelemetry_api-1.44.0.tar.gz", hash = "sha256:67647e5e9566edcf421166fdf022b3537f818635daa852b289e34604dc6fb33a", size = 72406, upload-time = "2026-07-16T15:25:32.678Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl", hash = "sha256:94b98c893a91b88657eaac1e3ba89618cdb85be6918196705354f34728b2cdef", size = 60018, upload-time = "2026-07-16T15:25:11.657Z" },
+]
+
+[[package]]
+name = "ordered-set"
+version = "4.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4c/ca/bfac8bc689799bcca4157e0e0ced07e70ce125193fc2e166d2e685b7e2fe/ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8", size = 12826, upload-time = "2022-01-26T14:38:56.6Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/33/55/af02708f230eb77084a299d7b08175cff006dea4f2721074b92cdb0296c0/ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562", size = 7634, upload-time = "2022-01-26T14:38:48.677Z" },
+]
+
+[[package]]
+name = "orjson"
+version = "3.11.9"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7e/0c/964746fcafbd16f8ff53219ad9f6b412b34f345c75f384ad434ceaadb538/orjson-3.11.9.tar.gz", hash = "sha256:4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f", size = 5599163, upload-time = "2026-05-06T15:11:08.309Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/51/3fb9e65ae76ee97bd611869a503fa3fc0a6e81dd8b737cf3003f682df7ff/orjson-3.11.9-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f01c4818b3fc9b0da8e096722a84318071eaa118df35f6ed2344da0e73a5444f", size = 228522, upload-time = "2026-05-06T15:09:35.362Z" },
+ { url = "https://files.pythonhosted.org/packages/16/fa/9d54b07cb3f3b0bfd57841478e42d7a0ece4a9f49f9907eecf5a45461687/orjson-3.11.9-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:3ebca4179031ee716ed076ffadc29428e900512f6fccee8614c9983157fcf19c", size = 128463, upload-time = "2026-05-06T15:09:37.063Z" },
+ { url = "https://files.pythonhosted.org/packages/88/b1/6ceafc2eefd0a553e3be77ce6c49d107e772485d9568629376171c50e634/orjson-3.11.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48ee05097750de0ff69ed5b7bbcf0732182fd57a24043dcc2a1da780a5ead3a5", size = 132306, upload-time = "2026-05-06T15:09:38.299Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/76/f11311285324a40aab1e3031385c50b635a7cd0734fdaf60c7e89a696f60/orjson-3.11.9-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6082706765a95a6680d812e1daf1c0cfe8adec7831b3ff3b625693f3b461b1c", size = 127988, upload-time = "2026-05-06T15:09:39.597Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/85/0ef63bcf1337f44031ce9b91b1919563f62a37527b3ea4368bb15a22e5d7/orjson-3.11.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:277fefe9d76ee17eb14debf399e3533d4d63b5f677a4d3719eb763536af1f4bd", size = 135188, upload-time = "2026-05-06T15:09:40.957Z" },
+ { url = "https://files.pythonhosted.org/packages/05/94/b0d27090ea8a2095db3c2bd1b1c96f96f19bbb494d7fef33130e846e613d/orjson-3.11.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03db380e3780fa0015ed776a90f20e8e20bb11dde13b216ce19e5718e3dfba62", size = 145937, upload-time = "2026-05-06T15:09:42.249Z" },
+ { url = "https://files.pythonhosted.org/packages/09/eb/75d50c29c05b8054013e221e598820a365c8e64065312e75e202ed880709/orjson-3.11.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33d7d766701847dc6729846362dc27895d2f2d2251264f9d10e7cb9878194877", size = 132758, upload-time = "2026-05-06T15:09:43.945Z" },
+ { url = "https://files.pythonhosted.org/packages/49/bd/360686f39348aa88827cb6fbf7dc606fd41c831a35235e1abf1db8e3a9e6/orjson-3.11.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147302878da387104b66bb4a8b0227d1d487e976ce41a8501916161072ed87b1", size = 133971, upload-time = "2026-05-06T15:09:45.239Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/30/3178eb16f3221aeef068b6f1f1ebe05f656ea5c6dffe9f6c917329fe17a3/orjson-3.11.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3513550321f8c8c811a7c3297b8a630e82dc08e4c10216d07703c997776236cd", size = 141685, upload-time = "2026-05-06T15:09:46.858Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/f1/ff2f19ed0225f9680fafa42febca3570dd59444ebf190980738d376214c2/orjson-3.11.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c5d001196b89fa9cf0a4ab79766cd835b991a166e4b621ba95089edc50c429ff", size = 415167, upload-time = "2026-05-06T15:09:48.312Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/61/863bddf0da6e9e586765414debd54b4e58db05f560902b6d00658cb88636/orjson-3.11.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:16969c9d369c98eb084889c6e4d2d39b77c7eb38ceccf8da2a9fff62ae908980", size = 147913, upload-time = "2026-05-06T15:09:49.733Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/8a/4081492586d75b073d60c5271a8d0f05a0955cabf1e34c8473f6fcd84235/orjson-3.11.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:63e0efbc991250c0b3143488fa57d95affcabbfc63c99c48d625dd37779aafe2", size = 136959, upload-time = "2026-05-06T15:09:51.311Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/bd/70b6ab193594d7abb875320c0a7c8335e846f28968c432c31042409c3c8d/orjson-3.11.9-cp311-cp311-win32.whl", hash = "sha256:14ed654580c1ed2bc217352ec82f91b047aef82951aa71c7f64e0dcb03c0e180", size = 131533, upload-time = "2026-05-06T15:09:52.637Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/17/1a1a228183d62d1b77e2c30d210f47dd4768b310ebe1607c63e3c0e3a71e/orjson-3.11.9-cp311-cp311-win_amd64.whl", hash = "sha256:57ea77fb70a448ce87d18fca050193202a3da5e54598f6501ca5476fb66cfe02", size = 127106, upload-time = "2026-05-06T15:09:54.204Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/95/285de5fa296d09681ee9c546cd4a8aeb773b701cf343dc125994f4d52953/orjson-3.11.9-cp311-cp311-win_arm64.whl", hash = "sha256:19b72ed11572a2ee51a67a903afbe5af504f84ed6f529c0fe44b0ab3fb5cc697", size = 126848, upload-time = "2026-05-06T15:09:55.551Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "25.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
+]
+
+[[package]]
+name = "pandas"
+version = "1.5.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+ { name = "python-dateutil" },
+ { name = "pytz" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/74/ee/146cab1ff6d575b54ace8a6a5994048380dc94879b0125b25e62edcb9e52/pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1", size = 5203060, upload-time = "2023-01-19T08:31:39.615Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e2/24/a26af514113fd5eca2d8fe41ba4f22f70dfe6afefde4a6beb6a203570935/pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc", size = 18387750, upload-time = "2023-01-19T08:29:43.119Z" },
+ { url = "https://files.pythonhosted.org/packages/53/c9/d2f910dace7ef849b626980d0fd033b9cded36568949c8d560c9630ad2e0/pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d", size = 11868668, upload-time = "2023-01-19T08:29:48.733Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/be/1843b9aff84b98899663e7cad9f45513dfdd11d69cb5bd85c648aaf6a8d4/pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc", size = 10814036, upload-time = "2023-01-19T08:29:54.886Z" },
+ { url = "https://files.pythonhosted.org/packages/63/8d/c2bd356b9d4baf1c5cf8d7e251fb4540e87083072c905430da48c2bb31eb/pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae", size = 11374218, upload-time = "2023-01-19T08:30:00.5Z" },
+ { url = "https://files.pythonhosted.org/packages/56/73/3351beeb807dca69fcc3c4966bcccc51552bd01549a9b13c04ab00a43f21/pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6", size = 12017319, upload-time = "2023-01-19T08:30:06.097Z" },
+ { url = "https://files.pythonhosted.org/packages/da/6d/1235da14daddaa6e47f74ba0c255358f0ce7a6ee05da8bf8eb49161aa6b5/pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003", size = 10303385, upload-time = "2023-01-19T08:30:11.148Z" },
+]
+
+[[package]]
+name = "pathspec"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
+]
+
+[[package]]
+name = "pendulum"
+version = "3.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "python-dateutil" },
+ { name = "tzdata" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cb/72/9a51afa0a822b09e286c4cb827ed7b00bc818dac7bd11a5f161e493a217d/pendulum-3.2.0.tar.gz", hash = "sha256:e80feda2d10fa3ff8b1526715f7d33dcb7e08494b3088f2c8a3ac92d4a4331ce", size = 86912, upload-time = "2026-01-30T11:22:24.093Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c4/27/a4be6ec12161b503dd036f8d7cc57f8626170ae31bb298038be9af0001ce/pendulum-3.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5d775cc608c909ad415c8e789c84a9f120bb6a794c4215b2d8d910893cf0ec6a", size = 337923, upload-time = "2026-01-30T11:20:51.61Z" },
+ { url = "https://files.pythonhosted.org/packages/59/e1/2a214e18355ec2a6ce3f683a97eecdb6050866ff3a6cf165d411450aeb1b/pendulum-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8de794a7f665aebc8c1ba4dd4b05ab8fe1a36ce9c0498366adf1d1edd79b2686", size = 327379, upload-time = "2026-01-30T11:20:53.085Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/01/7392e58ebc1d9e70b987dc8bb0c89710b47ac8125067efe7aa4c420b616f/pendulum-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bac7df7696e1c942e17c0556b3a7bcdd1d7aa5b24faee7620cb071e754a0622", size = 340115, upload-time = "2026-01-30T11:20:54.635Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/33/80de84c5ca1a3e4f7f3b75090c9b61b6dbb6d095e302ee592cebbaf0bbfb/pendulum-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db0f6a8a04475d9cba26ce701e7d66d266fd97227f2f5f499270eba04be1c7e9", size = 373969, upload-time = "2026-01-30T11:20:56.209Z" },
+ { url = "https://files.pythonhosted.org/packages/75/e4/f7b4c1818927ab394a2a0a9b7011f360a0a75839a22678833c5bc0a84183/pendulum-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c352c63c1ff05f2198409b28498d7158547a8be23e1fbd4aa2cf5402fb239b55", size = 379058, upload-time = "2026-01-30T11:20:57.618Z" },
+ { url = "https://files.pythonhosted.org/packages/36/94/9947cf710620afcc68751683f2f8de88d902505e7c13c0349d7e9d362f97/pendulum-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de8c1ad1d1aa7d4ceae341528bab35a0f8c88a5aa63f2f5d84e16b517d1b32c2", size = 348403, upload-time = "2026-01-30T11:20:59.56Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/12/0e6ba0bb00fa57907af2a3fca8643bded5dba1e87072d50673776a0d6ed2/pendulum-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1ba955511c12fec2252038b0c866c25c0c30b720bf74d3023710f121e42b1498", size = 517457, upload-time = "2026-01-30T11:21:01.602Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/fe/dae5fbfe67bd41d943def0ad8f1e7f6988aa8e527255e433cd7c494f9ad5/pendulum-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4115bf364a2ec6d5ddc476751ceaa4164a04f2c15589f0d29aa210ddb784b15d", size = 561103, upload-time = "2026-01-30T11:21:03.924Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/a0/8f646160b98abfc19152505af19bd643a4279ec2bdbe0959f16b7025fc6b/pendulum-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:4151a903356413fdd9549de0997b708fb95a214ed97803ffb479ffd834088378", size = 260595, upload-time = "2026-01-30T11:21:05.495Z" },
+ { url = "https://files.pythonhosted.org/packages/79/01/feead7af9ded7a13f2d798fb6573e70f469113eafcd8cc8f59671584ca3e/pendulum-3.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:acfdee9ddc56053cb7c8c075afbfde0857322d09e56a56195b9cd127fae87e4c", size = 255382, upload-time = "2026-01-30T11:21:06.847Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/0d/d5ac8468a1b40f09a62d6e91654088de432367907579dd161c0fb1bdf222/pendulum-3.2.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9585594d32faa71efa5a78f576f1ee4f79e9c5340d7c6f0cd6c5dfe725effaaa", size = 338760, upload-time = "2026-01-30T11:22:12.225Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/e5/7fa8c8be6caac8e0be78fbe7668df571f44820ed779cb3736fab645fcba8/pendulum-3.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26401e2de77c437e8f3b6160c08c6c5d45518d906f8f9b48fd7cb5aa0f4e2aff", size = 328333, upload-time = "2026-01-30T11:22:13.811Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/78/73a1031b7d1bf7986e8e655cea3f018164b3470aecfea25a4074e77dda73/pendulum-3.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:637e65af042f383a2764a886aa28ccc6f853bf7a142df18e41c720542934c13b", size = 340841, upload-time = "2026-01-30T11:22:15.278Z" },
+ { url = "https://files.pythonhosted.org/packages/49/40/4e36e9074e92b0164c088b9ada3c02bfea386d83e24fa98b30fe9b6e61a8/pendulum-3.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6e46c28f4d067233c4a4c42748f4ffa641d9289c09e0e81488beb6d4b3fab51", size = 348959, upload-time = "2026-01-30T11:22:16.718Z" },
+ { url = "https://files.pythonhosted.org/packages/24/99/8bf7fcb91b526e1efe17d047faa845709b88800fff915ff848ff26054293/pendulum-3.2.0-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:71d46bcc86269f97bfd8c5f1475d55e717696a0a010b1871023605ca94624031", size = 518102, upload-time = "2026-01-30T11:22:18.2Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/b0/a36c468d2d0dec62ddea7c5e4177e93abb12f48ac90f09f24d0581c5189f/pendulum-3.2.0-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5cd956d4176afc7bfe8a91bf3f771b46ff8d326f6c5bf778eb5010eb742ebba6", size = 561884, upload-time = "2026-01-30T11:22:19.671Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/4d/dad105261898907bf806cabca53d3878529a9fa2c0d5d7f95f2035246fc2/pendulum-3.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:39ef129d7b90aab49708645867abdd207b714ba7bff12dae549975b0aca09716", size = 261236, upload-time = "2026-01-30T11:22:21.059Z" },
+ { url = "https://files.pythonhosted.org/packages/02/fb/d65db067a67df7252f18b0cb7420dda84078b9e8bfb375215469c14a50be/pendulum-3.2.0-py3-none-any.whl", hash = "sha256:f3a9c18a89b4d9ef39c5fa6a78722aaff8d5be2597c129a3b16b9f40a561acf3", size = 114111, upload-time = "2026-01-30T11:22:22.361Z" },
+]
+
+[[package]]
+name = "pip"
+version = "26.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/01/91/47e7d486260f618783899587af63ccf7980fb60245c3e63dd4571c6b57ad/pip-26.1.2.tar.gz", hash = "sha256:f49cd134c61cf2fd75e0ce2676db03e4054504a5a4986d00f8299ae632dc4605", size = 1840799, upload-time = "2026-05-31T17:33:58.56Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl", hash = "sha256:382ff9f685ee3bc25864f820aa50505825f10f5458ffff07e30a6d96e5715cab", size = 1813144, upload-time = "2026-05-31T17:33:56.772Z" },
+]
+
+[[package]]
+name = "pip-tools"
+version = "7.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "build" },
+ { name = "click" },
+ { name = "pip" },
+ { name = "pyproject-hooks" },
+ { name = "setuptools" },
+ { name = "wheel" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1a/87/1ef453f10fb0772f43549686f924460cc0a2404b828b348f72c52cb2f5bf/pip-tools-7.4.1.tar.gz", hash = "sha256:864826f5073864450e24dbeeb85ce3920cdfb09848a3d69ebf537b521f14bcc9", size = 145417, upload-time = "2024-03-06T12:13:23.533Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0d/dc/38f4ce065e92c66f058ea7a368a9c5de4e702272b479c0992059f7693941/pip_tools-7.4.1-py3-none-any.whl", hash = "sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9", size = 61235, upload-time = "2024-03-06T12:13:40.124Z" },
+]
+
+[[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 = "prefect"
+version = "3.7.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiosqlite" },
+ { name = "alembic" },
+ { name = "amplitude-analytics" },
+ { name = "anyio" },
+ { name = "apprise" },
+ { name = "asgi-lifespan" },
+ { name = "asyncpg" },
+ { name = "cachetools" },
+ { name = "click" },
+ { name = "cloudpickle" },
+ { name = "coolname" },
+ { name = "cryptography" },
+ { name = "cyclopts" },
+ { name = "dateparser" },
+ { name = "docker" },
+ { name = "exceptiongroup" },
+ { name = "fastapi" },
+ { name = "fsspec" },
+ { name = "graphviz" },
+ { name = "griffe" },
+ { name = "httpcore" },
+ { name = "httpx", extra = ["http2"] },
+ { name = "humanize" },
+ { name = "jinja2" },
+ { name = "jinja2-humanize-extension" },
+ { name = "jsonpatch" },
+ { name = "jsonschema" },
+ { name = "opentelemetry-api" },
+ { name = "orjson" },
+ { name = "packaging" },
+ { name = "pathspec" },
+ { name = "pendulum" },
+ { name = "pluggy" },
+ { name = "prometheus-client" },
+ { name = "pydantic" },
+ { name = "pydantic-core" },
+ { name = "pydantic-extra-types" },
+ { name = "pydantic-settings" },
+ { name = "pydocket" },
+ { name = "python-dateutil" },
+ { name = "python-slugify" },
+ { name = "pytz" },
+ { name = "pyyaml" },
+ { name = "readchar" },
+ { name = "rfc3339-validator" },
+ { name = "rich" },
+ { name = "ruamel-yaml" },
+ { name = "ruamel-yaml-clib", marker = "platform_python_implementation == 'CPython'" },
+ { name = "semver" },
+ { name = "sniffio" },
+ { name = "sqlalchemy", extra = ["asyncio"] },
+ { name = "starlette" },
+ { name = "toml" },
+ { name = "typing-extensions" },
+ { name = "uvicorn" },
+ { name = "websockets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e7/51/4b17109cac94607e3eecc3a0ff0d21aa40e812772a3269b78d28acf2236c/prefect-3.7.3.tar.gz", hash = "sha256:fd4f03474773af9af7f135f30cd9916bb371f88e499caec799ebd1921795d028", size = 14083737, upload-time = "2026-06-01T16:29:55.017Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/92/74/3a76454e24537429b010634896b8a51d3409ad7158b84114415085184de2/prefect-3.7.3-py3-none-any.whl", hash = "sha256:4266e950eb909b3c377d54e7b477e7ca614a69cd1190fbba6b24456dc06ec9d9", size = 14963599, upload-time = "2026-06-01T16:29:51.549Z" },
+]
+
+[[package]]
+name = "prometheus-client"
+version = "0.26.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/52/73/f1334c29c2af4cd9dba6c7817e61b611bd0215e2eb5565c6064a4de18802/prometheus_client-0.26.0.tar.gz", hash = "sha256:04a91bcf94e2cf74a44a1a874d651a2e853ed354b6e822f3b7487751465d5c2b", size = 92910, upload-time = "2026-07-24T19:36:41.893Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/eb/a3/b69efbf4143b5b9859b977770bbbabcc2796b702fa69dc40271e45cd5a56/prometheus_client-0.26.0-py3-none-any.whl", hash = "sha256:fa93d06737aa02bacd05794768508bb97d2fbee28cb3bca04eaae92f0ca953d6", size = 64494, upload-time = "2026-07-24T19:36:40.854Z" },
+]
+
+[[package]]
+name = "propcache"
+version = "0.5.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/f1/8a8cc1c2c7e7934ab77e0163414f736fadbc0f5e8dd9673b952355ac175b/propcache-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74b70780220e2dd89175ca24b81b68b67c83db499ae611e7f2313cb329801c78", size = 90744, upload-time = "2026-05-08T20:59:45.799Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/f4/651b1225e976bd1a2ba5cfba0c29d096581c2636b437e3a9a7ab6276270a/propcache-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4840ab0ae0216d952f4b53dc6d0b992bfc2bedbfe360bdd9b548bc184c08959", size = 52033, upload-time = "2026-05-08T20:59:47.408Z" },
+ { url = "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6844ba6364fb12f403928a82cfd295ab103a2b315c77c747b2dbe4a41894ea7", size = 52754, upload-time = "2026-05-08T20:59:49.202Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/fe/b3551b41bbc2f5b5bb088fc6920567cd43101253e68fbaa261339eb96fe1/propcache-0.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2293949b855ce597f2826452d17c2d545fb5622379c4ea6fdf525e9b8e8a2511", size = 57573, upload-time = "2026-05-08T20:59:50.778Z" },
+ { url = "https://files.pythonhosted.org/packages/83/27/ab851ebd1b7172e3e161f5f8d39e315d54a91bea246f01f4d872d3376aef/propcache-0.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0fd59b5af35f74da48d905dcbad55449ba13be91823cb05a9bd590bbf5b61660", size = 60645, upload-time = "2026-05-08T20:59:52.227Z" },
+ { url = "https://files.pythonhosted.org/packages/95/7d/466b3d18022e9897cbda9c735c493c5bd747d7a4c6f5ea1480b4cec434b6/propcache-0.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29f9309a2e42b0d273be006fdb4be2d6c39a47f6f57d8fb1cf9f81481df81b66", size = 61563, upload-time = "2026-05-08T20:59:53.866Z" },
+ { url = "https://files.pythonhosted.org/packages/27/1b/16ab7f2cf2041da2f60d156ba64c2484eadf9168075b4ff43c3ef60045af/propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5aaa2b923c1944ac8febd6609cb373540a5563e7cbcb0fd770f75dace2eb817b", size = 58888, upload-time = "2026-05-08T20:59:55.457Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/67/bb777ffd907633563bf35fd859c4ce97b0512c32f4633cf5d1eb7c33512b/propcache-0.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66ea454f095ddf5b6b14f56c064c0941c4788be11e18d2464cf643bf7203ff67", size = 59253, upload-time = "2026-05-08T20:59:57.075Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/42/64f8d90b73fd9cdc1499b48057ff6d9cd2a98a25734c9bb62ecf07e87061/propcache-0.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:95f1e3f4760d404b13c9976c0229b2b49a3c8e2c62a9ce92efdd2b11ada75e3f", size = 57558, upload-time = "2026-05-08T20:59:58.602Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/02/dba5bc03c9041f2092ea55a449caf5dfe68352c6654511b29ba0654ddb69/propcache-0.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:85341b12b9d55bad0bded24cac341bb34289469e03a11f3f583ea1cc1db0326c", size = 55007, upload-time = "2026-05-08T20:59:59.837Z" },
+ { url = "https://files.pythonhosted.org/packages/14/c0/43f649c7aa2a77a3b100d84e9dea3a483120ecb608bfe36ce49eaff517fe/propcache-0.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:26a4dca084132874e639895c3135dfad5eb20bae209f62d1aeb31b03e601c3c0", size = 60355, upload-time = "2026-05-08T21:00:01.144Z" },
+ { url = "https://files.pythonhosted.org/packages/83/c0/435dafd27f1cb4a495381dae60e25883ccfe4020bb72818e8184c1678092/propcache-0.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3b199b9b2b3d6a7edf3183ba8a9a137a22b97f7df525feb5ae1eccf026d2a9c6", size = 59057, upload-time = "2026-05-08T21:00:02.401Z" },
+ { url = "https://files.pythonhosted.org/packages/53/ae/6e292df9135d659944e96cb3389258e4a663e5b2b5f6c217ef0ddc8d2f73/propcache-0.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e59bc9e66329185b93dab73f210f1a37f81cb40f321501db8017c9aea15dba27", size = 61938, upload-time = "2026-05-08T21:00:03.638Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/42/314ebc50d8159055411fd6b0bda322ff510e4b1f7d2e4927940ad0f6af20/propcache-0.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:552ffadf6ad409844bc5919c42a0a83d88314cedddaea0e41e80a8b8fffe881f", size = 59731, upload-time = "2026-05-08T21:00:04.881Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/9b/2da6dee38871c3c8772fabc2758325a5c9077d6d18c597737dc04dd884cd/propcache-0.5.2-cp311-cp311-win32.whl", hash = "sha256:cd416c1de191973c52ff1a12a57446bfc7642797b282d7caf2162d7d1b8aa9a0", size = 38966, upload-time = "2026-05-08T21:00:06.511Z" },
+ { url = "https://files.pythonhosted.org/packages/42/4e/f17363fb58c0afe05b067361cb6d86ed2d29de6506779a27547c4d183075/propcache-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:44e488ef40dbb452700b2b1f8188934121f6648f52c295055662d2191959ff82", size = 42135, upload-time = "2026-05-08T21:00:08.088Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/eb/6af6685077d22e8b33358d3c548e3282706a0b3cd85044ffba4e5dd08e3b/propcache-0.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:54adaa85a22078d1e306304a40984dc5be99d599bf3dc0a24dc98f7daeab89ab", size = 38381, upload-time = "2026-05-08T21:00:09.692Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" },
+]
+
+[[package]]
+name = "psycopg"
+version = "3.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d3/b6/379d0a960f8f435ec78720462fd94c4863e7a31237cf81bf76d0af5883bf/psycopg-3.3.3.tar.gz", hash = "sha256:5e9a47458b3c1583326513b2556a2a9473a1001a56c9efe9e587245b43148dd9", size = 165624, upload-time = "2026-02-18T16:52:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c8/5b/181e2e3becb7672b502f0ed7f16ed7352aca7c109cfb94cf3878a9186db9/psycopg-3.3.3-py3-none-any.whl", hash = "sha256:f96525a72bcfade6584ab17e89de415ff360748c766f0106959144dcbb38c698", size = 212768, upload-time = "2026-02-18T16:46:27.365Z" },
+]
+
+[package.optional-dependencies]
+binary = [
+ { name = "psycopg-binary", marker = "implementation_name != 'pypy'" },
+]
+
+[[package]]
+name = "psycopg-binary"
+version = "3.3.3"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/c0/b389119dd754483d316805260f3e73cdcad97925839107cc7a296f6132b1/psycopg_binary-3.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a89bb9ee11177b2995d87186b1d9fa892d8ea725e85eab28c6525e4cc14ee048", size = 4609740, upload-time = "2026-02-18T16:47:51.093Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/e3/9976eef20f61840285174d360da4c820a311ab39d6b82fa09fbb545be825/psycopg_binary-3.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f7d0cf072c6fbac3795b08c98ef9ea013f11db609659dcfc6b1f6cc31f9e181", size = 4676837, upload-time = "2026-02-18T16:47:55.523Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/f2/d28ba2f7404fd7f68d41e8a11df86313bd646258244cb12a8dd83b868a97/psycopg_binary-3.3.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:90eecd93073922f085967f3ed3a98ba8c325cbbc8c1a204e300282abd2369e13", size = 5497070, upload-time = "2026-02-18T16:47:59.929Z" },
+ { url = "https://files.pythonhosted.org/packages/de/2f/6c5c54b815edeb30a281cfcea96dc93b3bb6be939aea022f00cab7aa1420/psycopg_binary-3.3.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dac7ee2f88b4d7bb12837989ca354c38d400eeb21bce3b73dac02622f0a3c8d6", size = 5172410, upload-time = "2026-02-18T16:48:05.665Z" },
+ { url = "https://files.pythonhosted.org/packages/51/75/8206c7008b57de03c1ada46bd3110cc3743f3fd9ed52031c4601401d766d/psycopg_binary-3.3.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b62cf8784eb6d35beaee1056d54caf94ec6ecf2b7552395e305518ab61eb8fd2", size = 6763408, upload-time = "2026-02-18T16:48:13.541Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/5a/ea1641a1e6c8c8b3454b0fcb43c3045133a8b703e6e824fae134088e63bd/psycopg_binary-3.3.3-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a39f34c9b18e8f6794cca17bfbcd64572ca2482318db644268049f8c738f35a6", size = 5006255, upload-time = "2026-02-18T16:48:22.176Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/fb/538df099bf55ae1637d52d7ccb6b9620b535a40f4c733897ac2b7bb9e14c/psycopg_binary-3.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:883d68d48ca9ff3cb3d10c5fdebea02c79b48eecacdddbf7cce6e7cdbdc216b8", size = 4532694, upload-time = "2026-02-18T16:48:27.338Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/d1/00780c0e187ea3c13dfc53bd7060654b2232cd30df562aac91a5f1c545ac/psycopg_binary-3.3.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:cab7bc3d288d37a80aa8c0820033250c95e40b1c2b5c57cf59827b19c2a8b69d", size = 4222833, upload-time = "2026-02-18T16:48:31.221Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/34/a07f1ff713c51d64dc9f19f2c32be80299a2055d5d109d5853662b922cb4/psycopg_binary-3.3.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:56c767007ca959ca32f796b42379fc7e1ae2ed085d29f20b05b3fc394f3715cc", size = 3952818, upload-time = "2026-02-18T16:48:35.869Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/67/d33f268a7759b4445f3c9b5a181039b01af8c8263c865c1be7a6444d4749/psycopg_binary-3.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:da2f331a01af232259a21573a01338530c6016dcfad74626c01330535bcd8628", size = 4258061, upload-time = "2026-02-18T16:48:41.365Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/3b/0d8d2c5e8e29ccc07d28c8af38445d9d9abcd238d590186cac82ee71fc84/psycopg_binary-3.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:19f93235ece6dbfc4036b5e4f6d8b13f0b8f2b3eeb8b0bd2936d406991bcdd40", size = 3558915, upload-time = "2026-02-18T16:48:46.679Z" },
+]
+
+[[package]]
+name = "py-key-value-aio"
+version = "0.4.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "beartype" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fb/e2/d689d922894a7ecde73b6daeaf9b13dab5aae06fe6aaaf7514722644d382/py_key_value_aio-0.4.5.tar.gz", hash = "sha256:c6563a2c6abe5da5e20f4f9e875c2a9b425a2244a54fadbf46cf140a9eea45d7", size = 107547, upload-time = "2026-05-27T16:37:08.107Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f6/95/b8ba862968712caa12a19666175334fa979e1f198b896a430adb3bacfe87/py_key_value_aio-0.4.5-py3-none-any.whl", hash = "sha256:ab862adbcb8c72547d1c57821f22cbbb71ab86509039c96f36e914e0336c8dd7", size = 170005, upload-time = "2026-05-27T16:37:06.629Z" },
+]
+
+[package.optional-dependencies]
+memory = [
+ { name = "cachetools" },
+]
+redis = [
+ { name = "redis" },
+]
+
+[[package]]
+name = "pycparser"
+version = "3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.13.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" },
+]
+
+[[package]]
+name = "pydantic-core"
+version = "2.46.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" },
+ { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" },
+ { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" },
+ { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" },
+ { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" },
+ { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" },
+ { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" },
+ { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" },
+ { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" },
+ { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" },
+ { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" },
+ { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" },
+]
+
+[[package]]
+name = "pydantic-extra-types"
+version = "2.11.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pydantic" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/66/71/dba38ee2651f84f7842206adbd2233d8bbdb59fb85e9fa14232486a8c471/pydantic_extra_types-2.11.1.tar.gz", hash = "sha256:46792d2307383859e923d8fcefa82108b1a141f8a9c0198982b3832ab5ef1049", size = 172002, upload-time = "2026-03-16T08:08:03.92Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/17/c1/3226e6d7f5a4f736f38ac11a6fbb262d701889802595cdb0f53a885ac2e0/pydantic_extra_types-2.11.1-py3-none-any.whl", hash = "sha256:1722ea2bddae5628ace25f2aa685b69978ef533123e5638cfbddb999e0100ec1", size = 79526, upload-time = "2026-03-16T08:08:02.533Z" },
+]
+
+[[package]]
+name = "pydantic-settings"
+version = "2.14.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pydantic" },
+ { name = "python-dotenv" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", size = 237700, upload-time = "2026-06-19T13:44:56.324Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl", hash = "sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440", size = 61715, upload-time = "2026-06-19T13:44:55.02Z" },
+]
+
+[[package]]
+name = "pydocket"
+version = "0.23.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "burner-redis" },
+ { name = "cloudpickle" },
+ { name = "cronsim" },
+ { name = "opentelemetry-api" },
+ { name = "prometheus-client" },
+ { name = "py-key-value-aio", extra = ["memory", "redis"] },
+ { name = "python-json-logger" },
+ { name = "redis" },
+ { name = "rich" },
+ { name = "typer" },
+ { name = "typing-extensions" },
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
+ { name = "uncalled-for" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f8/72/f5a0960249d32a213fb26297a55f842ce8bc90bb19adbf47fefebb9c99da/pydocket-0.23.1.tar.gz", hash = "sha256:136c1cc8b7aa7c4c08ea12431e966ae75eb093bb6ce6e0ac9db3391ba3d6034b", size = 425621, upload-time = "2026-07-20T18:49:24.592Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e6/67/b57ac7cfd2c2f30d58ff2c996591880d200078fc828cbbad8da69d634c0e/pydocket-0.23.1-py3-none-any.whl", hash = "sha256:3da279978fd0d07eb96d4119e1a213de61d6b4acd1792a28bc62e67f3e7e5929", size = 129230, upload-time = "2026-07-20T18:49:23.243Z" },
+]
+
+[[package]]
+name = "pyecore"
+version = "0.13.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "future-fstrings" },
+ { name = "lxml" },
+ { name = "ordered-set" },
+ { name = "restrictedpython" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cf/c5/2dab673015609457e37becd8f8d39fc2fbaee2c7fbf79de33b3fbf275717/pyecore-0.13.2.tar.gz", hash = "sha256:277b43855c3072f7ae5b5520bd4d529ee80d80c036859d25a150c8440b03de9c", size = 57559, upload-time = "2023-08-14T20:02:19.607Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e1/86/a9c3a70aef9e02d97fc210d83f295118c4e5e08aae69ad29e598ffa2b1af/pyecore-0.13.2-py3-none-any.whl", hash = "sha256:858d426fe0ffc86469a7d6b220365d0ef3c8aedd745aca0561ca20a7db05199d", size = 43326, upload-time = "2023-08-14T20:02:17.677Z" },
+]
+
+[[package]]
+name = "pyesdl"
+version = "26.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyecore" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b4/62/a9cb17f916eb2ee7c12b50f363a1457eccf879888ecd3ce2a0dc2904e561/pyesdl-26.7.tar.gz", hash = "sha256:7b685ab7ef57d07178178e54c20cc61962cc1c5ff901ea5efc0669f3d6c78eb8", size = 114922, upload-time = "2026-07-13T09:49:10.629Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fd/5b/1b913d6fbb904d5fdc45f5e67cdb285dc71c096070db0fe9dd9563c9a1de/pyesdl-26.7-py3-none-any.whl", hash = "sha256:30b512ee34a1ca4ffd2e58982208a75926eda67010a7e6b8a05b737cd9d0a127", size = 108848, upload-time = "2026-07-13T09:49:09.107Z" },
+]
+
+[package.optional-dependencies]
+profiles = [
+ { name = "influxdb" },
+ { name = "openpyxl" },
+ { name = "psycopg", extra = ["binary"] },
+ { name = "psycopg-binary" },
+]
+
+[[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 = "pymoca"
+version = "0.9.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "antlr4-python3-runtime" },
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9e/da/2abf5d074b6e69c190aac8fd6d2f732b2fcba0b73229776a18d4cace074f/pymoca-0.9.2.tar.gz", hash = "sha256:bb0f1368e67f7bb876c3cb3a468e4d3a87a28e7624adb7483b39a22274b730e0", size = 111886, upload-time = "2025-01-28T15:44:25.037Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/24/55/ecf41c62849b27684431f096872216427d6190dec2ee8d2c2550669d7395/pymoca-0.9.2-py3-none-any.whl", hash = "sha256:13b96bd877def818fba22f43b1b3916470b573e569c7e7f1bd98a8990b9b60d3", size = 113709, upload-time = "2025-01-28T15:44:22.626Z" },
+]
+
+[[package]]
+name = "pyproject-hooks"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228, upload-time = "2024-09-29T09:24:13.293Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "8.3.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "iniconfig" },
+ { name = "packaging" },
+ { name = "pluggy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" },
+]
+
+[[package]]
+name = "pytest-cov"
+version = "6.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "coverage", extra = ["toml"] },
+ { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945, upload-time = "2024-10-29T20:13:35.363Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949, upload-time = "2024-10-29T20:13:33.215Z" },
+]
+
+[[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 = "python-dotenv"
+version = "1.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115, upload-time = "2024-01-23T06:33:00.505Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863, upload-time = "2024-01-23T06:32:58.246Z" },
+]
+
+[[package]]
+name = "python-json-logger"
+version = "4.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f7/ff/3cc9165fd44106973cd7ac9facb674a65ed853494592541d339bdc9a30eb/python_json_logger-4.1.0.tar.gz", hash = "sha256:b396b9e3ed782b09ff9d6e4f1683d46c83ad0d35d2e407c09a9ebbf038f88195", size = 17573, upload-time = "2026-03-29T04:39:56.805Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/27/be/0631a861af4d1c875f096c07d34e9a63639560a717130e7a87cbc82b7e3f/python_json_logger-4.1.0-py3-none-any.whl", hash = "sha256:132994765cf75bf44554be9aa49b06ef2345d23661a96720262716438141b6b2", size = 15021, upload-time = "2026-03-29T04:39:55.266Z" },
+]
+
+[[package]]
+name = "python-slugify"
+version = "8.0.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "text-unidecode" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921, upload-time = "2024-02-08T18:32:45.488Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051, upload-time = "2024-02-08T18:32:43.911Z" },
+]
+
+[[package]]
+name = "pytz"
+version = "2025.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
+]
+
+[[package]]
+name = "pywin32"
+version = "312"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1f/f5/10a6e845a00fc5e7afd0a988b744f403d4d57162a28d160a093c4d9322f0/pywin32-312-cp311-cp311-win32.whl", hash = "sha256:17948aeadbdb091f0ced6ef0841620794e68327b94ee415571c1203594b7215c", size = 6362659, upload-time = "2026-06-04T07:49:21.349Z" },
+ { url = "https://files.pythonhosted.org/packages/35/c4/dcd2d62b5944b6d5db53413a5899016ccd57ffcb7278f3f81655d25d2027/pywin32-312-cp311-cp311-win_amd64.whl", hash = "sha256:d11417d84412f859b722fad0841b3614459ed0047f7542d8362e77884f6b6e8a", size = 6928825, upload-time = "2026-06-04T07:49:23.934Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/56/3cbb433fe4501cdba2eb9040f56a4e1a8243faa4186b25295564d1a7a79d/pywin32-312-cp311-cp311-win_arm64.whl", hash = "sha256:b2200a054ca6d6625c4842fc56a4976a4b47f96b73dbe5538c3f813a80359f47", size = 6721875, upload-time = "2026-06-04T07:49:26.416Z" },
+]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" },
+ { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" },
+ { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" },
+ { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" },
+ { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" },
+ { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" },
+]
+
+[[package]]
+name = "readchar"
+version = "4.2.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ed/49/a10341024c45bed95d13197ec9ef0f4e2fd10b5ca6e7f8d7684d18082398/readchar-4.2.2.tar.gz", hash = "sha256:e3b270fe16fc90c50ac79107700330a133dd4c63d22939f5b03b4f24564d5dd8", size = 9762, upload-time = "2026-04-06T19:45:54.226Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl", hash = "sha256:92daf7e42c52b0787e6c75d01ecfb9a94f4ceff3764958b570c1dddedd47b200", size = 9401, upload-time = "2026-04-06T19:45:52.993Z" },
+]
+
+[[package]]
+name = "redis"
+version = "8.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "async-timeout", marker = "python_full_version < '3.11.3'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cc/c3/928b290c2c0ca99ab96eea5b4ff8f30be8112b075301a7d3ba214a3c8c12/redis-8.0.1.tar.gz", hash = "sha256:afc5a7a2f5a084f5b1880dec548dd45be17db7e43c82a30d84f952aefb05cfb0", size = 5114170, upload-time = "2026-06-23T14:52:37.728Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl", hash = "sha256:47daa35a058c23468d6437f17a8c76882cb316b838ef763036af99b96cedd743", size = 502406, upload-time = "2026-06-23T14:52:36.137Z" },
+]
+
+[[package]]
+name = "referencing"
+version = "0.37.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "rpds-py" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" },
+]
+
+[[package]]
+name = "regex"
+version = "2026.7.19"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/20/98/04b13f1ddfb63158025291c02e03eb42fbb7acb51d091d541050eb4e35e8/regex-2026.7.19.tar.gz", hash = "sha256:7e77b324909c1617cbb4c668677e2c6ae13f44d7c1de0d4f15f2e3c10f3315b5", size = 416440, upload-time = "2026-07-19T00:19:48.923Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/e5/cef4de2bac939280b68d32adc659478845238a8274f2f79c465063f590ad/regex-2026.7.19-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ac777001cdfc28b72477d93c8564bb7583081ea8fb45cdca3d568e0a4f87183c", size = 494012, upload-time = "2026-07-19T00:16:39.927Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/87/e86f51eb117457bb7803132ffe5cb6e2841e2b5bea4cc85d397f3c6e257d/regex-2026.7.19-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:59787bd5f8c70aa339084e961d2996b53fbdeab4d5393bba5c1fe1fc32e02bae", size = 295281, upload-time = "2026-07-19T00:16:41.433Z" },
+ { url = "https://files.pythonhosted.org/packages/41/2e/2360c41d8080a3d9ec7e5c90fad6eab3b50192869d10e9a5609e48c8177b/regex-2026.7.19-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:90c633e7e8d6bf4e992b8b36ce69e018f834b641dd6de8cea6d78c06ffa119c5", size = 290615, upload-time = "2026-07-19T00:16:43.058Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/69/b65ba4344efbc771b28fe5dde84cbbb6c8f9551165952fe78def5b9dde6a/regex-2026.7.19-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:87ccab0db8d5f4fbb0272642113c1adb2ffc698c16d3a0944580222331fa7a20", size = 791804, upload-time = "2026-07-19T00:16:44.662Z" },
+ { url = "https://files.pythonhosted.org/packages/81/b6/a40dfa0dc6224b36f620c00296eacc830489cbf8c2837b6750dfe6170375/regex-2026.7.19-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e50d748a32da622f256e8d505867f5d3c43a837c6a9f0efb149655fadd1042a", size = 861723, upload-time = "2026-07-19T00:16:46.412Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/02/735991dee71abd83196a7962f7ed8bf5aa05720ff06e2d3ff896a85e2bbb/regex-2026.7.19-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bf1516fe58fc104f39b2d1dbe2d5e27d0cd45c4be2e42ba6ee0cc763701ec3c7", size = 905932, upload-time = "2026-07-19T00:16:47.956Z" },
+ { url = "https://files.pythonhosted.org/packages/45/6c/e7098d8b846ccdbf431d8c081b61e496526a27a28094ed09e0dce21b3f54/regex-2026.7.19-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09f3e5287f94f17b709dc9a9e70865855feee835c861613be144218ce4ca82cc", size = 801407, upload-time = "2026-07-19T00:16:49.43Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/18/34b69274e2649bcc7d9b089c2b2983fb2632d8ecf667e359593be9072e79/regex-2026.7.19-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6383cd2ed53a646c659ba1fe65727db76437fdaa069e697a0b44a51d5843d864", size = 774448, upload-time = "2026-07-19T00:16:51.352Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/e6/0a72247d025585fd3800b98e040b84d562a88af6303347100484849f4f01/regex-2026.7.19-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:09d3007fc76249a83cdd33de160d50e6cb77f54e09d8fa9e7148e10607ce24af", size = 783297, upload-time = "2026-07-19T00:16:53.071Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/aa/c4f65ae7dd02a36b323a70c4cff326e1f3442361aaebc9311100a130d54f/regex-2026.7.19-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f8c6e7a1cfa3dc9d0ee2de0e65e834537fa29992cc3976ffec914afc35c5dd5", size = 854736, upload-time = "2026-07-19T00:16:54.607Z" },
+ { url = "https://files.pythonhosted.org/packages/62/c3/668082bcc817b9e694189b84997aeba7385b7779faa6711788679c482e35/regex-2026.7.19-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:b2ea4a3e8357be8849e833beeae757ac3c7a6b3fc055c03c808a53c91ad30d82", size = 763298, upload-time = "2026-07-19T00:16:56.289Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/fb/2d07ad555e7af88aa5f867fdafa47a8d945ee237c20af3ebceb46a820835/regex-2026.7.19-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:80115dd39481fd3a4b4080220799dbcacb921a844de4b827264ececacbe17c78", size = 844430, upload-time = "2026-07-19T00:16:57.933Z" },
+ { url = "https://files.pythonhosted.org/packages/51/15/c82a471fe3dce56f03745635b43aa456c40dc0db089e07ef148b331507d1/regex-2026.7.19-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d6ce43a0269d68cee79a7d1ade7def53c20f8f2a047b92d7b5d5bcc73ae88327", size = 789683, upload-time = "2026-07-19T00:16:59.583Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/f4/7532a2c59d56f5398902c20de60f0c9a5d1cd364e42a051b48e1b210be7b/regex-2026.7.19-cp311-cp311-win32.whl", hash = "sha256:9be2a6647740dd3cca6acb24e87f03d7632cd280dbce9bbe40c26353a215a45d", size = 266778, upload-time = "2026-07-19T00:17:01.032Z" },
+ { url = "https://files.pythonhosted.org/packages/83/2b/cf1bc631db154eb95520d9d5dbc2371ff77a0f014bbf7d748fed8496aa63/regex-2026.7.19-cp311-cp311-win_amd64.whl", hash = "sha256:8d3469c91dd92ee41b7c95280edbd975ef1ba9195086686623a1c6e8935ce965", size = 277983, upload-time = "2026-07-19T00:17:02.571Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/bd/56ceaf170e875d5a6761bf2bfd0d040f1cacc896850d5e40cb29b11bbd06/regex-2026.7.19-cp311-cp311-win_arm64.whl", hash = "sha256:36aacfb15faaff3ced55afbf35ec72f50d4aee22082c4f7fe0573a33e2fca92e", size = 276961, upload-time = "2026-07-19T00:17:04.135Z" },
+]
+
+[[package]]
+name = "requests"
+version = "2.34.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "charset-normalizer" },
+ { name = "idna" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" },
+]
+
+[[package]]
+name = "requests-oauthlib"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "oauthlib" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" },
+]
+
+[[package]]
+name = "restrictedpython"
+version = "8.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/97/04/7314639eab9edd57b5c8f6e158a558f5a5a65453c37a51fb8f9ecc1d112e/restrictedpython-8.2.tar.gz", hash = "sha256:b835c2ff87d71b76f6d8b129096cc5a1e893bf01839ab802ba47a4129f1bdfe4", size = 449323, upload-time = "2026-05-29T06:27:57.285Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/35/59/b2778bfafcc37fdfd87c02702bbfc5753c58c28c7eb82999b7b49ec6e0e7/restrictedpython-8.2-py3-none-any.whl", hash = "sha256:6ff69e2fe06674bfe88943f17f2ce8353a9bc743ee37ea7bec38ff8b4851afd1", size = 27176, upload-time = "2026-05-29T06:27:55.651Z" },
+]
+
+[[package]]
+name = "rfc3339-validator"
+version = "0.1.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" },
+]
+
+[[package]]
+name = "rich"
+version = "15.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
+]
+
+[[package]]
+name = "rich-rst"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pygments" },
+ { name = "rich" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e2/d6/d0b9fafc73b65767200da027acab1db1bdb1048f4fea5ebf659df01c700e/rich_rst-2.1.0.tar.gz", hash = "sha256:f4d117b49697f338769759fa5cacf5197da4888b347b9fda2e50aef5cd8d93bd", size = 302732, upload-time = "2026-07-05T02:59:44.308Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl", hash = "sha256:7ecd1343ee12c879d0e7ae74c3eb6d263b023d2929c6d114212eb1fd91057255", size = 272987, upload-time = "2026-07-05T02:59:42.792Z" },
+]
+
+[[package]]
+name = "rpds-py"
+version = "2026.6.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/aa/2a/9618a122aeb2a169a28b03889a2995fe297588964333d4a7d67bdf46e147/rpds_py-2026.6.3.tar.gz", hash = "sha256:1cebd1337c242e4ec2293e541f712b2da849b29f48f0c293684b71c0632625d4", size = 64051, upload-time = "2026-06-30T07:17:53.009Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/1f/a2dca5ffdbf1d475ffc4e80e4d5d720ff3a00f691795910116960ee12511/rpds_py-2026.6.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:7b689145a1485c335569bd056464f3243a29af7ed3871c7be31ad624ba239bc7", size = 342174, upload-time = "2026-06-30T07:14:54.821Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/dc/323d08583c0832911768663d1944f0107fcd4088704858d84b5e06d105a0/rpds_py-2026.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:db08f45aecde626498fb3df07bcf6d2ec040af42e859a4f5040d79c200342911", size = 345513, upload-time = "2026-06-30T07:14:56.515Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/2a/e31989834d18d2f26ec1d2774c5b1eb3331df4ea8ada525175294c94b48a/rpds_py-2026.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acc992ab27b15f852c76755eb2ab7dce86585ddadba6fa5946e58556088845b4", size = 373783, upload-time = "2026-06-30T07:14:57.736Z" },
+ { url = "https://files.pythonhosted.org/packages/87/fe/e80107ee3639585c9941c17d6a42cd65325022f656c023191fce78c324c8/rpds_py-2026.6.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f88d653e7b3b779d71ae7454e20dcc9b6bae903f33c269db9f2be41bda3f261", size = 378316, upload-time = "2026-06-30T07:14:59.077Z" },
+ { url = "https://files.pythonhosted.org/packages/22/6f/81e3adf81acfb6fa694de2a6e4e7d8863121e3e0799e0a7725e6cf5679c4/rpds_py-2026.6.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e52655eaf81e32593abedaa4bfe33170c8cfedf3365ed9be6e11e07f148f0278", size = 499423, upload-time = "2026-06-30T07:15:00.488Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/9a/41263969df0ce3d9af2a96d5005a288200af1989aed3354bfceb5fc0b21f/rpds_py-2026.6.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dfcc8b909769d19db55c7cc9541eb64b9b774b1057ffffb4f1048070475bb9f9", size = 386077, upload-time = "2026-06-30T07:15:01.911Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/19/7e98f468bd50346faff5b10e5297374b443bfdddacc8e9fbc65984539597/rpds_py-2026.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c1255b302953c86a486b81d330d5ee1d5bd937691ce271b6be0ef0e299eaab7", size = 371315, upload-time = "2026-06-30T07:15:03.317Z" },
+ { url = "https://files.pythonhosted.org/packages/99/3c/2b973b4d371906a134b03decfea7f5d9835a2c6d263454392e15b64b5b18/rpds_py-2026.6.3-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:8d2294a31386bfa251d8c8a39472beee17db67d4f1a6eabea665d35c9a4461c3", size = 383502, upload-time = "2026-06-30T07:15:04.627Z" },
+ { url = "https://files.pythonhosted.org/packages/98/2a/12e2799500af0a307bca76b63361c51f9fe479223561489c29eea1f2ee41/rpds_py-2026.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8f23ead891a3b762f35ab3b04623da7056545b48aa60d59957e6789914545da", size = 402673, upload-time = "2026-06-30T07:15:05.856Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/e3/21e5872d165fe08be4f229e3d5ee9d90019c0bf0e5538de60dbd54009450/rpds_py-2026.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:421aba32367055614287a4292b6a17f1939c9452299f7a0209c117e990b646d4", size = 549964, upload-time = "2026-06-30T07:15:07.159Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/d0/5ee0fe36844297de8123bee27bc12078c1a7416ad9f1b8a8ca18d6b0c0ac/rpds_py-2026.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1e5822dfc2f0d4ab7e745eaa6d85945069329beeccef965af3f3bb26058fcab6", size = 615446, upload-time = "2026-06-30T07:15:08.531Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/80/1ea5873cb683f2fbe5f21b23ea1f6d179ead19f3c5b249b7eb5dca568ef2/rpds_py-2026.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:83e35b57523816c8613fd0776b40cd8bb9f596b37ddd2692eb4a6bb5ab2f8c93", size = 576975, upload-time = "2026-06-30T07:15:09.97Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/e1/90ef639217a5ddb15b7f4f61b1c33911fd044ad03c311bafdd2bcab85582/rpds_py-2026.6.3-cp311-cp311-win32.whl", hash = "sha256:de3eceba0b683bcbb1ab93da016d0270df1f9ae7be716b40214c5dafac6ea45a", size = 204453, upload-time = "2026-06-30T07:15:11.324Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/b7/b7a1695d7af36f521fb11e80d6d3adbd744f73b921859bd3c2a2c0dc706f/rpds_py-2026.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:2c54a076ca4d370980ab57bc0e31df57bbe8d41340436a90ef8b1219a3cbb127", size = 223219, upload-time = "2026-06-30T07:15:12.476Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/a2/145afacf796e4506062825941176ad9445c2dcf2b3b6a1f13d3030a15e19/rpds_py-2026.6.3-cp311-cp311-win_arm64.whl", hash = "sha256:168c733a7112e071bb7a66460e667edfcff06c017a3c523f7a8a8e08d0140804", size = 219137, upload-time = "2026-06-30T07:15:13.631Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/9c/f0d19ac587fd0e4ab6b72cda355e9c5a6166b01ef7e064e437aef8eb9fef/rpds_py-2026.6.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4cf2d36a2357e4d07bb5a4f98801265327b48256867816cfd2ceb001e9754a8f", size = 349791, upload-time = "2026-06-30T07:17:33.315Z" },
+ { url = "https://files.pythonhosted.org/packages/38/c7/1d49d204c9fd2ee6c537601dc4c1ba921e03363ca576bfab94a00254ac9a/rpds_py-2026.6.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:30c6dc199b24a5e3e81d50da0f00858c5bbdb2617a750395687f4339c5818171", size = 352842, upload-time = "2026-06-30T07:17:34.897Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/e5/c0b5dc93cd0d4c06ce1f438907649514e2ea077bcd911e3154a51e96c38e/rpds_py-2026.6.3-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9891e594296ab9dada6551c8e7b387b2721f27a67eecd528412e8906247a7b90", size = 382094, upload-time = "2026-06-30T07:17:36.514Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/54/ec0e907b4ca8d541112db352409bd15f871c9b243e0c92c9b5a46ae96f01/rpds_py-2026.6.3-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5c2dc92304aa48a4a60443b548bb12f12e119d4b72f314015e67b9e1be97fca", size = 388662, upload-time = "2026-06-30T07:17:38.235Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/f4/921c22a4fd0f1c1ac13a3996ffbf0aa67951e2c8ad0d1d9574938a2932e8/rpds_py-2026.6.3-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:127e08c0642d880cf32ca47ec2a4a77b901f7e2dd1ad9762adb13955d72ffcc9", size = 504896, upload-time = "2026-06-30T07:17:39.689Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/1b/a114b972cefa1ab1cdb3c7bb177cd3844a12826c507c722d3a73516dbbaf/rpds_py-2026.6.3-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8bb68f03f395eb793220b45c097bd4d8c32944393da0fad8b999efac0868fc8c", size = 391545, upload-time = "2026-06-30T07:17:41.336Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/98/af9b3db77d47fcbe6c8c1f36e2c2147ec70292819e99c325f871584a1c11/rpds_py-2026.6.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3450b693fde92133e9f51060568a4c31fcca76d5e53bbd611e689ca446517e9", size = 380059, upload-time = "2026-06-30T07:17:42.857Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/ba/0efd8668b97c1d26a61566386c636a7a7a09829e474fdf807caa15a2c844/rpds_py-2026.6.3-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:5e8d07bddee435a2ff6f1920e18feff28d0bc4533e42f4bf6927fbd073312c41", size = 393235, upload-time = "2026-06-30T07:17:44.637Z" },
+ { url = "https://files.pythonhosted.org/packages/62/90/8c139ee9690f73b0829f32647de6f40d826f8f443af6fa72644f96351aac/rpds_py-2026.6.3-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3a83ae6c67b7676b9878378547ca8e93ed77a580037bcbcd1d32f739e1e6089c", size = 413008, upload-time = "2026-06-30T07:17:46.225Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/97/0043896fdd7828ce09a1d9a8b06433714d0960fc4ff3fc4aa72b666b764e/rpds_py-2026.6.3-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2bfd04c19ddbd6640de0b51894d764bd2758854d5b75bd102d2ef10cb9c293a9", size = 558118, upload-time = "2026-06-30T07:17:47.759Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/40/02355f0e134f783a8f9814c4680a1bd311d37671577a5964ea838573ff37/rpds_py-2026.6.3-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:ca6546b66be9dc4738b1b043d5ebd5488c66c578c5ff0fd0e8065313fe3afb76", size = 623138, upload-time = "2026-06-30T07:17:49.355Z" },
+ { url = "https://files.pythonhosted.org/packages/10/85/48f0abdcef5cce4e034c7a5b0ceeceba0b01bf0d942824f4bb720afe2dec/rpds_py-2026.6.3-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:8e65860d238379ed982fd9ba690579b5e95af2f4840f99c772816dbe573cb826", size = 586486, upload-time = "2026-06-30T07:17:51.141Z" },
+]
+
+[[package]]
+name = "rtc-tools-channel-flow"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pymoca" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/74/bd/a8d14a0f9f147abd590cb25e1afeb0dfc8bfd6d091c25f3e9738e0c764cc/rtc_tools_channel_flow-1.3.1.tar.gz", hash = "sha256:d7e1a025900e975386d5915fedd9d555572801e61872ee70ab82553f474d814b", size = 51304, upload-time = "2025-12-17T10:51:07.57Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/23/5c/ee6cb699992fc5884c223bb1965c6f495be297267106f3157981313c6d5d/rtc_tools_channel_flow-1.3.1-py3-none-any.whl", hash = "sha256:fc2829eb746328b511089b1cb101247cc921c1020dd5c768bb8177a033665fd0", size = 83767, upload-time = "2025-12-17T10:51:06.571Z" },
+]
+
+[[package]]
+name = "rtc-tools-gil-comp"
+version = "2.6.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "casadi-gil-comp" },
+ { name = "defusedxml" },
+ { name = "numpy" },
+ { name = "pymoca" },
+ { name = "rtc-tools-channel-flow" },
+ { name = "scipy" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f8/1c/355e93d8c7b70fe56552cca8bebb8a09ce395acdfb5480b3b80522a98405/rtc_tools_gil_comp-2.6.1-py3-none-any.whl", hash = "sha256:f973a03e89df95bb4a8f04993e9591dadb090c683079c5ce6ae7fa525d1ca6a6", size = 146102, upload-time = "2025-02-12T13:42:26.834Z" },
+]
+
+[[package]]
+name = "ruamel-yaml"
+version = "0.19.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/3b/ebda527b56beb90cb7652cb1c7e4f91f48649fbcd8d2eb2fb6e77cd3329b/ruamel_yaml-0.19.1.tar.gz", hash = "sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993", size = 142709, upload-time = "2026-01-02T16:50:31.84Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93", size = 118102, upload-time = "2026-01-02T16:50:29.201Z" },
+]
+
+[[package]]
+name = "ruamel-yaml-clib"
+version = "0.2.15"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ea/97/60fda20e2fb54b83a61ae14648b0817c8f5d84a3821e40bfbdae1437026a/ruamel_yaml_clib-0.2.15.tar.gz", hash = "sha256:46e4cc8c43ef6a94885f72512094e482114a8a706d3c555a34ed4b0d20200600", size = 225794, upload-time = "2025-11-16T16:12:59.761Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/80/8ce7b9af532aa94dd83360f01ce4716264db73de6bc8efd22c32341f6658/ruamel_yaml_clib-0.2.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c583229f336682b7212a43d2fa32c30e643d3076178fb9f7a6a14dde85a2d8bd", size = 147998, upload-time = "2025-11-16T16:13:13.241Z" },
+ { url = "https://files.pythonhosted.org/packages/53/09/de9d3f6b6701ced5f276d082ad0f980edf08ca67114523d1b9264cd5e2e0/ruamel_yaml_clib-0.2.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56ea19c157ed8c74b6be51b5fa1c3aff6e289a041575f0556f66e5fb848bb137", size = 132743, upload-time = "2025-11-16T16:13:14.265Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/f7/73a9b517571e214fe5c246698ff3ed232f1ef863c8ae1667486625ec688a/ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5fea0932358e18293407feb921d4f4457db837b67ec1837f87074667449f9401", size = 731459, upload-time = "2025-11-16T20:22:44.338Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/a2/0dc0013169800f1c331a6f55b1282c1f4492a6d32660a0cf7b89e6684919/ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71831bd61fbdb7aa0399d5c4da06bea37107ab5c79ff884cc07f2450910262", size = 749289, upload-time = "2025-11-16T16:13:15.633Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/ed/3fb20a1a96b8dc645d88c4072df481fe06e0289e4d528ebbdcc044ebc8b3/ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:617d35dc765715fa86f8c3ccdae1e4229055832c452d4ec20856136acc75053f", size = 777630, upload-time = "2025-11-16T16:13:16.898Z" },
+ { url = "https://files.pythonhosted.org/packages/60/50/6842f4628bc98b7aa4733ab2378346e1441e150935ad3b9f3c3c429d9408/ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b45498cc81a4724a2d42273d6cfc243c0547ad7c6b87b4f774cb7bcc131c98d", size = 744368, upload-time = "2025-11-16T16:13:18.117Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/b0/128ae8e19a7d794c2e36130a72b3bb650ce1dd13fb7def6cf10656437dcf/ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:def5663361f6771b18646620fca12968aae730132e104688766cf8a3b1d65922", size = 745233, upload-time = "2025-11-16T20:22:45.833Z" },
+ { url = "https://files.pythonhosted.org/packages/75/05/91130633602d6ba7ce3e07f8fc865b40d2a09efd4751c740df89eed5caf9/ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:014181cdec565c8745b7cbc4de3bf2cc8ced05183d986e6d1200168e5bb59490", size = 770963, upload-time = "2025-11-16T16:13:19.344Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/4b/fd4542e7f33d7d1bc64cc9ac9ba574ce8cf145569d21f5f20133336cdc8c/ruamel_yaml_clib-0.2.15-cp311-cp311-win32.whl", hash = "sha256:d290eda8f6ada19e1771b54e5706b8f9807e6bb08e873900d5ba114ced13e02c", size = 102640, upload-time = "2025-11-16T16:13:20.498Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/eb/00ff6032c19c7537371e3119287999570867a0eafb0154fccc80e74bf57a/ruamel_yaml_clib-0.2.15-cp311-cp311-win_amd64.whl", hash = "sha256:bdc06ad71173b915167702f55d0f3f027fc61abd975bd308a0968c02db4a4c3e", size = 121996, upload-time = "2025-11-16T16:13:21.855Z" },
+]
+
+[[package]]
+name = "ruff"
+version = "0.15.22"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/3a/06/ae069393fc66e8ff33036d4b368003833bf6e88ccf182e17e7a2f1c754fd/ruff-0.15.22.tar.gz", hash = "sha256:3f15175b1fb580126f58285a5dae6b2ea89000136d980c64499211f116b54809", size = 4785063, upload-time = "2026-07-16T15:14:13.244Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/23/18/ee54b7ae1e121be7a28ea6da4b67564ebb0530e183a54415ab7e3bcd2c4e/ruff-0.15.22-py3-none-linux_armv6l.whl", hash = "sha256:44423e73493737f5e7c5b41d475483898ff37afcdae38bc3da5085e29af1c2d8", size = 10781258, upload-time = "2026-07-16T15:13:19.452Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/d2/2520cb14761ddbeaf57642a76942fc36adcbdbe53b4532241995f6fc485c/ruff-0.15.22-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b82c6482946e9eda7ff2e091d25b8bad3f718684e1916d41bd56873cee05b697", size = 10999477, upload-time = "2026-07-16T15:13:23.318Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/10/74e53572aa758dfaa678c2a2646b5c5515d884b7ca56be4d2ce03ca4b560/ruff-0.15.22-py3-none-macosx_11_0_arm64.whl", hash = "sha256:11c1c715af53a09f714e011106bffc419751ec8232fcb5da42173284ea3fec6f", size = 10466716, upload-time = "2026-07-16T15:13:26.162Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/cc/44eaaf0844e028182f2d0a8f2190d0f359159aed0a9e5ab861d892f1ae2a/ruff-0.15.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:742a29cf29bddb7c8327895d6a10e0e6c5b38a96dd407af9b5d0857f809c0576", size = 10892644, upload-time = "2026-07-16T15:13:29.229Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/21/8edf559014d2b0f82beea19cfb713993ad802ccda16868769979c6090a84/ruff-0.15.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72af58b951b0ae395935ae79763dc349bc0eb706319d28f7a33ad2cfb3cfc178", size = 10576719, upload-time = "2026-07-16T15:13:32.35Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/1e/3a13abd392a3b50b62e5938a831f9ab6e588358cacad5c18545b716d2182/ruff-0.15.22-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d425005c1835eb24e2ee4161cb90e8db263415f4a71c8c72c33abaa6c0c224", size = 11376494, upload-time = "2026-07-16T15:13:35.958Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/3e/422d3d95bcf04dd78e1aeac22184d4f9a8fb2c01865d39d44618484a0317/ruff-0.15.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b9b3f8779a4f08c969defc3c8c35abffaa757e601ed5ae66d6d1db6519969a", size = 12208370, upload-time = "2026-07-16T15:13:39.185Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/91/5d065a0e0a02bf4813f5119ad278462eed081d2b832eb7c021ade0ec9e65/ruff-0.15.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e0dd1b2e4d3d585f897a0d137cbf4eaf6223bef4e8ce34d6bb12556c5f9249e", size = 11581098, upload-time = "2026-07-16T15:13:42.132Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/f9/a0d4871d12fae702eb1f41b686caf05f1f8b124dc6db6f784f53d74918fa/ruff-0.15.22-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365523eb91d9224e1bcb03b022fbf0facb8f9e23792a2c53d9d4b3924bdbdebb", size = 11399422, upload-time = "2026-07-16T15:13:45.2Z" },
+ { url = "https://files.pythonhosted.org/packages/18/80/c843a5176cddbceb0b7e8dd41cf9993490796c1c469348d384f5a5c13c56/ruff-0.15.22-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fabfd168afdf29fee5be98b831efa9683c94d7c5a3b58b9ce5a2e38444589a74", size = 11381683, upload-time = "2026-07-16T15:13:48.46Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/00/8485de0ae92239438a36cfc51350db9b9e85c9ebdfaea91b18e422706662/ruff-0.15.22-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:225dbf095a87f1d9f90f5fd7924d2613ee452a75a4308c63a8f50f761787aa7c", size = 10850295, upload-time = "2026-07-16T15:13:51.655Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/91/24977ec2ec72eaf15e4394ace2959fdff2dd1e14f03e005e838023407169/ruff-0.15.22-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1877d63b9d24ed278744f1523fd11b85540566d54641f97c566d7d9dc5ca5296", size = 10579640, upload-time = "2026-07-16T15:13:54.79Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/47/9b51216951974df1f263ac19da550d34252e0ed7218c25f10c5ef9ed7517/ruff-0.15.22-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1606c510bd7215680d32efab38965f7cdec3ef69f5170a3f4791404ffdd5262", size = 11105077, upload-time = "2026-07-16T15:13:57.915Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/47/20e9d4a3b8016778acea5fc32bb50d35d207500a17ddb529ffa6996feef8/ruff-0.15.22-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:630479b18625f5ffc373f77603a22a9f8ac0acd7ff0501178b5db28ec71e9c64", size = 11490980, upload-time = "2026-07-16T15:14:01.032Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/76/3f72d8fc38c1cb77b38c56a70da9d0c17700cc1cc50f9649c9d3c8f5ba71/ruff-0.15.22-py3-none-win32.whl", hash = "sha256:e5ba0e4a13fd14abbed2a77b517a3911290c6c6c59ef67784328d1668fab76cf", size = 10789165, upload-time = "2026-07-16T15:14:04.16Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/46/4965251734c2b6fcdca1b1b187d20bcac3af0ee5b083b89c910bb961ce3a/ruff-0.15.22-py3-none-win_amd64.whl", hash = "sha256:9be63ba1eb936acd2d1342fb8337c356353706fce233b2a15a09a97037e6acde", size = 11938297, upload-time = "2026-07-16T15:14:07.316Z" },
+ { url = "https://files.pythonhosted.org/packages/57/c9/e69b1ff4c8b69093ef08b8919ab767af0569666865b39c30a8795d88d3c6/ruff-0.15.22-py3-none-win_arm64.whl", hash = "sha256:e1168075b72158510839f250027659cdd78476f40507dd517892304c41318661", size = 11298172, upload-time = "2026-07-16T15:14:10.51Z" },
+]
+
+[[package]]
+name = "s3fs"
+version = "2026.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiobotocore" },
+ { name = "aiohttp" },
+ { name = "fsspec" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/99/00/6677343dc919d6c072bb04d80210afdd22c16838a8d16b3315c122dc728f/s3fs-2026.6.0.tar.gz", hash = "sha256:b28de7082d0a4f72392884bdc497e34a4a1582f675d214c7da0acf6e950a0083", size = 87358, upload-time = "2026-06-16T02:05:48.719Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a5/0b/f68a968b49876eae0f2a515387093cebb2eb9451380a96741cc20efac0d0/s3fs-2026.6.0-py3-none-any.whl", hash = "sha256:60576e31bb31193c1f643f32b4c6439548720ea6918ac702e21cd757c80b5db8", size = 32573, upload-time = "2026-06-16T02:05:47.608Z" },
+]
+
+[[package]]
+name = "scipy"
+version = "1.10.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/84/a9/2bf119f3f9cff1f376f924e39cfae18dec92a1514784046d185731301281/scipy-1.10.1.tar.gz", hash = "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5", size = 42407997, upload-time = "2023-02-19T21:20:13.395Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/53/053cd3669be0d474deae8fe5f757bff4c4f480b8a410231e0631c068873d/scipy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f1564ea217e82c1bbe75ddf7285ba0709ecd503f048cb1236ae9995f64217bd", size = 35003170, upload-time = "2023-02-19T20:40:53.274Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/3e/d05b9de83677195886fb79844fcca19609a538db63b1790fa373155bc3cf/scipy-1.10.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d925fa1c81b772882aa55bcc10bf88324dadb66ff85d548c71515f6689c6dac5", size = 28717513, upload-time = "2023-02-19T20:42:20.82Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/3d/b69746c50e44893da57a68457da3d7e5bb75f6a37fbace3769b70d017488/scipy-1.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaea0a6be54462ec027de54fca511540980d1e9eea68b2d5c1dbfe084797be35", size = 30687257, upload-time = "2023-02-19T20:43:48.139Z" },
+ { url = "https://files.pythonhosted.org/packages/21/cd/fe2d4af234b80dc08c911ce63fdaee5badcdde3e9bcd9a68884580652ef0/scipy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15a35c4242ec5f292c3dd364a7c71a61be87a3d4ddcc693372813c0b73c9af1d", size = 34124096, upload-time = "2023-02-19T20:45:27.415Z" },
+ { url = "https://files.pythonhosted.org/packages/65/76/903324159e4a3566e518c558aeb21571d642f781d842d8dd0fd9c6b0645a/scipy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:43b8e0bcb877faf0abfb613d51026cd5cc78918e9530e375727bf0625c82788f", size = 42238704, upload-time = "2023-02-19T20:47:26.366Z" },
+]
+
+[[package]]
+name = "semver"
+version = "3.0.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730, upload-time = "2025-01-24T13:19:27.617Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912, upload-time = "2025-01-24T13:19:24.949Z" },
+]
+
+[[package]]
+name = "setuptools"
+version = "75.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/54/292f26c208734e9a7f067aea4a7e282c080750c4546559b58e2e45413ca0/setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", size = 1337429, upload-time = "2024-11-20T18:16:13.378Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/55/21/47d163f615df1d30c094f6c8bbb353619274edccf0327b185cc2493c2c33/setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d", size = 1224032, upload-time = "2024-11-20T18:16:10.861Z" },
+]
+
+[[package]]
+name = "shellingham"
+version = "1.5.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
+]
+
+[[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 = "sniffio"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
+]
+
+[[package]]
+name = "sqlalchemy"
+version = "2.0.51"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/02/f1/a7a892f18d4d224e6b26f706531eafccc41e37594d37d304786969ee13cb/sqlalchemy-2.0.51.tar.gz", hash = "sha256:804dccd8a4a6242c4e30ad961e540e18a588f6527202f2d6791b01845d59fdc9", size = 9912201, upload-time = "2026-06-15T15:41:20.012Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3a/69/a67c69e5f28fc9c99d6f7bd60bd50e91f2fed2423e3b30fb228fa00e51f3/sqlalchemy-2.0.51-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1aa10c0daee6705294d181daadaa793221e1a59ed55000a3fab1d42b088ce4ba", size = 2161838, upload-time = "2026-06-15T16:05:17.144Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/a4/c8c22b8438bddc0a030157c6ec0f6ef97b3c38effa444bdab2a27af04090/sqlalchemy-2.0.51-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5b2ed6d828f1f09bd812861f4f59ca3bc3803f9df871f4555187f0faf018604", size = 3319402, upload-time = "2026-06-15T16:10:40.002Z" },
+ { url = "https://files.pythonhosted.org/packages/90/54/44012d32fd77d991256d2ff793ba3807c51d40cb27a85b4796224f6744df/sqlalchemy-2.0.51-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:436728ce18a80f6951a1e11cc6112c2ede9faf20766f1a26195a7c441ca12dbd", size = 3319675, upload-time = "2026-06-15T16:12:25.658Z" },
+ { url = "https://files.pythonhosted.org/packages/29/a5/de0592acaf5906cd7430874392d6f7e8b4a7c8437610953ee2d1501c0b44/sqlalchemy-2.0.51-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dc261707bf5739aea8a541593f3cc1d463c2701fb05fbcbba0ce031b69a21260", size = 3270777, upload-time = "2026-06-15T16:10:42.125Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/14/a44c90739c780b362238e4ac3cb19dd0ca40d13e6ddc5daa112166ddab4f/sqlalchemy-2.0.51-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a6d26094615306d116dd5e4a51b0304c99dd2356fc569eed6922a80a6bd3b265", size = 3293940, upload-time = "2026-06-15T16:12:27.156Z" },
+ { url = "https://files.pythonhosted.org/packages/65/eb/fbd0f206a330e66f8c602a99c37c4e731f107faed62954b41b01f16dd9d9/sqlalchemy-2.0.51-cp311-cp311-win32.whl", hash = "sha256:ca8435d13829b92f4a97362d91975154a4015db3a2634154e1754e9a915e6b86", size = 2121183, upload-time = "2026-06-15T16:13:29.905Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/fd/005bf80f3cf6e5c62b5dd68616280f51cd012c60840fa74781b3ed7b1623/sqlalchemy-2.0.51-cp311-cp311-win_amd64.whl", hash = "sha256:4a011ea4510683319ce4ed274b56ee05194b39b6da9d09ca7a39388f0fa84dcc", size = 2145796, upload-time = "2026-06-15T16:13:31.283Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/22/dbf013a12ec759e54a34a119e9e217435b3f71b2dd5c61a7ade0a25dae87/sqlalchemy-2.0.51-py3-none-any.whl", hash = "sha256:bb024d8b621d0be75f4f44ecc7c950450026e76d66dc8f791bb5331d7fed59d5", size = 1944334, upload-time = "2026-06-15T16:09:22.418Z" },
+]
+
+[package.optional-dependencies]
+asyncio = [
+ { name = "greenlet" },
+]
+
+[[package]]
+name = "starlette"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" },
+]
+
+[[package]]
+name = "streamcapture"
+version = "1.2.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "setuptools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9e/cc/59abd0b4eb6576bbe59c5bf4e23dfbe306c804b201bfaeca6470a8ba7562/streamcapture-1.2.7.tar.gz", hash = "sha256:2eb59cd87f91c7964a670a51879c5cd8428ed5d37dfe439c9882a87c5ae9a837", size = 7990, upload-time = "2026-02-05T19:06:21.513Z" }
+
+[[package]]
+name = "strenum"
+version = "0.4.15"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/85/ad/430fb60d90e1d112a62ff57bdd1f286ec73a2a0331272febfddd21f330e1/StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff", size = 23384, upload-time = "2023-06-29T22:02:58.399Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/69/297302c5f5f59c862faa31e6cb9a4cd74721cd1e052b38e464c5b402df8b/StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659", size = 8851, upload-time = "2023-06-29T22:02:56.947Z" },
+]
+
+[[package]]
+name = "text-unidecode"
+version = "1.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885, upload-time = "2019-08-30T21:36:45.405Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154, upload-time = "2019-08-30T21:37:03.543Z" },
+]
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
+]
+
+[[package]]
+name = "tomli"
+version = "2.4.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" },
+ { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" },
+ { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" },
+ { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" },
+ { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" },
+ { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" },
+]
+
+[[package]]
+name = "ty"
+version = "0.0.61"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/92/63/6944925d0fe9a4bb9cc744e6c045a42bbd2ee4654c103190674577a36c3f/ty-0.0.61.tar.gz", hash = "sha256:acbf0d914cc7e2e57ccc440036af36114819e2a604a5ffb554e72e4ca7dd65a2", size = 6234957, upload-time = "2026-07-18T01:39:54.696Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/cf/044f31523e2768e3e64b0ca2ec32f70b3a731d4a2caa6ea110baf26e251c/ty-0.0.61-py3-none-linux_armv6l.whl", hash = "sha256:148779b8675eac93f40ec58bd70037fe67537117f20a23272264f8f136d41336", size = 11891448, upload-time = "2026-07-18T01:39:18.449Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/55/558cfe76b65d91d1854bbfac336020bd42fd887caa632d845d13c0c539eb/ty-0.0.61-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:08217382b3385808ee7288501ea3214b32631b08d1fd091ece6799b0c95264c5", size = 11602442, upload-time = "2026-07-18T01:39:20.914Z" },
+ { url = "https://files.pythonhosted.org/packages/27/be/78c0ae6634cd606a68e5b46b338db427a48a1800c96a749b2d2f7a702e03/ty-0.0.61-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6d99c729011b47dec20e78a32ac9c8f6defd4cf62f7bb851bbccf70dde6cee50", size = 11125286, upload-time = "2026-07-18T01:39:22.893Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/18/a40793962f1b6337938ddb0bca7496b54e70879e23b4d2cc8dfd7e5d1af3/ty-0.0.61-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cda607978ae271b77e51c947663218bce635c3507e256865444b10c37cdb60d", size = 11663403, upload-time = "2026-07-18T01:39:25.017Z" },
+ { url = "https://files.pythonhosted.org/packages/98/c1/7879244da5b30407dc368946d36be5024380073408b079f144ffe034030e/ty-0.0.61-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d78f160a0f9434d570cdcdbc4dafba1f6aac3c47a32f9f63995b3cb55ffe4b6", size = 11715250, upload-time = "2026-07-18T01:39:27.045Z" },
+ { url = "https://files.pythonhosted.org/packages/35/c4/8a4637cd58abd37f315dd515e24c582986cb1bfdf2edc4786882f5a4f69a/ty-0.0.61-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09aeab4800b36e93e4ce918699004da642d74988cac920b7592a6a2b9be6611c", size = 12393876, upload-time = "2026-07-18T01:39:29.197Z" },
+ { url = "https://files.pythonhosted.org/packages/27/4b/27e7c640b1272743503229aa17ae2167a538040c4716a2fa1777c2b34fea/ty-0.0.61-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dccc8136df44142a109953a168be17b4915c99876b047d0b6672c31dae939bdf", size = 12958187, upload-time = "2026-07-18T01:39:31.308Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/f5/70eaaefb6081fb0a8115cff66fbfaa20dafac8c646df2477adad95a59de2/ty-0.0.61-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:220760c2d13a887d027ee1093172c24ac35b6e634805329c93a30908ae4d3f5c", size = 12560101, upload-time = "2026-07-18T01:39:33.35Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/5a/17bae3b6429b5c479dc6c1e344d34e1f79efbc27531f15f3ee5b5da63745/ty-0.0.61-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:effefbb89da7128d18059529d1c2ea390fe7f1f3882690d257ca2143d49a0c34", size = 12225389, upload-time = "2026-07-18T01:39:35.436Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/0e/2ac380ba20d6395542c8df1d6fa4f00e2aead784c2e6aaefa1e02ed0610c/ty-0.0.61-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:ba8b28a5ef811d5bb6461e37d76110c06fd20487474865c323d3d18b08b972b2", size = 12548403, upload-time = "2026-07-18T01:39:37.556Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/e5/7da4b73e825e1a9808c26d68b0156e9a37aede1846191210dfffb8c64042/ty-0.0.61-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:88ecd6d9b05e8174b1860dac9bd3e188d6cef5702b0d3239fd9f94f6ac73a29d", size = 11621813, upload-time = "2026-07-18T01:39:39.919Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/3c/5b58015e998cd0d89b17a463b6321421457d86d987574e8dac65ddfceba3/ty-0.0.61-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fb0cdfe4c48542ffb9a1139825dfa3d4aae49e96e966682ef7da762ab97831ff", size = 11734101, upload-time = "2026-07-18T01:39:42.097Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/21/294f4cc819b7b12ed659fd860e5cdfbd592d4c768c8f23596685dbc43e6b/ty-0.0.61-py3-none-musllinux_1_2_i686.whl", hash = "sha256:dff03873c0c3d0b44738f8b6d403b0756a31cf54c65136397df7624c6159b1f0", size = 11988401, upload-time = "2026-07-18T01:39:44.183Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/26/0f96f79fdac118521a9771e9eef3f9b3f447d647b2c77953e80a1715c7e8/ty-0.0.61-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a9210e80e3d41c1dfc751e9e8e0980272f475031fafd0fb0f48aee233c78da03", size = 12330624, upload-time = "2026-07-18T01:39:46.662Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/08/1e62d1bca5c0cebdc7a34db1f4b61557aab85961cedd56953dd2c32d3e66/ty-0.0.61-py3-none-win32.whl", hash = "sha256:e3e1fe06f49a5492a922a5df2739834aa5ee978c7dd10414119dc8755cc40c9c", size = 11313991, upload-time = "2026-07-18T01:39:48.761Z" },
+ { url = "https://files.pythonhosted.org/packages/26/f1/d8e33b3aeb36b73d81ae34d10e46ec4abf506d68f4e0a1491a76a593dd42/ty-0.0.61-py3-none-win_amd64.whl", hash = "sha256:25f2291169e0298fcdbba1b1fea64f8207a6c1908dddef32346fd5e3e6ac9221", size = 12311717, upload-time = "2026-07-18T01:39:50.881Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/14/7caec26d93a943c0e7d15eb7374644508d08cbd387d112b722b12d14e044/ty-0.0.61-py3-none-win_arm64.whl", hash = "sha256:3e496f7698bc4b5bbb1eb66d8b5799ba87596d88d36604ca359083893fa2fc49", size = 11693485, upload-time = "2026-07-18T01:39:52.73Z" },
+]
+
+[[package]]
+name = "typer"
+version = "0.27.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-doc" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "rich" },
+ { name = "shellingham" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/37/78/fda3361b56efc27944f24225f6ecd13d96d6fcfe37bd0eb34e2f4c63f9fc/typer-0.27.0.tar.gz", hash = "sha256:629bd12ea5d13a17148125d9a264f949eb171fb3f120f9b04d85873cab054fa5", size = 203430, upload-time = "2026-07-15T19:21:07.007Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl", hash = "sha256:6f4b27631e47f077871b7dc30e933ec0131c1390fbe0e387ea5574b5bac9ccf1", size = 122716, upload-time = "2026-07-15T19:21:05.553Z" },
+]
+
+[[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 = "typing-inspection"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
+]
+
+[[package]]
+name = "tzdata"
+version = "2026.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" },
+]
+
+[[package]]
+name = "tzlocal"
+version = "5.4.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/81/5b/879b2f932adfa7a053c360d50bc896c977fa6426109185f7c12ebdd0cb9d/tzlocal-5.4.4.tar.gz", hash = "sha256:8dbb8660838688a7b6ba4fed31d18dedf842afb4d47ca050d6d891c2c15f3be4", size = 31170, upload-time = "2026-06-29T08:03:40.026Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl", hash = "sha256:aae09f0126a8a86fa736be266eb4a471380d26a0de3bc14844e7821fee3e2a15", size = 18115, upload-time = "2026-06-29T08:03:38.666Z" },
+]
+
+[[package]]
+name = "uncalled-for"
+version = "0.3.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b5/82/345cc927f7fbdae6065e7768759932fcc827fc20b29b45dfbafa2f1f7da4/uncalled_for-0.3.2.tar.gz", hash = "sha256:89f5dbcd71e2b8f47c030b1fa302e6cce2ec795d1ac565eeb6525c5fe55cb8a2", size = 50032, upload-time = "2026-05-06T13:38:25.204Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3b/25/2c87754f3a9e692315f7b811244090e68f362979fc8886b3fbd2985a1d8c/uncalled_for-0.3.2-py3-none-any.whl", hash = "sha256:0ff60b142c7d1f8070bde9d42afaa70aedc77dcc10998c227687e9c15713418e", size = 11444, upload-time = "2026-05-06T13:38:24.025Z" },
+]
+
+[[package]]
+name = "urllib3"
+version = "2.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
+]
+
+[[package]]
+name = "uvicorn"
+version = "0.51.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a2/65/b7c6c443ccc58678c91e1e973bbe2a878591538655d6e1d47f24ba1c51f3/uvicorn-0.51.0.tar.gz", hash = "sha256:f6f4b69b657c312f516dd2d268ab9ae6f254b11e4bac504f37b2ab58b24dd0b0", size = 94412, upload-time = "2026-07-08T10:59:05.962Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/45/ec/dbb7e5a6b91f86bfb9eb7d2988a2730907b6a729875b949c7f022e8b88fa/uvicorn-0.51.0-py3-none-any.whl", hash = "sha256:5d38af6cd620f2ae3849fb44fd4879e0890aa1febe8d47eb355fb45d93fe6a5b", size = 73219, upload-time = "2026-07-08T10:59:04.44Z" },
+]
+
+[[package]]
+name = "websockets"
+version = "16.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/21/f7/bc3a25c5ec26ce62ce487690becc2f3710bbc7b33338f005ad390db0b986/websockets-16.1.1.tar.gz", hash = "sha256:db234eda965dcce15df96bb9709f587cd87d4d52aaf0e80e2f34ec04c7670c57", size = 182204, upload-time = "2026-07-17T22:51:05.858Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2b/03/47debfe28e9d6d354be5d777b67fd44c359b9eb299a5d103500bd7cc3e37/websockets-16.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d0fcf657e9f13ff4b177960ab2200237b12994232dfb6df16f1cfe1d4339f93c", size = 179566, upload-time = "2026-07-17T22:48:49.596Z" },
+ { url = "https://files.pythonhosted.org/packages/72/93/31efa1ed78c17e5cfc229fd449e3966e1b9cc15753204cd585cc8dd01f4a/websockets-16.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b852788aa51764e2d8e4cf5493d559326bcae5e38d16ba25ffa322b034df272a", size = 177250, upload-time = "2026-07-17T22:48:50.942Z" },
+ { url = "https://files.pythonhosted.org/packages/01/4a/542378ab3972b0c1cf1df3df3eff9591cea0d30c58c3aa3c4ddbc244e787/websockets-16.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1427fb4cf0d72f66333e2cacc3ff5f575bf2d7008166ce991a4a470b21d51a22", size = 177528, upload-time = "2026-07-17T22:48:52.59Z" },
+ { url = "https://files.pythonhosted.org/packages/33/d9/162321f63c7eed558e9e1798ed7a1e34a4f6dab51f35419e4ed7a4907979/websockets-16.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:da4ca1a9d72f9030b3146b8d7022719a9f3d478f61efe6f7dd51d243f61c51b2", size = 186859, upload-time = "2026-07-17T22:48:53.915Z" },
+ { url = "https://files.pythonhosted.org/packages/de/09/87df740f7430ce564bd52402e9c9458d4d0459cc7d2ee29e530c8204851b/websockets-16.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86d7f0f8bdb25d2c632b72527325e4776430fd5bc61b9118de4e2b8ddb5f5b01", size = 188095, upload-time = "2026-07-17T22:48:55.384Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/12/3d2703af7cc095f3c81904c92208cc1ae79affbc67376944b50ee9301f73/websockets-16.1.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7dfcad78ea1492ee3a9ec765cb7f51bbc17d477107aaf6b22abf7b2558d1c5a0", size = 191385, upload-time = "2026-07-17T22:48:56.742Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/69/986aa0234a964a00f5149cfc46e136e96c8faad1c783474550f40d31aef4/websockets-16.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fb9a0a6dc3d1b3986cb88091b6899f0396651e0f74e2c9766ab8d6ffc3842e29", size = 188653, upload-time = "2026-07-17T22:48:58.134Z" },
+ { url = "https://files.pythonhosted.org/packages/35/6b/10f9d03e3970a69ba67bd3b46b87a929b586d0300fadbfe14f57c1f85490/websockets-16.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29dfa8114c4a620c69591c5973860f768eac29d3fd6904f37f34266cb219c512", size = 187426, upload-time = "2026-07-17T22:48:59.515Z" },
+ { url = "https://files.pythonhosted.org/packages/56/db/bb3aad62bf63d8bb3f0634b2eabffcfb3677a34bd19492110ff6869cf703/websockets-16.1.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6ff9417c0ada4d0f7d212f928303e5579bdf3ace4c802fa4afabb30995da58c3", size = 184882, upload-time = "2026-07-17T22:49:00.916Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/4c/c09a2ea9bfbeccce52fdc383e5f28af4bc8843338aabac28c81489af6120/websockets-16.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fe0b50da2d84535fb4f7b4bfa951280f97ce3d558a0443b541166d609e67b57", size = 187584, upload-time = "2026-07-17T22:49:02.283Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/8b/31bb4eb4d9eaacf1fdd39d115772a8aeaedfc19b5dc262e57ffbc8a9d42c/websockets-16.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34420aaa64440ebd51ac72ca8a45ef4626429438c9b02e633ae412ed43f925d3", size = 186174, upload-time = "2026-07-17T22:49:03.973Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/e4/dc02d725610a1ad49e193ef91a548194d71bdc6cdf27da83067dd1f73995/websockets-16.1.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a6a61aff018180c9c50b7b0da33bfd29d378af3497429c95006c589a23a11648", size = 187986, upload-time = "2026-07-17T22:49:05.553Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/73/30ed84c8bfd14c73d4af29d5ed9323c3073b48e0b7b23b67070f4e7fd59b/websockets-16.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:04fd29a0e2fe9414a95b00e92c67ae51bf900c50c0f8a4b2dafdad621f49ea1d", size = 185565, upload-time = "2026-07-17T22:49:06.959Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/d3/4be8d4959f51e31b4f8fc0ece12b45bd3b6c0d15ea23b9990d9c11fc805f/websockets-16.1.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5c31aa7e39ee3e8a358573257f1c0bb5c52430d1b637030dd9c8cc2c282926be", size = 186598, upload-time = "2026-07-17T22:49:08.293Z" },
+ { url = "https://files.pythonhosted.org/packages/26/fa/abb38597a52d84ed9cfacadc7a0c6f2db282c0ab23cdf72b58a666a21227/websockets-16.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d14bfb217eb4701e850f1525c9d29d79c44794cdf1c299ead25f39f8c78dea81", size = 186834, upload-time = "2026-07-17T22:49:09.766Z" },
+ { url = "https://files.pythonhosted.org/packages/59/80/1119ad08a228b90c4eb77fbe48df7836731a605f5f881ba701ca826a4a65/websockets-16.1.1-cp311-cp311-win32.whl", hash = "sha256:2e28e602bb13da44fbe518c1781a88e3b9d4c3d48d02c9bad83e546164336f57", size = 179940, upload-time = "2026-07-17T22:49:11.196Z" },
+ { url = "https://files.pythonhosted.org/packages/71/b2/e511c1c6f64a95c2f3fc54bffda0e14eaa7e9442be605c29270f7589b918/websockets-16.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:7421fad442de870a8cbf2287d1cad7e706ece0dbfeba5e911df132cbdc1cb56a", size = 180239, upload-time = "2026-07-17T22:49:12.519Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/ed/71fea6e141590cafc40b14dc5943b0845606bee87bdb52a21b6a73eb4311/websockets-16.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:820fb8450edddae3812fd58cbc08e2bf22812cb248ecb5f06dbb82119a56e869", size = 177185, upload-time = "2026-07-17T22:50:56.665Z" },
+ { url = "https://files.pythonhosted.org/packages/01/ec/00e7eeca200facf9266a83e4cbbf1bed0e67fba1d4d45031d3e5b3d81b5c/websockets-16.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:125f22dbefaf1554fea66fc83851490edb284ce4f501d37ffed2752f418332d9", size = 177459, upload-time = "2026-07-17T22:50:58.197Z" },
+ { url = "https://files.pythonhosted.org/packages/75/fd/5774c4b33f7c0d8f0c51809c8b3a93456c48e3543579262cfa64eb5f522e/websockets-16.1.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:30bbe120437b5648a77d3519b7024ea09530e0b5b18d3698c5a0ae536fe0cc2e", size = 178294, upload-time = "2026-07-17T22:50:59.641Z" },
+ { url = "https://files.pythonhosted.org/packages/37/c3/48e2c03d2bd79bb45948841c592d24156312dd5f58cdf8f549febe652fb6/websockets-16.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6b9dadbef0cccd9f4c4ee96b08898afa73e26803bbe0f6aeb5bb12b0074206d", size = 179190, upload-time = "2026-07-17T22:51:01.129Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/3f/73e511ecf2496ceac57dd4ed8388efe2bcf0769338a2dbf242c8366ae87e/websockets-16.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56cd5fc4f10a9ea8aa0804bddb7b42506cf9e136046f3b4c27de8fec9e2ecba5", size = 180330, upload-time = "2026-07-17T22:51:02.603Z" },
+ { url = "https://files.pythonhosted.org/packages/be/4d/2d0d67834092e354d2b0498f014a41249a89556bc406cf86f3e1557bb463/websockets-16.1.1-py3-none-any.whl", hash = "sha256:6abbd3e82c731c8e531714466acd5d87b5e88ac3243465337ba71d68e23ae7e3", size = 173814, upload-time = "2026-07-17T22:51:04.184Z" },
+]
+
+[[package]]
+name = "wheel"
+version = "0.45.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545, upload-time = "2024-11-23T00:18:23.513Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" },
+]
+
+[[package]]
+name = "wrapt"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2b/b0/c1f5a970721f06b85c0cd5142e0ff8fe067708abd779b0c4f4be7d61d09f/wrapt-2.3.0.tar.gz", hash = "sha256:681a2d0eefd721998f90642762b8e75c2159ec531b20ad5e437245ea7b06a107", size = 131509, upload-time = "2026-07-28T06:06:14.895Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/00/b8/9182e4c618a847be0baccb68e4602b070d0fa22c782cf058f4bc66b32709/wrapt-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ab559e1b2551d23d54db2a0001c6d73bad022a254639561c5f6c382a9d6c2fe", size = 81427, upload-time = "2026-07-28T06:04:20.106Z" },
+ { url = "https://files.pythonhosted.org/packages/84/ca/613cefd9c5977366b1587e61c0b428176d382e6d75b454084c5e58503042/wrapt-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bff9a671bc00709cab5a7f745c592b5671873449db0ee2a569af994f16b29a4d", size = 82360, upload-time = "2026-07-28T06:04:21.613Z" },
+ { url = "https://files.pythonhosted.org/packages/71/71/4cd2151a236f44a6e2dd4ed8011838d7ba0be3d656c8bafdfc65a2ed1917/wrapt-2.3.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fc648a335d7e01adb3640b25f02fd0ea05886cf04d0af7f4ee902bc7b5e466e8", size = 161700, upload-time = "2026-07-28T06:04:22.723Z" },
+ { url = "https://files.pythonhosted.org/packages/49/2c/bc508fee75eb2919ed69769800b09968e4aab16897f909a23f39c81e323f/wrapt-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d0077f3d65541925fa83002f967b22ad6550d24813ac64cb905f717194128d9c", size = 162922, upload-time = "2026-07-28T06:04:24.177Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/e5/04f34d38e66d857dfc2fc4088d60e70c0e422467822defa49b2b4a26e17b/wrapt-2.3.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9790ea25190a4e0fe4cdf4eeb868e9d75f8a024a70a5b6bf9c348a3a2b72e731", size = 156125, upload-time = "2026-07-28T06:04:25.58Z" },
+ { url = "https://files.pythonhosted.org/packages/23/41/c35940ea1c423f129ebe4361db853bc80d4def6326242e1206fa15bf94f4/wrapt-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:816877aa749253149f9ecfd2635d4d948ecfa338e1a0311d187b1acb1bb8a3eb", size = 162039, upload-time = "2026-07-28T06:04:27.154Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/60/9bda34c3d7d182aa703fe35339ae0ed4c4dad5e5c587f93890143e1f87fb/wrapt-2.3.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d1c2c1b808600d2ea808e6360910a60ed5f409a4011655e10f9164ba0a414a6", size = 155110, upload-time = "2026-07-28T06:04:28.497Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/ba/60bfd9b1a751f4fcb2d603668fc272d651ccdd339a56acf8c40ad21a0293/wrapt-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5ba1e5e08ddc46130e9682b2c249f2d1dd39bda9106ed4bd401b7519f18f41bd", size = 161089, upload-time = "2026-07-28T06:04:29.959Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/32/2bd358c6f4f1305c813479d1e9ba746bebdd794f4a20107ab2b3ee0cbd45/wrapt-2.3.0-cp311-cp311-win32.whl", hash = "sha256:45c9279b373d15649dfa2c2077cb3408ea1a6d3125afbdab9d6b809a66f68e14", size = 78030, upload-time = "2026-07-28T06:04:31.241Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/62/ecc969b13b141fef89b888c9760821cb01a86ac8fc953911592c8e1e1522/wrapt-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:195b1842b4122fb54e3cd3dd5b2b4aa49302a5a61da901df0481f5c97aedde84", size = 80944, upload-time = "2026-07-28T06:04:32.655Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/3d/9278ada8a2b3f24372b630361e84e9a7de7abc3784634860c26d1c37785a/wrapt-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:6db604ef0c67bdb2042ecdfd7b7f037cf09733557ca42360d1018285634f7b98", size = 80074, upload-time = "2026-07-28T06:04:33.811Z" },
+ { url = "https://files.pythonhosted.org/packages/00/39/3daf9f47be208606586de4568ba6713db53ebc8fd7a575aea1fe57983b69/wrapt-2.3.0-py3-none-any.whl", hash = "sha256:d8c7ed08477429752b8c44991f40ad7838b18332a160698740a6bfbc10d998a2", size = 61866, upload-time = "2026-07-28T06:06:12.9Z" },
+]
+
+[[package]]
+name = "yarl"
+version = "1.24.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "idna" },
+ { name = "multidict" },
+ { name = "propcache" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/31/33/ebe9e3d1f86c7a0b51094c0a146392045ca1631d2664889539dec8088a33/yarl-1.24.5.tar.gz", hash = "sha256:e81b83143bee16329c23db3c1b2d82b29892fcbcb849186d2f6e98a5abe9a57f", size = 228679, upload-time = "2026-07-20T02:07:45.435Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fe/db/3cb5df059756a45761cc3dee8fd25ec82b83a6585ea3542b969fda850f99/yarl-1.24.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2c1fe720934a16ea8e7146175cba2126f87f54912c8c5435e7f7c7a51ef808d3", size = 135043, upload-time = "2026-07-20T02:04:52.39Z" },
+ { url = "https://files.pythonhosted.org/packages/44/f8/767d6bd5a03db63bc467df2fb56d6fafeae9667d74aea92cd6af399f828b/yarl-1.24.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c687ed078e145f5fd53a14854beff320e1d2ab76df03e2009c98f39a0f68f39a", size = 96942, upload-time = "2026-07-20T02:04:54.26Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/97/10b939c44d7b28d1dbc389cfc7012306d1ea8dba01eaef44b39fffaee52a/yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:709f1efed56c4a145793c046cd4939f9959bcd818979a787b77d8e09c57a0840", size = 97046, upload-time = "2026-07-20T02:04:56.638Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/7a/b410dbe39b6255c55fb2a2bcee96eb844d0789235ddc381a889a90dc72d6/yarl-1.24.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:874019bd513008b009f58657134e5d0c5e030b3559bd0553976837adf52fe966", size = 110512, upload-time = "2026-07-20T02:04:58.955Z" },
+ { url = "https://files.pythonhosted.org/packages/83/c7/da591971f78a5617e1f21f5699858ebccd836fe181a6493788ffc91ba69b/yarl-1.24.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4582acf7ef76482f6f511ebaf1946dae7f2e85ec4728b81a678c01df63bd723", size = 102454, upload-time = "2026-07-20T02:05:00.623Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/8e/73b0ed4de47289a78a96045d76d1cfe5e41848bf0da59ce25b2ec87ee05d/yarl-1.24.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2cabe6546e41dabe439999a23fcb5246e0c3b595b4315b96ef755252be90caeb", size = 117617, upload-time = "2026-07-20T02:05:02.325Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/14/b744747bc4f57a8d55bd744df463457524583e1e9f7538b5ace0346ab92e/yarl-1.24.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:17f57620f5475b3c69109376cc87e42a7af5db13c9398e4292772a706ff10780", size = 116135, upload-time = "2026-07-20T02:05:04.05Z" },
+ { url = "https://files.pythonhosted.org/packages/66/ca/95aa4d0e5b7ea4f20e4d577c42d001ed9df207569fdb063cc5ed4ebb496b/yarl-1.24.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:570fec8fbd22b032733625f03f10b7ff023bc399213db15e72a7acaef28c2f4e", size = 111935, upload-time = "2026-07-20T02:05:05.738Z" },
+ { url = "https://files.pythonhosted.org/packages/72/0d/d2ad8d6b147832d177a4e720ba1962fe686eb0913b74503b3eca094b8bba/yarl-1.24.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5fede79c6f73ff2c3ef822864cb1ada23196e62756df53bc6231d351a49516a2", size = 110010, upload-time = "2026-07-20T02:05:07.471Z" },
+ { url = "https://files.pythonhosted.org/packages/50/18/eb335e4120903903f4865041355ae46256a2406eb2865bc24827f4f27b61/yarl-1.24.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ccf9aca873b767977c73df497a85dbedee4ee086ae9ae49dc461333b9b79f58", size = 110058, upload-time = "2026-07-20T02:05:09.246Z" },
+ { url = "https://files.pythonhosted.org/packages/44/70/97353add32c62ad6f206d948ac5a5ee84398225e534dc6ed6433d1b335b6/yarl-1.24.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ad5d8201d310b031e6cd839d9bac2d4e5a01533ce5d3d5b50b7de1ef3af1de61", size = 103308, upload-time = "2026-07-20T02:05:11.31Z" },
+ { url = "https://files.pythonhosted.org/packages/68/39/5e7398d4b6f6b3c9062823ebc60802df5b272e3fe9e788f9734c6ee46c85/yarl-1.24.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:841f0852f48fefea3b12c9dfec00704dfa3aef5215d0e3ce564bb3d7cd8d57c6", size = 116898, upload-time = "2026-07-20T02:05:13.099Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/c9/09e52f2239e8b96357eccca05915382e4ba5405ebfb623b6036040d99654/yarl-1.24.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:9baafc71b04f8f4bb0703b21d6fc9f0c30b346c636a532ff16ec8491a5ea4b1f", size = 109400, upload-time = "2026-07-20T02:05:14.821Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/6a/e94133d4c2d1a14d2384310bf3e79d9cf32c9d1eae1c6f034fb80d098fa1/yarl-1.24.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d897129df1a22b12aeed2c2c98df0785a2e8e6e0bde87b389491d0025c187077", size = 115934, upload-time = "2026-07-20T02:05:17.78Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/3c/34955ed967b976fc38edcbb6d538dee79dbda4cb7fc7f72a0907a7c78e0f/yarl-1.24.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dd625535328fd9882374356269227670189adfcc6a2d90284f323c05862eecbd", size = 112178, upload-time = "2026-07-20T02:05:19.675Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/46/d7bd3a8859d47dcfaffd7127af7076032a7da278a9a02e17b5f37bfb6712/yarl-1.24.5-cp311-cp311-win_amd64.whl", hash = "sha256:f4239bbec5a3577ddb49e4b50aeb32d8e5792098262ae2f63723f916a29b1a25", size = 97544, upload-time = "2026-07-20T02:05:21.523Z" },
+ { url = "https://files.pythonhosted.org/packages/01/69/c1bfd21e32c638974ea2c542a0b8c53ef1fa9eff336020f5d014f9503ff2/yarl-1.24.5-cp311-cp311-win_arm64.whl", hash = "sha256:3ac6aff147deb9c09461b2d4bbdf6256831198f5d8a23f5d37138213090b6d8a", size = 93359, upload-time = "2026-07-20T02:05:23.493Z" },
+ { url = "https://files.pythonhosted.org/packages/61/02/962c1cbfc401a30c1d034dc67ff395f64b52302c6d62de556c1fca99acc0/yarl-1.24.5-py3-none-any.whl", hash = "sha256:a33700d13d9b7d84fd10947b09ff69fb9a792e519c8cb9764a3ca70baa6c23a7", size = 58612, upload-time = "2026-07-20T02:07:43.461Z" },
+]