diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..eb9b82eb7de30fb0baefb6c7229c5af99aeff234 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,37 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info/ +dist/ +build/ + +# Virtual environments (but not in backend/) +**/.venv/ +**/venv/ +**/ENV/ +**/env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore + +# Tests +tests/ +*.egg-info/ + +# Lock files +uv.lock diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..13566b81b018ad684f3a35fee301741b2734c8f4 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ea72a911af2d782f20b992e808276bb838718d8 --- /dev/null +++ b/.idea/copilot.data.migration.agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask.xml b/.idea/copilot.data.migration.ask.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ef04e2ea0752989be4a246d998b53adf46bab42 --- /dev/null +++ b/.idea/copilot.data.migration.ask.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask2agent.xml b/.idea/copilot.data.migration.ask2agent.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f2ea11e7f0069b02b6f715f9735b8a31b234538 --- /dev/null +++ b/.idea/copilot.data.migration.ask2agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml new file mode 100644 index 0000000000000000000000000000000000000000..8648f9401aa827dc53e658ac3b1c1f1556df236b --- /dev/null +++ b/.idea/copilot.data.migration.edit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000000000000000000000000000000000..03d9549ea8e4ada36fb3ecbc30fef08175b7d728 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..90dee705c2feea55b5758429d0dce56882074a46 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + {} + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..3befe1452c370485afd12a903575fd6fe8e07993 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/rmscript_space_demo.iml b/.idea/rmscript_space_demo.iml new file mode 100644 index 0000000000000000000000000000000000000000..24643cc37449b4bde54411a80b8ed61258225e34 --- /dev/null +++ b/.idea/rmscript_space_demo.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..7df0f812fa08018ba7b2c8849fb28c2b91872677 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..c171e5d4cb6334829b85486c04d6b70b76742df8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +# Dockerfile for RMScript Web Demo on HuggingFace Spaces +FROM python:3.11-slim + +# Set working directory +WORKDIR /app + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + && rm -rf /var/lib/apt/lists/* + +# Copy reachy_mini package source (dependency of rmscript) +COPY reachy_mini/ /app/reachy_mini/ + +# Install reachy_mini package +RUN pip install --no-cache-dir /app/reachy_mini + +# Copy rmscript package source +COPY rmscript/ /app/rmscript/ + +# Install rmscript package with dependencies +RUN pip install --no-cache-dir /app/rmscript[scipy] + +# Copy backend code +COPY backend/ /app/backend/ + +# Install backend dependencies +WORKDIR /app/backend +RUN pip install --no-cache-dir fastapi uvicorn[standard] pydantic + +# Copy frontend code +COPY frontend/ /app/frontend/ + +# Expose port 7860 (required by HuggingFace Spaces) +EXPOSE 7860 + +# Run the FastAPI server +CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"] diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1b75ad2728a03cf19942c0f80d9e2bfe847f0641 --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +--- +title: RMScript Web Demo +emoji: 🤖 +colorFrom: purple +colorTo: blue +sdk: docker +app_port: 7860 +pinned: false +--- + +# RMScript Web Demo + +Web-based IDE for writing, verifying, and executing rmscript code on Reachy Mini. + +## Architecture + +- **Frontend** (`frontend/`): HTML/CSS/JavaScript editor with live compilation and robot control +- **Backend** (`backend/`): FastAPI server for rmscript compilation and validation +- **Robot**: Reachy Mini robot daemon running on localhost:8000 + +## Quick Start + +### On HuggingFace Spaces + +Just open the Space - the web IDE will load automatically. + +**Requirements:** +- Reachy Mini daemon running on `localhost:8000` on your local machine +- Modern web browser with WebSocket support + +### Local Development + +1. Install rmscript package: +```bash +cd rmscript +uv sync +``` + +2. Start backend server: +```bash +cd backend +uv sync +uv run python app.py +``` + +3. Make sure your Reachy Mini daemon is running on `localhost:8000` + +4. Open `frontend/index.html` in your web browser + +## Features + +- **Code Editor**: Write rmscript with syntax examples +- **Verify Button**: Check script validity without executing +- **Execute Button**: Compile and run script on connected robot +- **Live Compilation**: See IR (Intermediate Representation) of your script +- **Example Scripts**: Load pre-written examples (basic, complex, repeat) +- **Real-time Logging**: Console shows compilation errors, warnings, and execution progress + +## Usage + +1. Write rmscript in the editor (or load an example) +2. Click "Verify" to check syntax and semantics +3. Review any errors/warnings in the console +4. Click "Execute" to run on the robot (robot must be connected) +5. Watch execution progress in the Execution Info panel + +## Current Limitations + +- Sound and picture actions are not yet implemented in execution + +## Deployment to HuggingFace Spaces + +To deploy this demo to HuggingFace Spaces: + +1. **Prepare the repository structure:** + - Copy the `rmscript` and `reachy_mini` directories into the `rmscript_space_demo` directory: + ```bash + cd rmscript_space_demo + cp -r ../rmscript ./rmscript + cp -r ../reachy_mini ./reachy_mini + ``` + - Your structure should be: + ``` + rmscript_space_demo/ + ├── Dockerfile + ├── README.md + ├── .dockerignore + ├── backend/ + ├── frontend/ + ├── rmscript/ ← copied source + └── reachy_mini/ ← copied source (dependency) + ``` + +2. **Create a new Space:** + - Go to https://huggingface.co/new-space + - Select "Docker" as the SDK + - Push this directory to your Space repository + +3. **The Space will:** + - Build the Docker container + - Install rmscript and dependencies + - Serve the web IDE on port 7860 + +**Note:** The Space connects to your local robot daemon on `localhost:8000`. Make sure it's running when using the demo. + +## Development + +To modify the demo: +- Frontend code: `frontend/app.js` +- Backend API: `backend/app.py` +- Styling: `frontend/index.html` (embedded CSS) diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6b9682573f7dc7cb0c62ee473b277d0327907822 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,44 @@ +# RMScript Web Demo - Backend + +FastAPI backend for compiling and validating rmscript code. + +## Installation + +```bash +# Install dependencies with uv +uv sync +``` + +## Running + +```bash +uv run python app.py +``` + +Or with uvicorn directly: + +```bash +uv run uvicorn app:app --reload --port 8001 +``` + +The API will be available at http://localhost:8001 + +## API Endpoints + +- `GET /` - API information +- `POST /api/verify` - Verify rmscript syntax (returns errors/warnings) +- `POST /api/compile` - Compile rmscript to IR (returns IR actions) + +## Example Usage + +```bash +# Verify a script +curl -X POST http://localhost:8001/api/verify \ + -H "Content-Type: application/json" \ + -d '{"source": "look left\nwait 1s\nlook right"}' + +# Compile a script +curl -X POST http://localhost:8001/api/compile \ + -H "Content-Type: application/json" \ + -d '{"source": "look left\nwait 1s\nlook right"}' +``` diff --git a/backend/app.py b/backend/app.py new file mode 100644 index 0000000000000000000000000000000000000000..0ccb6b67f06f4a312926b9afed7a6723fcb4ecc7 --- /dev/null +++ b/backend/app.py @@ -0,0 +1,252 @@ +"""FastAPI backend for rmscript web demo.""" + +import logging +from pathlib import Path +from typing import Any, Dict, List +from fastapi import FastAPI, HTTPException +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import FileResponse +from fastapi.staticfiles import StaticFiles +from pydantic import BaseModel + +from rmscript import compile_script + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# Create FastAPI app +app = FastAPI( + title="RMScript Web Demo API", + description="Backend API for compiling and validating rmscript code", + version="1.0.0" +) + +# Enable CORS for local development +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # In production, specify exact origins + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +# Set up paths for serving frontend +BACKEND_DIR = Path(__file__).parent +FRONTEND_DIR = BACKEND_DIR.parent / "frontend" + +# Mount static files (CSS, JS) +if FRONTEND_DIR.exists(): + app.mount("/static", StaticFiles(directory=str(FRONTEND_DIR)), name="static") + + +class ScriptInput(BaseModel): + """Input model for script compilation.""" + + source: str + + +class CompilationError(BaseModel): + """Compilation error model.""" + + line: int + column: int + message: str + severity: str + + +class VerifyResponse(BaseModel): + """Response model for script verification.""" + + success: bool + errors: List[Dict[str, Any]] + warnings: List[Dict[str, Any]] + name: str = "" + description: str = "" + + +class IRActionModel(BaseModel): + """Simplified IR action model for JSON serialization.""" + + type: str # "action", "wait", "picture", "sound" + duration: float = 0.0 + # For movement actions + head_pose: List[List[float]] | None = None # 4x4 matrix as nested list + antennas: List[float] | None = None # [left, right] in radians + body_yaw: float | None = None # radians + # For sound actions + sound_name: str | None = None + blocking: bool = False + loop: bool = False + # Metadata + source_line: int = 0 + + +class CompileResponse(BaseModel): + """Response model for script compilation.""" + + success: bool + errors: List[Dict[str, Any]] + warnings: List[Dict[str, Any]] + name: str = "" + description: str = "" + ir: List[IRActionModel] + + +@app.get("/") +async def root(): + """Serve the frontend application.""" + index_path = FRONTEND_DIR / "index.html" + if index_path.exists(): + return FileResponse(index_path) + return { + "name": "RMScript Web Demo API", + "version": "1.0.0", + "endpoints": { + "/api/verify": "POST - Verify rmscript syntax and semantics", + "/api/compile": "POST - Compile rmscript to IR", + } + } + + +@app.post("/api/verify", response_model=VerifyResponse) +async def verify_script(input: ScriptInput): + """Verify rmscript without generating IR. + + Args: + input: Script source code + + Returns: + Verification result with errors and warnings + + """ + logger.info(f"Verifying script ({len(input.source)} chars)") + + try: + result = compile_script(input.source) + + # Convert errors and warnings to dict format + errors = [ + { + "line": e.line, + "column": e.column, + "message": e.message, + "severity": e.severity + } + for e in result.errors + ] + + warnings = [ + { + "line": w.line, + "column": w.column, + "message": w.message, + "severity": w.severity + } + for w in result.warnings + ] + + return VerifyResponse( + success=result.success, + errors=errors, + warnings=warnings, + name=result.name, + description=result.description + ) + + except Exception as e: + logger.error(f"Verification error: {e}") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.post("/api/compile", response_model=CompileResponse) +async def compile_rmscript(input: ScriptInput): + """Compile rmscript to intermediate representation. + + Args: + input: Script source code + + Returns: + Compilation result with IR + + """ + logger.info(f"Compiling script ({len(input.source)} chars)") + + try: + from rmscript.ir import IRAction, IRWaitAction, IRPictureAction, IRPlaySoundAction + + result = compile_script(input.source) + + # Convert errors and warnings to dict format + errors = [ + { + "line": e.line, + "column": e.column, + "message": e.message, + "severity": e.severity + } + for e in result.errors + ] + + warnings = [ + { + "line": w.line, + "column": w.column, + "message": w.message, + "severity": w.severity + } + for w in result.warnings + ] + + # Convert IR to JSON-serializable format + ir_json = [] + for action in result.ir: + if isinstance(action, IRAction): + ir_json.append(IRActionModel( + type="action", + duration=action.duration, + head_pose=action.head_pose.tolist() if action.head_pose is not None else None, + antennas=action.antennas if action.antennas is not None else None, + body_yaw=action.body_yaw, + source_line=action.source_line + )) + elif isinstance(action, IRWaitAction): + ir_json.append(IRActionModel( + type="wait", + duration=action.duration, + source_line=action.source_line + )) + elif isinstance(action, IRPictureAction): + ir_json.append(IRActionModel( + type="picture", + source_line=action.source_line + )) + elif isinstance(action, IRPlaySoundAction): + ir_json.append(IRActionModel( + type="sound", + duration=action.duration or 0.0, + sound_name=action.sound_name, + blocking=action.blocking, + loop=action.loop, + source_line=action.source_line + )) + + logger.info(f"Compiled {len(ir_json)} IR actions") + + return CompileResponse( + success=result.success, + errors=errors, + warnings=warnings, + name=result.name, + description=result.description, + ir=ir_json + ) + + except Exception as e: + logger.error(f"Compilation error: {e}") + raise HTTPException(status_code=500, detail=str(e)) + + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8001, log_level="info") diff --git a/backend/pyproject.toml b/backend/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..b16eab1eb4576455b454da1becacfdee577030f3 --- /dev/null +++ b/backend/pyproject.toml @@ -0,0 +1,14 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "rmscript-web-backend" +version = "1.0.0" +requires-python = ">=3.11" +dependencies = [ + "fastapi>=0.104.0", + "uvicorn[standard]>=0.24.0", + "pydantic>=2.4.0", + "rmscript[reachy,scipy] @ file:///Users/david/projects/reachy-mini/rmscript", +] diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..a1fe4848660d4b5de68d82aa10f3dc2ec23424a5 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,4 @@ +fastapi>=0.104.0 +uvicorn[standard]>=0.24.0 +pydantic>=2.4.0 +rmscript>=0.1.0 diff --git a/backend/uv.lock b/backend/uv.lock new file mode 100644 index 0000000000000000000000000000000000000000..dc53d317594e898beb50af2a0891468419c91fd8 --- /dev/null +++ b/backend/uv.lock @@ -0,0 +1,2108 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" +resolution-markers = [ + "python_full_version >= '3.12' and sys_platform == 'darwin'", + "python_full_version >= '3.12' and platform_machine == 'aarch64' and sys_platform == 'linux'", + "(python_full_version >= '3.12' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.12' and sys_platform == 'darwin'", + "python_full_version < '3.12' and platform_machine == 'aarch64' and sys_platform == 'linux'", + "(python_full_version < '3.12' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.12' and sys_platform != 'darwin' and sys_platform != 'linux')", +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994, upload-time = "2025-10-28T20:59:39.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/74/b321e7d7ca762638cdf8cdeceb39755d9c745aff7a64c8789be96ddf6e96/aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0", size = 743409, upload-time = "2025-10-28T20:56:00.354Z" }, + { url = "https://files.pythonhosted.org/packages/99/3d/91524b905ec473beaf35158d17f82ef5a38033e5809fe8742e3657cdbb97/aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb", size = 497006, upload-time = "2025-10-28T20:56:01.85Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d3/7f68bc02a67716fe80f063e19adbd80a642e30682ce74071269e17d2dba1/aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9", size = 493195, upload-time = "2025-10-28T20:56:03.314Z" }, + { url = "https://files.pythonhosted.org/packages/98/31/913f774a4708775433b7375c4f867d58ba58ead833af96c8af3621a0d243/aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613", size = 1747759, upload-time = "2025-10-28T20:56:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/e8/63/04efe156f4326f31c7c4a97144f82132c3bb21859b7bb84748d452ccc17c/aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead", size = 1704456, upload-time = "2025-10-28T20:56:06.986Z" }, + { url = "https://files.pythonhosted.org/packages/8e/02/4e16154d8e0a9cf4ae76f692941fd52543bbb148f02f098ca73cab9b1c1b/aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780", size = 1807572, upload-time = "2025-10-28T20:56:08.558Z" }, + { url = "https://files.pythonhosted.org/packages/34/58/b0583defb38689e7f06798f0285b1ffb3a6fb371f38363ce5fd772112724/aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a", size = 1895954, upload-time = "2025-10-28T20:56:10.545Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f3/083907ee3437425b4e376aa58b2c915eb1a33703ec0dc30040f7ae3368c6/aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592", size = 1747092, upload-time = "2025-10-28T20:56:12.118Z" }, + { url = "https://files.pythonhosted.org/packages/ac/61/98a47319b4e425cc134e05e5f3fc512bf9a04bf65aafd9fdcda5d57ec693/aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab", size = 1606815, upload-time = "2025-10-28T20:56:14.191Z" }, + { url = "https://files.pythonhosted.org/packages/97/4b/e78b854d82f66bb974189135d31fce265dee0f5344f64dd0d345158a5973/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30", size = 1723789, upload-time = "2025-10-28T20:56:16.101Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fc/9d2ccc794fc9b9acd1379d625c3a8c64a45508b5091c546dea273a41929e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40", size = 1718104, upload-time = "2025-10-28T20:56:17.655Z" }, + { url = "https://files.pythonhosted.org/packages/66/65/34564b8765ea5c7d79d23c9113135d1dd3609173da13084830f1507d56cf/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948", size = 1785584, upload-time = "2025-10-28T20:56:19.238Z" }, + { url = "https://files.pythonhosted.org/packages/30/be/f6a7a426e02fc82781afd62016417b3948e2207426d90a0e478790d1c8a4/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf", size = 1595126, upload-time = "2025-10-28T20:56:20.836Z" }, + { url = "https://files.pythonhosted.org/packages/e5/c7/8e22d5d28f94f67d2af496f14a83b3c155d915d1fe53d94b66d425ec5b42/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782", size = 1800665, upload-time = "2025-10-28T20:56:22.922Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/91133c8b68b1da9fc16555706aa7276fdf781ae2bb0876c838dd86b8116e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8", size = 1739532, upload-time = "2025-10-28T20:56:25.924Z" }, + { url = "https://files.pythonhosted.org/packages/17/6b/3747644d26a998774b21a616016620293ddefa4d63af6286f389aedac844/aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec", size = 431876, upload-time = "2025-10-28T20:56:27.524Z" }, + { url = "https://files.pythonhosted.org/packages/c3/63/688462108c1a00eb9f05765331c107f95ae86f6b197b865d29e930b7e462/aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c", size = 456205, upload-time = "2025-10-28T20:56:29.062Z" }, + { url = "https://files.pythonhosted.org/packages/29/9b/01f00e9856d0a73260e86dd8ed0c2234a466c5c1712ce1c281548df39777/aiohttp-3.13.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b1e56bab2e12b2b9ed300218c351ee2a3d8c8fdab5b1ec6193e11a817767e47b", size = 737623, upload-time = "2025-10-28T20:56:30.797Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1b/4be39c445e2b2bd0aab4ba736deb649fabf14f6757f405f0c9685019b9e9/aiohttp-3.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:364e25edaabd3d37b1db1f0cbcee8c73c9a3727bfa262b83e5e4cf3489a2a9dc", size = 492664, upload-time = "2025-10-28T20:56:32.708Z" }, + { url = "https://files.pythonhosted.org/packages/28/66/d35dcfea8050e131cdd731dff36434390479b4045a8d0b9d7111b0a968f1/aiohttp-3.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5c94825f744694c4b8db20b71dba9a257cd2ba8e010a803042123f3a25d50d7", size = 491808, upload-time = "2025-10-28T20:56:34.57Z" }, + { url = "https://files.pythonhosted.org/packages/00/29/8e4609b93e10a853b65f8291e64985de66d4f5848c5637cddc70e98f01f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba2715d842ffa787be87cbfce150d5e88c87a98e0b62e0f5aa489169a393dbbb", size = 1738863, upload-time = "2025-10-28T20:56:36.377Z" }, + { url = "https://files.pythonhosted.org/packages/9d/fa/4ebdf4adcc0def75ced1a0d2d227577cd7b1b85beb7edad85fcc87693c75/aiohttp-3.13.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:585542825c4bc662221fb257889e011a5aa00f1ae4d75d1d246a5225289183e3", size = 1700586, upload-time = "2025-10-28T20:56:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/da/04/73f5f02ff348a3558763ff6abe99c223381b0bace05cd4530a0258e52597/aiohttp-3.13.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39d02cb6025fe1aabca329c5632f48c9532a3dabccd859e7e2f110668972331f", size = 1768625, upload-time = "2025-10-28T20:56:39.75Z" }, + { url = "https://files.pythonhosted.org/packages/f8/49/a825b79ffec124317265ca7d2344a86bcffeb960743487cb11988ffb3494/aiohttp-3.13.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e67446b19e014d37342f7195f592a2a948141d15a312fe0e700c2fd2f03124f6", size = 1867281, upload-time = "2025-10-28T20:56:41.471Z" }, + { url = "https://files.pythonhosted.org/packages/b9/48/adf56e05f81eac31edcfae45c90928f4ad50ef2e3ea72cb8376162a368f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4356474ad6333e41ccefd39eae869ba15a6c5299c9c01dfdcfdd5c107be4363e", size = 1752431, upload-time = "2025-10-28T20:56:43.162Z" }, + { url = "https://files.pythonhosted.org/packages/30/ab/593855356eead019a74e862f21523db09c27f12fd24af72dbc3555b9bfd9/aiohttp-3.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeacf451c99b4525f700f078becff32c32ec327b10dcf31306a8a52d78166de7", size = 1562846, upload-time = "2025-10-28T20:56:44.85Z" }, + { url = "https://files.pythonhosted.org/packages/39/0f/9f3d32271aa8dc35036e9668e31870a9d3b9542dd6b3e2c8a30931cb27ae/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8a9b889aeabd7a4e9af0b7f4ab5ad94d42e7ff679aaec6d0db21e3b639ad58d", size = 1699606, upload-time = "2025-10-28T20:56:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3c/52d2658c5699b6ef7692a3f7128b2d2d4d9775f2a68093f74bca06cf01e1/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fa89cb11bc71a63b69568d5b8a25c3ca25b6d54c15f907ca1c130d72f320b76b", size = 1720663, upload-time = "2025-10-28T20:56:48.528Z" }, + { url = "https://files.pythonhosted.org/packages/9b/d4/8f8f3ff1fb7fb9e3f04fcad4e89d8a1cd8fc7d05de67e3de5b15b33008ff/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8aa7c807df234f693fed0ecd507192fc97692e61fee5702cdc11155d2e5cadc8", size = 1737939, upload-time = "2025-10-28T20:56:50.77Z" }, + { url = "https://files.pythonhosted.org/packages/03/d3/ddd348f8a27a634daae39a1b8e291ff19c77867af438af844bf8b7e3231b/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9eb3e33fdbe43f88c3c75fa608c25e7c47bbd80f48d012763cb67c47f39a7e16", size = 1555132, upload-time = "2025-10-28T20:56:52.568Z" }, + { url = "https://files.pythonhosted.org/packages/39/b8/46790692dc46218406f94374903ba47552f2f9f90dad554eed61bfb7b64c/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9434bc0d80076138ea986833156c5a48c9c7a8abb0c96039ddbb4afc93184169", size = 1764802, upload-time = "2025-10-28T20:56:54.292Z" }, + { url = "https://files.pythonhosted.org/packages/ba/e4/19ce547b58ab2a385e5f0b8aa3db38674785085abcf79b6e0edd1632b12f/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff15c147b2ad66da1f2cbb0622313f2242d8e6e8f9b79b5206c84523a4473248", size = 1719512, upload-time = "2025-10-28T20:56:56.428Z" }, + { url = "https://files.pythonhosted.org/packages/70/30/6355a737fed29dcb6dfdd48682d5790cb5eab050f7b4e01f49b121d3acad/aiohttp-3.13.2-cp312-cp312-win32.whl", hash = "sha256:27e569eb9d9e95dbd55c0fc3ec3a9335defbf1d8bc1d20171a49f3c4c607b93e", size = 426690, upload-time = "2025-10-28T20:56:58.736Z" }, + { url = "https://files.pythonhosted.org/packages/0a/0d/b10ac09069973d112de6ef980c1f6bb31cb7dcd0bc363acbdad58f927873/aiohttp-3.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:8709a0f05d59a71f33fd05c17fc11fcb8c30140506e13c2f5e8ee1b8964e1b45", size = 453465, upload-time = "2025-10-28T20:57:00.795Z" }, + { url = "https://files.pythonhosted.org/packages/bf/78/7e90ca79e5aa39f9694dcfd74f4720782d3c6828113bb1f3197f7e7c4a56/aiohttp-3.13.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7519bdc7dfc1940d201651b52bf5e03f5503bda45ad6eacf64dda98be5b2b6be", size = 732139, upload-time = "2025-10-28T20:57:02.455Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/1f59215ab6853fbaa5c8495fa6cbc39edfc93553426152b75d82a5f32b76/aiohttp-3.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:088912a78b4d4f547a1f19c099d5a506df17eacec3c6f4375e2831ec1d995742", size = 490082, upload-time = "2025-10-28T20:57:04.784Z" }, + { url = "https://files.pythonhosted.org/packages/68/7b/fe0fe0f5e05e13629d893c760465173a15ad0039c0a5b0d0040995c8075e/aiohttp-3.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5276807b9de9092af38ed23ce120539ab0ac955547b38563a9ba4f5b07b95293", size = 489035, upload-time = "2025-10-28T20:57:06.894Z" }, + { url = "https://files.pythonhosted.org/packages/d2/04/db5279e38471b7ac801d7d36a57d1230feeee130bbe2a74f72731b23c2b1/aiohttp-3.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1237c1375eaef0db4dcd7c2559f42e8af7b87ea7d295b118c60c36a6e61cb811", size = 1720387, upload-time = "2025-10-28T20:57:08.685Z" }, + { url = "https://files.pythonhosted.org/packages/31/07/8ea4326bd7dae2bd59828f69d7fdc6e04523caa55e4a70f4a8725a7e4ed2/aiohttp-3.13.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96581619c57419c3d7d78703d5b78c1e5e5fc0172d60f555bdebaced82ded19a", size = 1688314, upload-time = "2025-10-28T20:57:10.693Z" }, + { url = "https://files.pythonhosted.org/packages/48/ab/3d98007b5b87ffd519d065225438cc3b668b2f245572a8cb53da5dd2b1bc/aiohttp-3.13.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2713a95b47374169409d18103366de1050fe0ea73db358fc7a7acb2880422d4", size = 1756317, upload-time = "2025-10-28T20:57:12.563Z" }, + { url = "https://files.pythonhosted.org/packages/97/3d/801ca172b3d857fafb7b50c7c03f91b72b867a13abca982ed6b3081774ef/aiohttp-3.13.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:228a1cd556b3caca590e9511a89444925da87d35219a49ab5da0c36d2d943a6a", size = 1858539, upload-time = "2025-10-28T20:57:14.623Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0d/4764669bdf47bd472899b3d3db91fffbe925c8e3038ec591a2fd2ad6a14d/aiohttp-3.13.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac6cde5fba8d7d8c6ac963dbb0256a9854e9fafff52fbcc58fdf819357892c3e", size = 1739597, upload-time = "2025-10-28T20:57:16.399Z" }, + { url = "https://files.pythonhosted.org/packages/c4/52/7bd3c6693da58ba16e657eb904a5b6decfc48ecd06e9ac098591653b1566/aiohttp-3.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2bef8237544f4e42878c61cef4e2839fee6346dc60f5739f876a9c50be7fcdb", size = 1555006, upload-time = "2025-10-28T20:57:18.288Z" }, + { url = "https://files.pythonhosted.org/packages/48/30/9586667acec5993b6f41d2ebcf96e97a1255a85f62f3c653110a5de4d346/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:16f15a4eac3bc2d76c45f7ebdd48a65d41b242eb6c31c2245463b40b34584ded", size = 1683220, upload-time = "2025-10-28T20:57:20.241Z" }, + { url = "https://files.pythonhosted.org/packages/71/01/3afe4c96854cfd7b30d78333852e8e851dceaec1c40fd00fec90c6402dd2/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bb7fb776645af5cc58ab804c58d7eba545a97e047254a52ce89c157b5af6cd0b", size = 1712570, upload-time = "2025-10-28T20:57:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/11/2c/22799d8e720f4697a9e66fd9c02479e40a49de3de2f0bbe7f9f78a987808/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1b4951125ec10c70802f2cb09736c895861cd39fd9dcb35107b4dc8ae6220b8", size = 1733407, upload-time = "2025-10-28T20:57:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/34/cb/90f15dd029f07cebbd91f8238a8b363978b530cd128488085b5703683594/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:550bf765101ae721ee1d37d8095f47b1f220650f85fe1af37a90ce75bab89d04", size = 1550093, upload-time = "2025-10-28T20:57:26.257Z" }, + { url = "https://files.pythonhosted.org/packages/69/46/12dce9be9d3303ecbf4d30ad45a7683dc63d90733c2d9fe512be6716cd40/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fe91b87fc295973096251e2d25a811388e7d8adf3bd2b97ef6ae78bc4ac6c476", size = 1758084, upload-time = "2025-10-28T20:57:28.349Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c8/0932b558da0c302ffd639fc6362a313b98fdf235dc417bc2493da8394df7/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0c8e31cfcc4592cb200160344b2fb6ae0f9e4effe06c644b5a125d4ae5ebe23", size = 1716987, upload-time = "2025-10-28T20:57:30.233Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8b/f5bd1a75003daed099baec373aed678f2e9b34f2ad40d85baa1368556396/aiohttp-3.13.2-cp313-cp313-win32.whl", hash = "sha256:0740f31a60848d6edb296a0df827473eede90c689b8f9f2a4cdde74889eb2254", size = 425859, upload-time = "2025-10-28T20:57:32.105Z" }, + { url = "https://files.pythonhosted.org/packages/5d/28/a8a9fc6957b2cee8902414e41816b5ab5536ecf43c3b1843c10e82c559b2/aiohttp-3.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:a88d13e7ca367394908f8a276b89d04a3652044612b9a408a0bb22a5ed976a1a", size = 452192, upload-time = "2025-10-28T20:57:34.166Z" }, + { url = "https://files.pythonhosted.org/packages/9b/36/e2abae1bd815f01c957cbf7be817b3043304e1c87bad526292a0410fdcf9/aiohttp-3.13.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2475391c29230e063ef53a66669b7b691c9bfc3f1426a0f7bcdf1216bdbac38b", size = 735234, upload-time = "2025-10-28T20:57:36.415Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e3/1ee62dde9b335e4ed41db6bba02613295a0d5b41f74a783c142745a12763/aiohttp-3.13.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f33c8748abef4d8717bb20e8fb1b3e07c6adacb7fd6beaae971a764cf5f30d61", size = 490733, upload-time = "2025-10-28T20:57:38.205Z" }, + { url = "https://files.pythonhosted.org/packages/1a/aa/7a451b1d6a04e8d15a362af3e9b897de71d86feac3babf8894545d08d537/aiohttp-3.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ae32f24bbfb7dbb485a24b30b1149e2f200be94777232aeadba3eecece4d0aa4", size = 491303, upload-time = "2025-10-28T20:57:40.122Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/209958dbb9b01174870f6a7538cd1f3f28274fdbc88a750c238e2c456295/aiohttp-3.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7f02042c1f009ffb70067326ef183a047425bb2ff3bc434ead4dd4a4a66a2b", size = 1717965, upload-time = "2025-10-28T20:57:42.28Z" }, + { url = "https://files.pythonhosted.org/packages/08/aa/6a01848d6432f241416bc4866cae8dc03f05a5a884d2311280f6a09c73d6/aiohttp-3.13.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93655083005d71cd6c072cdab54c886e6570ad2c4592139c3fb967bfc19e4694", size = 1667221, upload-time = "2025-10-28T20:57:44.869Z" }, + { url = "https://files.pythonhosted.org/packages/87/4f/36c1992432d31bbc789fa0b93c768d2e9047ec8c7177e5cd84ea85155f36/aiohttp-3.13.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0db1e24b852f5f664cd728db140cf11ea0e82450471232a394b3d1a540b0f906", size = 1757178, upload-time = "2025-10-28T20:57:47.216Z" }, + { url = "https://files.pythonhosted.org/packages/ac/b4/8e940dfb03b7e0f68a82b88fd182b9be0a65cb3f35612fe38c038c3112cf/aiohttp-3.13.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b009194665bcd128e23eaddef362e745601afa4641930848af4c8559e88f18f9", size = 1838001, upload-time = "2025-10-28T20:57:49.337Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ef/39f3448795499c440ab66084a9db7d20ca7662e94305f175a80f5b7e0072/aiohttp-3.13.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c038a8fdc8103cd51dbd986ecdce141473ffd9775a7a8057a6ed9c3653478011", size = 1716325, upload-time = "2025-10-28T20:57:51.327Z" }, + { url = "https://files.pythonhosted.org/packages/d7/51/b311500ffc860b181c05d91c59a1313bdd05c82960fdd4035a15740d431e/aiohttp-3.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66bac29b95a00db411cd758fea0e4b9bdba6d549dfe333f9a945430f5f2cc5a6", size = 1547978, upload-time = "2025-10-28T20:57:53.554Z" }, + { url = "https://files.pythonhosted.org/packages/31/64/b9d733296ef79815226dab8c586ff9e3df41c6aff2e16c06697b2d2e6775/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4ebf9cfc9ba24a74cf0718f04aac2a3bbe745902cc7c5ebc55c0f3b5777ef213", size = 1682042, upload-time = "2025-10-28T20:57:55.617Z" }, + { url = "https://files.pythonhosted.org/packages/3f/30/43d3e0f9d6473a6db7d472104c4eff4417b1e9df01774cb930338806d36b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a4b88ebe35ce54205c7074f7302bd08a4cb83256a3e0870c72d6f68a3aaf8e49", size = 1680085, upload-time = "2025-10-28T20:57:57.59Z" }, + { url = "https://files.pythonhosted.org/packages/16/51/c709f352c911b1864cfd1087577760ced64b3e5bee2aa88b8c0c8e2e4972/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98c4fb90bb82b70a4ed79ca35f656f4281885be076f3f970ce315402b53099ae", size = 1728238, upload-time = "2025-10-28T20:57:59.525Z" }, + { url = "https://files.pythonhosted.org/packages/19/e2/19bd4c547092b773caeb48ff5ae4b1ae86756a0ee76c16727fcfd281404b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:ec7534e63ae0f3759df3a1ed4fa6bc8f75082a924b590619c0dd2f76d7043caa", size = 1544395, upload-time = "2025-10-28T20:58:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/cf/87/860f2803b27dfc5ed7be532832a3498e4919da61299b4a1f8eb89b8ff44d/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5b927cf9b935a13e33644cbed6c8c4b2d0f25b713d838743f8fe7191b33829c4", size = 1742965, upload-time = "2025-10-28T20:58:03.972Z" }, + { url = "https://files.pythonhosted.org/packages/67/7f/db2fc7618925e8c7a601094d5cbe539f732df4fb570740be88ed9e40e99a/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:88d6c017966a78c5265d996c19cdb79235be5e6412268d7e2ce7dee339471b7a", size = 1697585, upload-time = "2025-10-28T20:58:06.189Z" }, + { url = "https://files.pythonhosted.org/packages/0c/07/9127916cb09bb38284db5036036042b7b2c514c8ebaeee79da550c43a6d6/aiohttp-3.13.2-cp314-cp314-win32.whl", hash = "sha256:f7c183e786e299b5d6c49fb43a769f8eb8e04a2726a2bd5887b98b5cc2d67940", size = 431621, upload-time = "2025-10-28T20:58:08.636Z" }, + { url = "https://files.pythonhosted.org/packages/fb/41/554a8a380df6d3a2bba8a7726429a23f4ac62aaf38de43bb6d6cde7b4d4d/aiohttp-3.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:fe242cd381e0fb65758faf5ad96c2e460df6ee5b2de1072fe97e4127927e00b4", size = 457627, upload-time = "2025-10-28T20:58:11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8e/3824ef98c039d3951cb65b9205a96dd2b20f22241ee17d89c5701557c826/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f10d9c0b0188fe85398c61147bbd2a657d616c876863bfeff43376e0e3134673", size = 767360, upload-time = "2025-10-28T20:58:13.358Z" }, + { url = "https://files.pythonhosted.org/packages/a4/0f/6a03e3fc7595421274fa34122c973bde2d89344f8a881b728fa8c774e4f1/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e7c952aefdf2460f4ae55c5e9c3e80aa72f706a6317e06020f80e96253b1accd", size = 504616, upload-time = "2025-10-28T20:58:15.339Z" }, + { url = "https://files.pythonhosted.org/packages/c6/aa/ed341b670f1bc8a6f2c6a718353d13b9546e2cef3544f573c6a1ff0da711/aiohttp-3.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c20423ce14771d98353d2e25e83591fa75dfa90a3c1848f3d7c68243b4fbded3", size = 509131, upload-time = "2025-10-28T20:58:17.693Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f0/c68dac234189dae5c4bbccc0f96ce0cc16b76632cfc3a08fff180045cfa4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e96eb1a34396e9430c19d8338d2ec33015e4a87ef2b4449db94c22412e25ccdf", size = 1864168, upload-time = "2025-10-28T20:58:20.113Z" }, + { url = "https://files.pythonhosted.org/packages/8f/65/75a9a76db8364b5d0e52a0c20eabc5d52297385d9af9c35335b924fafdee/aiohttp-3.13.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:23fb0783bc1a33640036465019d3bba069942616a6a2353c6907d7fe1ccdaf4e", size = 1719200, upload-time = "2025-10-28T20:58:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/8df2ed78d7f41d232f6bd3ff866b6f617026551aa1d07e2f03458f964575/aiohttp-3.13.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1a9bea6244a1d05a4e57c295d69e159a5c50d8ef16aa390948ee873478d9a5", size = 1843497, upload-time = "2025-10-28T20:58:24.672Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e0/94d7215e405c5a02ccb6a35c7a3a6cfff242f457a00196496935f700cde5/aiohttp-3.13.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a3d54e822688b56e9f6b5816fb3de3a3a64660efac64e4c2dc435230ad23bad", size = 1935703, upload-time = "2025-10-28T20:58:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/0b/78/1eeb63c3f9b2d1015a4c02788fb543141aad0a03ae3f7a7b669b2483f8d4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a653d872afe9f33497215745da7a943d1dc15b728a9c8da1c3ac423af35178e", size = 1792738, upload-time = "2025-10-28T20:58:29.787Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/aaf1eea4c188e51538c04cc568040e3082db263a57086ea74a7d38c39e42/aiohttp-3.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:56d36e80d2003fa3fc0207fac644216d8532e9504a785ef9a8fd013f84a42c61", size = 1624061, upload-time = "2025-10-28T20:58:32.529Z" }, + { url = "https://files.pythonhosted.org/packages/9b/c2/3b6034de81fbcc43de8aeb209073a2286dfb50b86e927b4efd81cf848197/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78cd586d8331fb8e241c2dd6b2f4061778cc69e150514b39a9e28dd050475661", size = 1789201, upload-time = "2025-10-28T20:58:34.618Z" }, + { url = "https://files.pythonhosted.org/packages/c9/38/c15dcf6d4d890217dae79d7213988f4e5fe6183d43893a9cf2fe9e84ca8d/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:20b10bbfbff766294fe99987f7bb3b74fdd2f1a2905f2562132641ad434dcf98", size = 1776868, upload-time = "2025-10-28T20:58:38.835Z" }, + { url = "https://files.pythonhosted.org/packages/04/75/f74fd178ac81adf4f283a74847807ade5150e48feda6aef024403716c30c/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9ec49dff7e2b3c85cdeaa412e9d438f0ecd71676fde61ec57027dd392f00c693", size = 1790660, upload-time = "2025-10-28T20:58:41.507Z" }, + { url = "https://files.pythonhosted.org/packages/e7/80/7368bd0d06b16b3aba358c16b919e9c46cf11587dc572091031b0e9e3ef0/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:94f05348c4406450f9d73d38efb41d669ad6cd90c7ee194810d0eefbfa875a7a", size = 1617548, upload-time = "2025-10-28T20:58:43.674Z" }, + { url = "https://files.pythonhosted.org/packages/7d/4b/a6212790c50483cb3212e507378fbe26b5086d73941e1ec4b56a30439688/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:fa4dcb605c6f82a80c7f95713c2b11c3b8e9893b3ebd2bc9bde93165ed6107be", size = 1817240, upload-time = "2025-10-28T20:58:45.787Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f7/ba5f0ba4ea8d8f3c32850912944532b933acbf0f3a75546b89269b9b7dde/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf00e5db968c3f67eccd2778574cf64d8b27d95b237770aa32400bd7a1ca4f6c", size = 1762334, upload-time = "2025-10-28T20:58:47.936Z" }, + { url = "https://files.pythonhosted.org/packages/7e/83/1a5a1856574588b1cad63609ea9ad75b32a8353ac995d830bf5da9357364/aiohttp-3.13.2-cp314-cp314t-win32.whl", hash = "sha256:d23b5fe492b0805a50d3371e8a728a9134d8de5447dce4c885f5587294750734", size = 464685, upload-time = "2025-10-28T20:58:50.642Z" }, + { url = "https://files.pythonhosted.org/packages/9f/4d/d22668674122c08f4d56972297c51a624e64b3ed1efaa40187607a7cb66e/aiohttp-3.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:ff0a7b0a82a7ab905cbda74006318d1b12e37c797eb1b0d4eb3e316cf47f658f", size = 498093, upload-time = "2025-10-28T20:58:52.782Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +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 = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, +] + +[[package]] +name = "asgiref" +version = "3.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/b9/4db2509eabd14b4a8c71d1b24c8d5734c52b8560a7b1e1a8b56c8d25568b/asgiref-3.11.0.tar.gz", hash = "sha256:13acff32519542a1736223fb79a715acdebe24286d98e8b164a73085f40da2c4", size = 37969, upload-time = "2025-11-19T15:32:20.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/be/317c2c55b8bbec407257d45f5c8d1b6867abc76d12043f2d3d58c538a4ea/asgiref-3.11.0-py3-none-any.whl", hash = "sha256:1db9021efadb0d9512ce8ffaf72fcef601c7b73a8807a1bb2ef143dc6b14846d", size = 24096, upload-time = "2025-11-19T15:32:19.004Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cv2-enumerate-cameras" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/cf/a6eb5fa54d7dfc87c93a6161aef57527c6ef4d8239be7cef10d13fb9efd6/cv2_enumerate_cameras-1.3.0.tar.gz", hash = "sha256:795d8005b0e92ca117e1b8c4849c752edb39b7e2a1818b2d7ac4463aa26caac1", size = 12455, upload-time = "2025-09-12T04:42:33.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/38/cc570b8579a2be52d0a3f6dba7afad536bc6d41cfc44108727ef7d8b185a/cv2_enumerate_cameras-1.3.0-cp32-abi3-win32.whl", hash = "sha256:bd24be3c2df42b88da59e9f6029b97484fc8468678a2be3900aa717835c40f6a", size = 20406, upload-time = "2025-09-12T04:42:28.463Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ef/0a6e095462e90d12358ef68653c7ea4d86dd6f5dd8f433279ecb5745e9ca/cv2_enumerate_cameras-1.3.0-cp32-abi3-win_amd64.whl", hash = "sha256:ef892cc7d92dec3ad0f696fa592a9d5461e593698048f84e877353cffcfc486f", size = 21296, upload-time = "2025-09-12T04:42:30.87Z" }, + { url = "https://files.pythonhosted.org/packages/7e/d5/6a6b74c92b6901d7077eb67284010354d90762702ed3451ea5d6297ef692/cv2_enumerate_cameras-1.3.0-py3-none-any.whl", hash = "sha256:7a67d8cc98fd112c3df51ff699c6953884e96088ced2ee05191bdeaaa2e1e847", size = 11571, upload-time = "2025-09-12T04:42:32.272Z" }, +] + +[[package]] +name = "eclipse-zenoh" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/3b/15bb190da421536b28de45438ad328925f203b5b274c5e92a7dcc6f7ac14/eclipse_zenoh-1.6.2.tar.gz", hash = "sha256:852b649a9d1c482edb690759311d5322fa10e5388ba6dec507d35151b48ceb35", size = 132916, upload-time = "2025-10-17T20:11:01.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/13/0e6511e1f007686084beff96d960407edc8303a0aac267689087e1be3e11/eclipse_zenoh-1.6.2-cp39-abi3-linux_armv6l.whl", hash = "sha256:b311c5e4626cc2faad367ef0edbb09079dafefc004531f135cafd22af48f362e", size = 9454073, upload-time = "2025-10-17T20:10:46.806Z" }, + { url = "https://files.pythonhosted.org/packages/1b/84/f36e224fb7eb05927e55ea7cd2ee000f7a9254d194f7ab539627a1635dd3/eclipse_zenoh-1.6.2-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:13d0b10c09fbd4233356a38b11cf008112acefda308a4dd4feb3c8e74c674065", size = 17565641, upload-time = "2025-10-17T20:10:49.061Z" }, + { url = "https://files.pythonhosted.org/packages/e0/7d/98194e5f4f369eb7f49024d7d4536342636bee216f191cbb111c7ee86764/eclipse_zenoh-1.6.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:29f081cf6ba5eee7c72606cab1e534e6e6a825c08899529c176d7a6fa1cff6c4", size = 8984387, upload-time = "2025-10-17T20:10:50.736Z" }, + { url = "https://files.pythonhosted.org/packages/04/17/0b550ec08095471bd099258ea23685f569dba79394fa22dd25c232d75cae/eclipse_zenoh-1.6.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c1c332334ec4bceb0856472146684cfb4230e55c0409cba6b369e34c87a5f5cb", size = 9337753, upload-time = "2025-10-17T20:10:52.696Z" }, + { url = "https://files.pythonhosted.org/packages/9c/bc/9c2196cc742ad0ccdcc9e942bea3d627f70e5a17708ab412e05bbca07180/eclipse_zenoh-1.6.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10cf678ed2578b954cf8d1863c897c9d4404d9bac1c9560dfdb9a300bb488e01", size = 10147324, upload-time = "2025-10-17T20:10:55.234Z" }, + { url = "https://files.pythonhosted.org/packages/dd/81/7ac634430be1fd15aea65d6e849f7d73d0a8cf285dd74e8e39cd7b7ea2e2/eclipse_zenoh-1.6.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5db633632e3da9c63ae70e219f2a84dca3dcb08125fb9aef9f11602104790afb", size = 9626850, upload-time = "2025-10-17T20:10:56.785Z" }, + { url = "https://files.pythonhosted.org/packages/29/fe/c5b2e65e0c2800b4e1a02b388e0ddf7c3b71f478757bb6a294c021d49e84/eclipse_zenoh-1.6.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e7f9bf3849567631caa3bdeecf2edce66461b1ae511f28dfafea6089022d02e1", size = 9487136, upload-time = "2025-10-17T20:10:58.359Z" }, + { url = "https://files.pythonhosted.org/packages/77/93/4df169108c4313d0f476bb9abd7d76496059e8bfcc3a98168aa26cc73b00/eclipse_zenoh-1.6.2-cp39-abi3-win_amd64.whl", hash = "sha256:f59f75f0d733daf5059843037e63bb62dd5268809d041a150bcfd8f8d62b9b08", size = 7805746, upload-time = "2025-10-17T20:11:00.257Z" }, +] + +[[package]] +name = "fastapi" +version = "0.122.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/de/3ee97a4f6ffef1fb70bf20561e4f88531633bb5045dc6cebc0f8471f764d/fastapi-0.122.0.tar.gz", hash = "sha256:cd9b5352031f93773228af8b4c443eedc2ac2aa74b27780387b853c3726fb94b", size = 346436, upload-time = "2025-11-24T19:17:47.95Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/93/aa8072af4ff37b795f6bbf43dcaf61115f40f49935c7dbb180c9afc3f421/fastapi-0.122.0-py3-none-any.whl", hash = "sha256:a456e8915dfc6c8914a50d9651133bd47ec96d331c5b44600baa635538a30d67", size = 110671, upload-time = "2025-11-24T19:17:45.96Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, +] + +[[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/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, + { 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 = "2025.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, +] + +[[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 = "hf-xet" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload-time = "2025-10-24T19:04:11.422Z" }, + { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload-time = "2025-10-24T19:04:09.586Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload-time = "2025-10-24T19:04:00.314Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload-time = "2025-10-24T19:03:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload-time = "2025-10-24T19:04:20.951Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload-time = "2025-10-24T19:04:22.549Z" }, + { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload-time = "2025-10-24T19:04:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" }, + { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" }, + { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, +] + +[[package]] +name = "httptools" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/08/17e07e8d89ab8f343c134616d72eebfe03798835058e2ab579dcc8353c06/httptools-0.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:474d3b7ab469fefcca3697a10d11a32ee2b9573250206ba1e50d5980910da657", size = 206521, upload-time = "2025-10-10T03:54:31.002Z" }, + { url = "https://files.pythonhosted.org/packages/aa/06/c9c1b41ff52f16aee526fd10fbda99fa4787938aa776858ddc4a1ea825ec/httptools-0.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3c3b7366bb6c7b96bd72d0dbe7f7d5eead261361f013be5f6d9590465ea1c70", size = 110375, upload-time = "2025-10-10T03:54:31.941Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cc/10935db22fda0ee34c76f047590ca0a8bd9de531406a3ccb10a90e12ea21/httptools-0.7.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:379b479408b8747f47f3b253326183d7c009a3936518cdb70db58cffd369d9df", size = 456621, upload-time = "2025-10-10T03:54:33.176Z" }, + { url = "https://files.pythonhosted.org/packages/0e/84/875382b10d271b0c11aa5d414b44f92f8dd53e9b658aec338a79164fa548/httptools-0.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cad6b591a682dcc6cf1397c3900527f9affef1e55a06c4547264796bbd17cf5e", size = 454954, upload-time = "2025-10-10T03:54:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/30/e1/44f89b280f7e46c0b1b2ccee5737d46b3bb13136383958f20b580a821ca0/httptools-0.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eb844698d11433d2139bbeeb56499102143beb582bd6c194e3ba69c22f25c274", size = 440175, upload-time = "2025-10-10T03:54:35.942Z" }, + { url = "https://files.pythonhosted.org/packages/6f/7e/b9287763159e700e335028bc1824359dc736fa9b829dacedace91a39b37e/httptools-0.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f65744d7a8bdb4bda5e1fa23e4ba16832860606fcc09d674d56e425e991539ec", size = 440310, upload-time = "2025-10-10T03:54:37.1Z" }, + { url = "https://files.pythonhosted.org/packages/b3/07/5b614f592868e07f5c94b1f301b5e14a21df4e8076215a3bccb830a687d8/httptools-0.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:135fbe974b3718eada677229312e97f3b31f8a9c8ffa3ae6f565bf808d5b6bcb", size = 86875, upload-time = "2025-10-10T03:54:38.421Z" }, + { url = "https://files.pythonhosted.org/packages/53/7f/403e5d787dc4942316e515e949b0c8a013d84078a915910e9f391ba9b3ed/httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5", size = 206280, upload-time = "2025-10-10T03:54:39.274Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0d/7f3fd28e2ce311ccc998c388dd1c53b18120fda3b70ebb022b135dc9839b/httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5", size = 110004, upload-time = "2025-10-10T03:54:40.403Z" }, + { url = "https://files.pythonhosted.org/packages/84/a6/b3965e1e146ef5762870bbe76117876ceba51a201e18cc31f5703e454596/httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03", size = 517655, upload-time = "2025-10-10T03:54:41.347Z" }, + { url = "https://files.pythonhosted.org/packages/11/7d/71fee6f1844e6fa378f2eddde6c3e41ce3a1fb4b2d81118dd544e3441ec0/httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2", size = 511440, upload-time = "2025-10-10T03:54:42.452Z" }, + { url = "https://files.pythonhosted.org/packages/22/a5/079d216712a4f3ffa24af4a0381b108aa9c45b7a5cc6eb141f81726b1823/httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362", size = 495186, upload-time = "2025-10-10T03:54:43.937Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/025ad7b65278745dee3bd0ebf9314934c4592560878308a6121f7f812084/httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c", size = 499192, upload-time = "2025-10-10T03:54:45.003Z" }, + { url = "https://files.pythonhosted.org/packages/6d/de/40a8f202b987d43afc4d54689600ff03ce65680ede2f31df348d7f368b8f/httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321", size = 86694, upload-time = "2025-10-10T03:54:45.923Z" }, + { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" }, + { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" }, + { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" }, + { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" }, + { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" }, + { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" }, + { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" }, + { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" }, + { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4a/a548bdfae6369c0d078bab5769f7b66f17f1bfaa6fa28f81d6be6959066b/httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b", size = 470831, upload-time = "2025-10-10T03:54:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" }, + { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" }, + { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.34.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/c9/bdbe19339f76d12985bc03572f330a01a93c04dffecaaea3061bdd7fb892/huggingface_hub-0.34.4.tar.gz", hash = "sha256:a4228daa6fb001be3f4f4bdaf9a0db00e1739235702848df00885c9b5742c85c", size = 459768, upload-time = "2025-08-08T09:14:52.365Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl", hash = "sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a", size = 561452, upload-time = "2025-08-08T09:14:50.159Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, +] + +[[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 = "libusb-package" +version = "1.0.26.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-resources" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/bf/3fe9d322e2dcd0437ae2bd6a039117965702ed473ca59d2d6a1c39838009/libusb_package-1.0.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:60e15d7d3e4aab31794da95641bc28c4ffec9e24f50891ce33f75794b8f531f3", size = 63864, upload-time = "2025-04-01T12:59:14.567Z" }, + { url = "https://files.pythonhosted.org/packages/bc/70/df0348c11e6aaead4a66cc59840e102ddf64baf8e4b2c1ad5cff1ca83554/libusb_package-1.0.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d93a6137609cf72dc5db69bc337ddf96520231e395beeff69fa77a923090003", size = 59502, upload-time = "2025-04-01T12:59:15.863Z" }, + { url = "https://files.pythonhosted.org/packages/27/67/6c84eebc9fcdf7f26704b5d32b51b3ee5bf4e9090d61286941257bdc8702/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fafb69c5fd42b241fbd20493d014328c507d34e1b7ceb883a20ef14565b26898", size = 70247, upload-time = "2025-04-01T14:53:07.606Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/cbcc42ca4b3d8778bf081b96e6e6288a437d82a4cc4e9b982bef40a88856/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c206cd8a30565a0cede3ba426929e70a37e7b769e41a5ac7f00ca6737dc5d", size = 74537, upload-time = "2025-04-01T14:53:08.61Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0f/fd203fb1fa5eda1d446f345d84205f23533767e6ef837a7c77a2599d5783/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a2041331c087d5887969405837f86c8422120fe9ba3e6faa44bf4810f07b71", size = 70653, upload-time = "2025-04-01T14:53:09.576Z" }, + { url = "https://files.pythonhosted.org/packages/79/ef/dcc682cb4b29c4d4cdb23df65825c6276753184f6a7b4338c54a59a54c20/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:48b536a1279ee0dbf70b898cffd16cd661774d2c8bbec8ff7178a5bc20196af3", size = 71859, upload-time = "2025-04-01T14:53:10.987Z" }, + { url = "https://files.pythonhosted.org/packages/62/4d/323d5ac4ba339362e4b148c291fbc6e7ee04c6395d5fec967b32432db5c5/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3f273e33ff1810242f81ea3a0286e25887d99d99019ba83e08be0d1ca456cc05", size = 76476, upload-time = "2025-04-01T14:53:12.019Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3b/506db7f6cbe5dc2f38c14b272b8faf4d43e5559ac99d4dce1a41026ec925/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:67476093601e1ea58a6130426795b906acd8d18d51c84e29a3a69548a5dfcf5d", size = 71037, upload-time = "2025-04-01T14:53:13.42Z" }, + { url = "https://files.pythonhosted.org/packages/3e/40/2538763c06e07bbbe0a5c8830779ef1ed1cea845264a91973bf31b9ecce5/libusb_package-1.0.26.3-cp311-cp311-win32.whl", hash = "sha256:8f3eed2852ee4f08847a221749a98d0f4f3962f8bed967e2253327db1171ba60", size = 77642, upload-time = "2025-04-01T12:58:03.106Z" }, + { url = "https://files.pythonhosted.org/packages/a4/46/0cd5ea91c5bbe6293c0936c96915051e31750f72e9556718af666af3fe45/libusb_package-1.0.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:b48b5f5b17c7ac5e315e233f9ee801f730aac6183eb53a3226b01245d7bcfe00", size = 90592, upload-time = "2025-04-01T12:58:04.103Z" }, + { url = "https://files.pythonhosted.org/packages/2e/f6/83e13936b5799360eae8f0e31b5b298dd092451b91136d7cd13852777954/libusb_package-1.0.26.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c9404298485762a4e73b416e8a3208d33aa3274fb9b870c2a1cacba7e2918f19", size = 62045, upload-time = "2025-04-01T12:59:16.817Z" }, + { url = "https://files.pythonhosted.org/packages/33/97/86ed73880b6734c9383be5f34061b541e8fe5bd0303580b1f5abe2962d58/libusb_package-1.0.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8126f6711318dad4cb2805ea20cd47b895a847207087d8fdb032e082dd7a2e24", size = 59502, upload-time = "2025-04-01T12:59:17.72Z" }, + { url = "https://files.pythonhosted.org/packages/95/f7/27b67b8fe63450abf0b0b66aacf75d5d64cdf30317e214409ceb534f34b4/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11c219366e4a2368117b9a9807261f3506b5623531f8b8ce41af5bbaec8156a0", size = 70247, upload-time = "2025-04-01T14:53:14.387Z" }, + { url = "https://files.pythonhosted.org/packages/8c/11/613543f9c6dab5a82eefd0c78d52d08b5d9eb93a0362151fbedf74b32541/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8809a50d8ab84297344c54e862027090c0d73b14abef843a8b5f783313f49457", size = 74537, upload-time = "2025-04-01T14:53:15.345Z" }, + { url = "https://files.pythonhosted.org/packages/f0/43/5a2331615693b56221a902869fb2094d9a0b9a764a8706c8ba16e915f77c/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a83067c3dfdbb3856badb4532eaea22e8502b52ce4245f5ab46acf93d7fbd471", size = 70652, upload-time = "2025-04-01T14:53:16.319Z" }, + { url = "https://files.pythonhosted.org/packages/44/1a/186d4ec86421b69feb45e214edb5301fbcb9e8dc9df963678aeff1a447d5/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b56be087ea9cde8e50fb02740a4f0cefb6f63c61ac2e7812a9244487614a3973", size = 71860, upload-time = "2025-04-01T14:53:17.87Z" }, + { url = "https://files.pythonhosted.org/packages/4b/3c/8cebdad822d7bfcb683a77d5fd113fbc6f72516cfb7c1c3a274fefafa8e9/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea0f6bf40e54b1671e763e40c9dbed46bf7f596a4cd98b7c827e147f176d8c97", size = 76476, upload-time = "2025-04-01T14:53:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/49/5f/30c625b6c4ecd14871644c1d16e97d7c971f82a0f87a9cfa81022f85bcfc/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b40f77df991c6db8621de9575504886eca03a00277e521a4d64b66cbef8f6997", size = 71037, upload-time = "2025-04-01T14:53:21.359Z" }, + { url = "https://files.pythonhosted.org/packages/7f/e9/3aa3ff3242867b7f22ee3ce28d0e93ff88547f170ca1b8a6edc59660d974/libusb_package-1.0.26.3-cp312-cp312-win32.whl", hash = "sha256:6eee99c9fde137443869c8604d0c01b2127a9545ebc59d06a3376cf1d891e786", size = 77642, upload-time = "2025-04-01T12:58:05.471Z" }, + { url = "https://files.pythonhosted.org/packages/15/0e/913ddb1849f828fc385438874c34541939d9b06c0e5616f48f24cddd24de/libusb_package-1.0.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:5e09c0b6b3cd475841cffe78e46e91df58f0c6c02ea105ea1a4d0755a07c8006", size = 90593, upload-time = "2025-04-01T12:58:06.798Z" }, + { url = "https://files.pythonhosted.org/packages/b4/b8/23bc7f3f53b4a5b1027c721ec3eb42324ca1ec56355f0d0851307adc7c6c/libusb_package-1.0.26.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:04c4505e2ca68d3dc6938f116ff9bf82daffb06c1a97aba08293a84715a998da", size = 62045, upload-time = "2025-04-01T12:59:18.698Z" }, + { url = "https://files.pythonhosted.org/packages/a2/f8/e3be96d0604070488ddc5ce5af1976992e1f4a00e6441c94edf807f274d5/libusb_package-1.0.26.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4961cdb3c622aa9f858d3e4f99a58ce5e822a97c22abc77040fd806cb5fa4c66", size = 59502, upload-time = "2025-04-01T12:59:19.632Z" }, + { url = "https://files.pythonhosted.org/packages/24/d5/df1508df5e6776ac8a09a2858991df29bc96ea6a0d1f90240b1c4d59b45d/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16182670e0c23235521b447054c5a01600bd8f1eed3bb08eedbb0d9f8a43249f", size = 70247, upload-time = "2025-04-01T14:53:22.328Z" }, + { url = "https://files.pythonhosted.org/packages/65/01/4cc9eed12b9214c088cfa8055ece3b1db970404400be9d7e3dda68d198f2/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75ea57b2cc903d28ec1d4b909902df442cbf21949d80d5b3d8b9dac36ac45d1a", size = 74537, upload-time = "2025-04-01T14:53:23.306Z" }, + { url = "https://files.pythonhosted.org/packages/99/83/9eb317f706f588f4b6679bddb8abee3b115ce53dc3fa560cca59910f8807/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d30b51b128ef5112fff73268b4696fea00b5676b3f39a5ee859bd76cb3ace5", size = 70651, upload-time = "2025-04-01T14:53:24.33Z" }, + { url = "https://files.pythonhosted.org/packages/22/49/85d3b307b4a20cf0150ab381e6e0385e5b78cb5dede8bade0a2d655d3fd3/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5c098dcfcfa8000cab42f33e19628c8fdb16111670db381048b2993651f2413b", size = 71860, upload-time = "2025-04-01T14:53:25.752Z" }, + { url = "https://files.pythonhosted.org/packages/da/7a/2271a5ae542d9036d9254415ae745d5c5d01a08d56d13054b2439bf9d392/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:93169aeab0657255fe6c9f757cf408f559db13827a1d122fc89239994d7d51f1", size = 76477, upload-time = "2025-04-01T14:53:27.564Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9d/d06d53994bb164564ec142ef631a4afa31e324994cf223f169ecca127f3a/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:63257653ee1ee06aa836e942f4bb89a1d7a0c6ae3d6183647a9011e585ffa1e3", size = 71036, upload-time = "2025-04-01T14:53:29.011Z" }, + { url = "https://files.pythonhosted.org/packages/32/3d/97f775a1d582548b1eb2a42444c58813e5fd93d568fc3b9ace59f64df527/libusb_package-1.0.26.3-cp313-cp313-win32.whl", hash = "sha256:05db4cc801db2e6373a808725748a701509f9450fecf393fbebab61c45d50b50", size = 77642, upload-time = "2025-04-01T12:58:07.774Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c4/d5234607697ca60593fbef88428a154317ac31f5c58ee23337b8a9360e91/libusb_package-1.0.26.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cd4aec825dac2b4fa5d23b37f6d72e63a1127987e5a073dabeb7b73528623a3", size = 90593, upload-time = "2025-04-01T12:58:08.676Z" }, +] + +[[package]] +name = "log-throttling" +version = "0.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/be/09fda383d82a7b91f12ff5002bc909e101769c802ff3b1d2cb9f533d1a2f/log-throttling-0.0.3.tar.gz", hash = "sha256:df714e1448cd9cb4c916cf668ab88323032e61ece733548708d996ecf63190b9", size = 3533, upload-time = "2022-03-08T16:29:23.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/6e/995ebad4ab08250b4afe1d91fe3086b863ed9bb74539d90485250a50f08a/log_throttling-0.0.3-py3-none-any.whl", hash = "sha256:a82508f489dd44a60b737a0339c784dd8ee2b9db16bdcf587a8ae1012a7f6ffc", size = 4081, upload-time = "2022-03-08T16:29:21.443Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/9e/5c727587644d67b2ed479041e4b1c58e30afc011e3d45d25bbe35781217c/multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc", size = 76604, upload-time = "2025-10-06T14:48:54.277Z" }, + { url = "https://files.pythonhosted.org/packages/17/e4/67b5c27bd17c085a5ea8f1ec05b8a3e5cba0ca734bfcad5560fb129e70ca/multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721", size = 44715, upload-time = "2025-10-06T14:48:55.445Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/866a5d77be6ea435711bef2a4291eed11032679b6b28b56b4776ab06ba3e/multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6", size = 44332, upload-time = "2025-10-06T14:48:56.706Z" }, + { url = "https://files.pythonhosted.org/packages/31/61/0c2d50241ada71ff61a79518db85ada85fdabfcf395d5968dae1cbda04e5/multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c", size = 245212, upload-time = "2025-10-06T14:48:58.042Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e0/919666a4e4b57fff1b57f279be1c9316e6cdc5de8a8b525d76f6598fefc7/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7", size = 246671, upload-time = "2025-10-06T14:49:00.004Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cc/d027d9c5a520f3321b65adea289b965e7bcbd2c34402663f482648c716ce/multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7", size = 225491, upload-time = "2025-10-06T14:49:01.393Z" }, + { url = "https://files.pythonhosted.org/packages/75/c4/bbd633980ce6155a28ff04e6a6492dd3335858394d7bb752d8b108708558/multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9", size = 257322, upload-time = "2025-10-06T14:49:02.745Z" }, + { url = "https://files.pythonhosted.org/packages/4c/6d/d622322d344f1f053eae47e033b0b3f965af01212de21b10bcf91be991fb/multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8", size = 254694, upload-time = "2025-10-06T14:49:04.15Z" }, + { url = "https://files.pythonhosted.org/packages/a8/9f/78f8761c2705d4c6d7516faed63c0ebdac569f6db1bef95e0d5218fdc146/multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd", size = 246715, upload-time = "2025-10-06T14:49:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/950818e04f91b9c2b95aab3d923d9eabd01689d0dcd889563988e9ea0fd8/multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb", size = 243189, upload-time = "2025-10-06T14:49:07.37Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3d/77c79e1934cad2ee74991840f8a0110966d9599b3af95964c0cd79bb905b/multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6", size = 237845, upload-time = "2025-10-06T14:49:08.759Z" }, + { url = "https://files.pythonhosted.org/packages/63/1b/834ce32a0a97a3b70f86437f685f880136677ac00d8bce0027e9fd9c2db7/multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2", size = 246374, upload-time = "2025-10-06T14:49:10.574Z" }, + { url = "https://files.pythonhosted.org/packages/23/ef/43d1c3ba205b5dec93dc97f3fba179dfa47910fc73aaaea4f7ceb41cec2a/multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff", size = 253345, upload-time = "2025-10-06T14:49:12.331Z" }, + { url = "https://files.pythonhosted.org/packages/6b/03/eaf95bcc2d19ead522001f6a650ef32811aa9e3624ff0ad37c445c7a588c/multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b", size = 246940, upload-time = "2025-10-06T14:49:13.821Z" }, + { url = "https://files.pythonhosted.org/packages/e8/df/ec8a5fd66ea6cd6f525b1fcbb23511b033c3e9bc42b81384834ffa484a62/multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34", size = 242229, upload-time = "2025-10-06T14:49:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a2/59b405d59fd39ec86d1142630e9049243015a5f5291ba49cadf3c090c541/multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff", size = 41308, upload-time = "2025-10-06T14:49:16.871Z" }, + { url = "https://files.pythonhosted.org/packages/32/0f/13228f26f8b882c34da36efa776c3b7348455ec383bab4a66390e42963ae/multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81", size = 46037, upload-time = "2025-10-06T14:49:18.457Z" }, + { url = "https://files.pythonhosted.org/packages/84/1f/68588e31b000535a3207fd3c909ebeec4fb36b52c442107499c18a896a2a/multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912", size = 43023, upload-time = "2025-10-06T14:49:19.648Z" }, + { url = "https://files.pythonhosted.org/packages/c2/9e/9f61ac18d9c8b475889f32ccfa91c9f59363480613fc807b6e3023d6f60b/multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184", size = 76877, upload-time = "2025-10-06T14:49:20.884Z" }, + { url = "https://files.pythonhosted.org/packages/38/6f/614f09a04e6184f8824268fce4bc925e9849edfa654ddd59f0b64508c595/multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45", size = 45467, upload-time = "2025-10-06T14:49:22.054Z" }, + { url = "https://files.pythonhosted.org/packages/b3/93/c4f67a436dd026f2e780c433277fff72be79152894d9fc36f44569cab1a6/multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa", size = 43834, upload-time = "2025-10-06T14:49:23.566Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f5/013798161ca665e4a422afbc5e2d9e4070142a9ff8905e482139cd09e4d0/multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7", size = 250545, upload-time = "2025-10-06T14:49:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/71/2f/91dbac13e0ba94669ea5119ba267c9a832f0cb65419aca75549fcf09a3dc/multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e", size = 258305, upload-time = "2025-10-06T14:49:26.778Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b0/754038b26f6e04488b48ac621f779c341338d78503fb45403755af2df477/multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546", size = 242363, upload-time = "2025-10-06T14:49:28.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/15/9da40b9336a7c9fa606c4cf2ed80a649dffeb42b905d4f63a1d7eb17d746/multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4", size = 268375, upload-time = "2025-10-06T14:49:29.96Z" }, + { url = "https://files.pythonhosted.org/packages/82/72/c53fcade0cc94dfaad583105fd92b3a783af2091eddcb41a6d5a52474000/multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1", size = 269346, upload-time = "2025-10-06T14:49:31.404Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e2/9baffdae21a76f77ef8447f1a05a96ec4bc0a24dae08767abc0a2fe680b8/multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d", size = 256107, upload-time = "2025-10-06T14:49:32.974Z" }, + { url = "https://files.pythonhosted.org/packages/3c/06/3f06f611087dc60d65ef775f1fb5aca7c6d61c6db4990e7cda0cef9b1651/multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304", size = 253592, upload-time = "2025-10-06T14:49:34.52Z" }, + { url = "https://files.pythonhosted.org/packages/20/24/54e804ec7945b6023b340c412ce9c3f81e91b3bf5fa5ce65558740141bee/multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12", size = 251024, upload-time = "2025-10-06T14:49:35.956Z" }, + { url = "https://files.pythonhosted.org/packages/14/48/011cba467ea0b17ceb938315d219391d3e421dfd35928e5dbdc3f4ae76ef/multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62", size = 251484, upload-time = "2025-10-06T14:49:37.631Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2f/919258b43bb35b99fa127435cfb2d91798eb3a943396631ef43e3720dcf4/multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0", size = 263579, upload-time = "2025-10-06T14:49:39.502Z" }, + { url = "https://files.pythonhosted.org/packages/31/22/a0e884d86b5242b5a74cf08e876bdf299e413016b66e55511f7a804a366e/multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a", size = 259654, upload-time = "2025-10-06T14:49:41.32Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/17e10e1b5c5f5a40f2fcbb45953c9b215f8a4098003915e46a93f5fcaa8f/multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8", size = 251511, upload-time = "2025-10-06T14:49:46.021Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9a/201bb1e17e7af53139597069c375e7b0dcbd47594604f65c2d5359508566/multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4", size = 41895, upload-time = "2025-10-06T14:49:48.718Z" }, + { url = "https://files.pythonhosted.org/packages/46/e2/348cd32faad84eaf1d20cce80e2bb0ef8d312c55bca1f7fa9865e7770aaf/multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b", size = 46073, upload-time = "2025-10-06T14:49:50.28Z" }, + { url = "https://files.pythonhosted.org/packages/25/ec/aad2613c1910dce907480e0c3aa306905830f25df2e54ccc9dea450cb5aa/multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec", size = 43226, upload-time = "2025-10-06T14:49:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/d2/86/33272a544eeb36d66e4d9a920602d1a2f57d4ebea4ef3cdfe5a912574c95/multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6", size = 76135, upload-time = "2025-10-06T14:49:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/1c/eb97db117a1ebe46d457a3d235a7b9d2e6dcab174f42d1b67663dd9e5371/multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159", size = 45117, upload-time = "2025-10-06T14:49:55.82Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d8/6c3442322e41fb1dd4de8bd67bfd11cd72352ac131f6368315617de752f1/multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca", size = 43472, upload-time = "2025-10-06T14:49:57.048Z" }, + { url = "https://files.pythonhosted.org/packages/75/3f/e2639e80325af0b6c6febdf8e57cc07043ff15f57fa1ef808f4ccb5ac4cd/multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8", size = 249342, upload-time = "2025-10-06T14:49:58.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cc/84e0585f805cbeaa9cbdaa95f9a3d6aed745b9d25700623ac89a6ecff400/multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60", size = 257082, upload-time = "2025-10-06T14:49:59.89Z" }, + { url = "https://files.pythonhosted.org/packages/b0/9c/ac851c107c92289acbbf5cfb485694084690c1b17e555f44952c26ddc5bd/multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4", size = 240704, upload-time = "2025-10-06T14:50:01.485Z" }, + { url = "https://files.pythonhosted.org/packages/50/cc/5f93e99427248c09da95b62d64b25748a5f5c98c7c2ab09825a1d6af0e15/multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f", size = 266355, upload-time = "2025-10-06T14:50:02.955Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0c/2ec1d883ceb79c6f7f6d7ad90c919c898f5d1c6ea96d322751420211e072/multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf", size = 267259, upload-time = "2025-10-06T14:50:04.446Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2d/f0b184fa88d6630aa267680bdb8623fb69cb0d024b8c6f0d23f9a0f406d3/multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32", size = 254903, upload-time = "2025-10-06T14:50:05.98Z" }, + { url = "https://files.pythonhosted.org/packages/06/c9/11ea263ad0df7dfabcad404feb3c0dd40b131bc7f232d5537f2fb1356951/multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036", size = 252365, upload-time = "2025-10-06T14:50:07.511Z" }, + { url = "https://files.pythonhosted.org/packages/41/88/d714b86ee2c17d6e09850c70c9d310abac3d808ab49dfa16b43aba9d53fd/multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec", size = 250062, upload-time = "2025-10-06T14:50:09.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/fe/ad407bb9e818c2b31383f6131ca19ea7e35ce93cf1310fce69f12e89de75/multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e", size = 249683, upload-time = "2025-10-06T14:50:10.714Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/a89abdb0229e533fb925e7c6e5c40201c2873efebc9abaf14046a4536ee6/multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64", size = 261254, upload-time = "2025-10-06T14:50:12.28Z" }, + { url = "https://files.pythonhosted.org/packages/8d/aa/0e2b27bd88b40a4fb8dc53dd74eecac70edaa4c1dd0707eb2164da3675b3/multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd", size = 257967, upload-time = "2025-10-06T14:50:14.16Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8e/0c67b7120d5d5f6d874ed85a085f9dc770a7f9d8813e80f44a9fec820bb7/multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288", size = 250085, upload-time = "2025-10-06T14:50:15.639Z" }, + { url = "https://files.pythonhosted.org/packages/ba/55/b73e1d624ea4b8fd4dd07a3bb70f6e4c7c6c5d9d640a41c6ffe5cdbd2a55/multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17", size = 41713, upload-time = "2025-10-06T14:50:17.066Z" }, + { url = "https://files.pythonhosted.org/packages/32/31/75c59e7d3b4205075b4c183fa4ca398a2daf2303ddf616b04ae6ef55cffe/multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390", size = 45915, upload-time = "2025-10-06T14:50:18.264Z" }, + { url = "https://files.pythonhosted.org/packages/31/2a/8987831e811f1184c22bc2e45844934385363ee61c0a2dcfa8f71b87e608/multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e", size = 43077, upload-time = "2025-10-06T14:50:19.853Z" }, + { url = "https://files.pythonhosted.org/packages/e8/68/7b3a5170a382a340147337b300b9eb25a9ddb573bcdfff19c0fa3f31ffba/multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00", size = 83114, upload-time = "2025-10-06T14:50:21.223Z" }, + { url = "https://files.pythonhosted.org/packages/55/5c/3fa2d07c84df4e302060f555bbf539310980362236ad49f50eeb0a1c1eb9/multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb", size = 48442, upload-time = "2025-10-06T14:50:22.871Z" }, + { url = "https://files.pythonhosted.org/packages/fc/56/67212d33239797f9bd91962bb899d72bb0f4c35a8652dcdb8ed049bef878/multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b", size = 46885, upload-time = "2025-10-06T14:50:24.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/d1/908f896224290350721597a61a69cd19b89ad8ee0ae1f38b3f5cd12ea2ac/multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c", size = 242588, upload-time = "2025-10-06T14:50:25.716Z" }, + { url = "https://files.pythonhosted.org/packages/ab/67/8604288bbd68680eee0ab568fdcb56171d8b23a01bcd5cb0c8fedf6e5d99/multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1", size = 249966, upload-time = "2025-10-06T14:50:28.192Z" }, + { url = "https://files.pythonhosted.org/packages/20/33/9228d76339f1ba51e3efef7da3ebd91964d3006217aae13211653193c3ff/multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b", size = 228618, upload-time = "2025-10-06T14:50:29.82Z" }, + { url = "https://files.pythonhosted.org/packages/f8/2d/25d9b566d10cab1c42b3b9e5b11ef79c9111eaf4463b8c257a3bd89e0ead/multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5", size = 257539, upload-time = "2025-10-06T14:50:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b1/8d1a965e6637fc33de3c0d8f414485c2b7e4af00f42cab3d84e7b955c222/multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad", size = 256345, upload-time = "2025-10-06T14:50:33.26Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/06b5a8adbdeedada6f4fb8d8f193d44a347223b11939b42953eeb6530b6b/multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c", size = 247934, upload-time = "2025-10-06T14:50:34.808Z" }, + { url = "https://files.pythonhosted.org/packages/8f/31/b2491b5fe167ca044c6eb4b8f2c9f3b8a00b24c432c365358eadac5d7625/multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5", size = 245243, upload-time = "2025-10-06T14:50:36.436Z" }, + { url = "https://files.pythonhosted.org/packages/61/1a/982913957cb90406c8c94f53001abd9eafc271cb3e70ff6371590bec478e/multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10", size = 235878, upload-time = "2025-10-06T14:50:37.953Z" }, + { url = "https://files.pythonhosted.org/packages/be/c0/21435d804c1a1cf7a2608593f4d19bca5bcbd7a81a70b253fdd1c12af9c0/multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754", size = 243452, upload-time = "2025-10-06T14:50:39.574Z" }, + { url = "https://files.pythonhosted.org/packages/54/0a/4349d540d4a883863191be6eb9a928846d4ec0ea007d3dcd36323bb058ac/multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c", size = 252312, upload-time = "2025-10-06T14:50:41.612Z" }, + { url = "https://files.pythonhosted.org/packages/26/64/d5416038dbda1488daf16b676e4dbfd9674dde10a0cc8f4fc2b502d8125d/multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762", size = 246935, upload-time = "2025-10-06T14:50:43.972Z" }, + { url = "https://files.pythonhosted.org/packages/9f/8c/8290c50d14e49f35e0bd4abc25e1bc7711149ca9588ab7d04f886cdf03d9/multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6", size = 243385, upload-time = "2025-10-06T14:50:45.648Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777, upload-time = "2025-10-06T14:50:47.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104, upload-time = "2025-10-06T14:50:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503, upload-time = "2025-10-06T14:50:50.16Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128, upload-time = "2025-10-06T14:50:51.92Z" }, + { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410, upload-time = "2025-10-06T14:50:53.275Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205, upload-time = "2025-10-06T14:50:54.911Z" }, + { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084, upload-time = "2025-10-06T14:50:56.369Z" }, + { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667, upload-time = "2025-10-06T14:50:57.991Z" }, + { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590, upload-time = "2025-10-06T14:50:59.589Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112, upload-time = "2025-10-06T14:51:01.183Z" }, + { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194, upload-time = "2025-10-06T14:51:02.794Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510, upload-time = "2025-10-06T14:51:04.724Z" }, + { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395, upload-time = "2025-10-06T14:51:06.306Z" }, + { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520, upload-time = "2025-10-06T14:51:08.091Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479, upload-time = "2025-10-06T14:51:10.365Z" }, + { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903, upload-time = "2025-10-06T14:51:12.466Z" }, + { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333, upload-time = "2025-10-06T14:51:14.48Z" }, + { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411, upload-time = "2025-10-06T14:51:16.072Z" }, + { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940, upload-time = "2025-10-06T14:51:17.544Z" }, + { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087, upload-time = "2025-10-06T14:51:18.875Z" }, + { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368, upload-time = "2025-10-06T14:51:20.225Z" }, + { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326, upload-time = "2025-10-06T14:51:21.588Z" }, + { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065, upload-time = "2025-10-06T14:51:22.93Z" }, + { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475, upload-time = "2025-10-06T14:51:24.352Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324, upload-time = "2025-10-06T14:51:25.822Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877, upload-time = "2025-10-06T14:51:27.604Z" }, + { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824, upload-time = "2025-10-06T14:51:29.664Z" }, + { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558, upload-time = "2025-10-06T14:51:31.684Z" }, + { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339, upload-time = "2025-10-06T14:51:33.699Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895, upload-time = "2025-10-06T14:51:36.189Z" }, + { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862, upload-time = "2025-10-06T14:51:41.291Z" }, + { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376, upload-time = "2025-10-06T14:51:43.55Z" }, + { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272, upload-time = "2025-10-06T14:51:45.265Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774, upload-time = "2025-10-06T14:51:46.836Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731, upload-time = "2025-10-06T14:51:48.541Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193, upload-time = "2025-10-06T14:51:50.355Z" }, + { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023, upload-time = "2025-10-06T14:51:51.883Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507, upload-time = "2025-10-06T14:51:53.672Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804, upload-time = "2025-10-06T14:51:55.415Z" }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, +] + +[[package]] +name = "numpy" +version = "2.3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/77/84dd1d2e34d7e2792a236ba180b5e8fcc1e3e414e761ce0253f63d7f572e/numpy-2.3.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de5672f4a7b200c15a4127042170a694d4df43c992948f5e1af57f0174beed10", size = 17034641, upload-time = "2025-11-16T22:49:19.336Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ea/25e26fa5837106cde46ae7d0b667e20f69cbbc0efd64cba8221411ab26ae/numpy-2.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acfd89508504a19ed06ef963ad544ec6664518c863436306153e13e94605c218", size = 12528324, upload-time = "2025-11-16T22:49:22.582Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1a/e85f0eea4cf03d6a0228f5c0256b53f2df4bc794706e7df019fc622e47f1/numpy-2.3.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ffe22d2b05504f786c867c8395de703937f934272eb67586817b46188b4ded6d", size = 5356872, upload-time = "2025-11-16T22:49:25.408Z" }, + { url = "https://files.pythonhosted.org/packages/5c/bb/35ef04afd567f4c989c2060cde39211e4ac5357155c1833bcd1166055c61/numpy-2.3.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:872a5cf366aec6bb1147336480fef14c9164b154aeb6542327de4970282cd2f5", size = 6893148, upload-time = "2025-11-16T22:49:27.549Z" }, + { url = "https://files.pythonhosted.org/packages/f2/2b/05bbeb06e2dff5eab512dfc678b1cc5ee94d8ac5956a0885c64b6b26252b/numpy-2.3.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3095bdb8dd297e5920b010e96134ed91d852d81d490e787beca7e35ae1d89cf7", size = 14557282, upload-time = "2025-11-16T22:49:30.964Z" }, + { url = "https://files.pythonhosted.org/packages/65/fb/2b23769462b34398d9326081fad5655198fcf18966fcb1f1e49db44fbf31/numpy-2.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cba086a43d54ca804ce711b2a940b16e452807acebe7852ff327f1ecd49b0d4", size = 16897903, upload-time = "2025-11-16T22:49:34.191Z" }, + { url = "https://files.pythonhosted.org/packages/ac/14/085f4cf05fc3f1e8aa95e85404e984ffca9b2275a5dc2b1aae18a67538b8/numpy-2.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cf9b429b21df6b99f4dee7a1218b8b7ffbbe7df8764dc0bd60ce8a0708fed1e", size = 16341672, upload-time = "2025-11-16T22:49:37.2Z" }, + { url = "https://files.pythonhosted.org/packages/6f/3b/1f73994904142b2aa290449b3bb99772477b5fd94d787093e4f24f5af763/numpy-2.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:396084a36abdb603546b119d96528c2f6263921c50df3c8fd7cb28873a237748", size = 18838896, upload-time = "2025-11-16T22:49:39.727Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b9/cf6649b2124f288309ffc353070792caf42ad69047dcc60da85ee85fea58/numpy-2.3.5-cp311-cp311-win32.whl", hash = "sha256:b0c7088a73aef3d687c4deef8452a3ac7c1be4e29ed8bf3b366c8111128ac60c", size = 6563608, upload-time = "2025-11-16T22:49:42.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/44/9fe81ae1dcc29c531843852e2874080dc441338574ccc4306b39e2ff6e59/numpy-2.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:a414504bef8945eae5f2d7cb7be2d4af77c5d1cb5e20b296c2c25b61dff2900c", size = 13078442, upload-time = "2025-11-16T22:49:43.99Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a7/f99a41553d2da82a20a2f22e93c94f928e4490bb447c9ff3c4ff230581d3/numpy-2.3.5-cp311-cp311-win_arm64.whl", hash = "sha256:0cd00b7b36e35398fa2d16af7b907b65304ef8bb4817a550e06e5012929830fa", size = 10458555, upload-time = "2025-11-16T22:49:47.092Z" }, + { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873, upload-time = "2025-11-16T22:49:49.84Z" }, + { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838, upload-time = "2025-11-16T22:49:52.863Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378, upload-time = "2025-11-16T22:49:55.055Z" }, + { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559, upload-time = "2025-11-16T22:49:57.371Z" }, + { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702, upload-time = "2025-11-16T22:49:59.632Z" }, + { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086, upload-time = "2025-11-16T22:50:02.127Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985, upload-time = "2025-11-16T22:50:04.536Z" }, + { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976, upload-time = "2025-11-16T22:50:07.557Z" }, + { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274, upload-time = "2025-11-16T22:50:10.746Z" }, + { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922, upload-time = "2025-11-16T22:50:12.811Z" }, + { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667, upload-time = "2025-11-16T22:50:16.16Z" }, + { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" }, + { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" }, + { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" }, + { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" }, + { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" }, + { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" }, + { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" }, + { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" }, + { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" }, + { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" }, + { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" }, + { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" }, + { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" }, + { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" }, + { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" }, + { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" }, + { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" }, + { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" }, + { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" }, + { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706, upload-time = "2025-11-16T22:51:19.558Z" }, + { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507, upload-time = "2025-11-16T22:51:22.492Z" }, + { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049, upload-time = "2025-11-16T22:51:25.171Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603, upload-time = "2025-11-16T22:51:27Z" }, + { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696, upload-time = "2025-11-16T22:51:29.402Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350, upload-time = "2025-11-16T22:51:32.167Z" }, + { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190, upload-time = "2025-11-16T22:51:35.403Z" }, + { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749, upload-time = "2025-11-16T22:51:39.698Z" }, + { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432, upload-time = "2025-11-16T22:51:42.476Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388, upload-time = "2025-11-16T22:51:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651, upload-time = "2025-11-16T22:51:47.749Z" }, + { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503, upload-time = "2025-11-16T22:51:50.443Z" }, + { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612, upload-time = "2025-11-16T22:51:53.609Z" }, + { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042, upload-time = "2025-11-16T22:51:56.213Z" }, + { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502, upload-time = "2025-11-16T22:51:58.584Z" }, + { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962, upload-time = "2025-11-16T22:52:01.698Z" }, + { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054, upload-time = "2025-11-16T22:52:04.267Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613, upload-time = "2025-11-16T22:52:08.651Z" }, + { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147, upload-time = "2025-11-16T22:52:11.453Z" }, + { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806, upload-time = "2025-11-16T22:52:14.641Z" }, + { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760, upload-time = "2025-11-16T22:52:17.975Z" }, + { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" }, + { url = "https://files.pythonhosted.org/packages/c6/65/f9dea8e109371ade9c782b4e4756a82edf9d3366bca495d84d79859a0b79/numpy-2.3.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f0963b55cdd70fad460fa4c1341f12f976bb26cb66021a5580329bd498988310", size = 16910689, upload-time = "2025-11-16T22:52:23.247Z" }, + { url = "https://files.pythonhosted.org/packages/00/4f/edb00032a8fb92ec0a679d3830368355da91a69cab6f3e9c21b64d0bb986/numpy-2.3.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4255143f5160d0de972d28c8f9665d882b5f61309d8362fdd3e103cf7bf010c", size = 12457053, upload-time = "2025-11-16T22:52:26.367Z" }, + { url = "https://files.pythonhosted.org/packages/16/a4/e8a53b5abd500a63836a29ebe145fc1ab1f2eefe1cfe59276020373ae0aa/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:a4b9159734b326535f4dd01d947f919c6eefd2d9827466a696c44ced82dfbc18", size = 5285635, upload-time = "2025-11-16T22:52:29.266Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2f/37eeb9014d9c8b3e9c55bc599c68263ca44fdbc12a93e45a21d1d56df737/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2feae0d2c91d46e59fcd62784a3a83b3fb677fead592ce51b5a6fbb4f95965ff", size = 6801770, upload-time = "2025-11-16T22:52:31.421Z" }, + { url = "https://files.pythonhosted.org/packages/7d/e4/68d2f474df2cb671b2b6c2986a02e520671295647dad82484cde80ca427b/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffac52f28a7849ad7576293c0cb7b9f08304e8f7d738a8cb8a90ec4c55a998eb", size = 14391768, upload-time = "2025-11-16T22:52:33.593Z" }, + { url = "https://files.pythonhosted.org/packages/b8/50/94ccd8a2b141cb50651fddd4f6a48874acb3c91c8f0842b08a6afc4b0b21/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63c0e9e7eea69588479ebf4a8a270d5ac22763cc5854e9a7eae952a3908103f7", size = 16729263, upload-time = "2025-11-16T22:52:36.369Z" }, + { url = "https://files.pythonhosted.org/packages/2d/ee/346fa473e666fe14c52fcdd19ec2424157290a032d4c41f98127bfb31ac7/numpy-2.3.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f16417ec91f12f814b10bafe79ef77e70113a2f5f7018640e7425ff979253425", size = 12967213, upload-time = "2025-11-16T22:52:39.38Z" }, +] + +[[package]] +name = "opencv-python" +version = "4.11.0.86" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/06/68c27a523103dad5837dc5b87e71285280c4f098c60e4fe8a8db6486ab09/opencv-python-4.11.0.86.tar.gz", hash = "sha256:03d60ccae62304860d232272e4a4fda93c39d595780cb40b161b310244b736a4", size = 95171956, upload-time = "2025-01-16T13:52:24.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/4d/53b30a2a3ac1f75f65a59eb29cf2ee7207ce64867db47036ad61743d5a23/opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:432f67c223f1dc2824f5e73cdfcd9db0efc8710647d4e813012195dc9122a52a", size = 37326322, upload-time = "2025-01-16T13:52:25.887Z" }, + { url = "https://files.pythonhosted.org/packages/3b/84/0a67490741867eacdfa37bc18df96e08a9d579583b419010d7f3da8ff503/opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:9d05ef13d23fe97f575153558653e2d6e87103995d54e6a35db3f282fe1f9c66", size = 56723197, upload-time = "2025-01-16T13:55:21.222Z" }, + { url = "https://files.pythonhosted.org/packages/f3/bd/29c126788da65c1fb2b5fb621b7fed0ed5f9122aa22a0868c5e2c15c6d23/opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b92ae2c8852208817e6776ba1ea0d6b1e0a1b5431e971a2a0ddd2a8cc398202", size = 42230439, upload-time = "2025-01-16T13:51:35.822Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8b/90eb44a40476fa0e71e05a0283947cfd74a5d36121a11d926ad6f3193cc4/opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b02611523803495003bd87362db3e1d2a0454a6a63025dc6658a9830570aa0d", size = 62986597, upload-time = "2025-01-16T13:52:08.836Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/1d5941a9dde095468b288d989ff6539dd69cd429dbf1b9e839013d21b6f0/opencv_python-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:810549cb2a4aedaa84ad9a1c92fbfdfc14090e2749cedf2c1589ad8359aa169b", size = 29384337, upload-time = "2025-01-16T13:52:13.549Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/f1c30a92854540bf789e9cd5dde7ef49bbe63f855b85a2e6b3db8135c591/opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec", size = 39488044, upload-time = "2025-01-16T13:52:21.928Z" }, +] + +[[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 = "pip" +version = "25.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, + { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, + { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" }, + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, + { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, + { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, + { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, + { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, + { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, + { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, + { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, + { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, + { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, + { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + +[[package]] +name = "psutil" +version = "7.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/88/bdd0a41e5857d5d703287598cbf08dad90aed56774ea52ae071bae9071b6/psutil-7.1.3.tar.gz", hash = "sha256:6c86281738d77335af7aec228328e944b30930899ea760ecf33a4dba66be5e74", size = 489059, upload-time = "2025-11-02T12:25:54.619Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/93/0c49e776b8734fef56ec9c5c57f923922f2cf0497d62e0f419465f28f3d0/psutil-7.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0005da714eee687b4b8decd3d6cc7c6db36215c9e74e5ad2264b90c3df7d92dc", size = 239751, upload-time = "2025-11-02T12:25:58.161Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8d/b31e39c769e70780f007969815195a55c81a63efebdd4dbe9e7a113adb2f/psutil-7.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:19644c85dcb987e35eeeaefdc3915d059dac7bd1167cdcdbf27e0ce2df0c08c0", size = 240368, upload-time = "2025-11-02T12:26:00.491Z" }, + { url = "https://files.pythonhosted.org/packages/62/61/23fd4acc3c9eebbf6b6c78bcd89e5d020cfde4acf0a9233e9d4e3fa698b4/psutil-7.1.3-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95ef04cf2e5ba0ab9eaafc4a11eaae91b44f4ef5541acd2ee91d9108d00d59a7", size = 287134, upload-time = "2025-11-02T12:26:02.613Z" }, + { url = "https://files.pythonhosted.org/packages/30/1c/f921a009ea9ceb51aa355cb0cc118f68d354db36eae18174bab63affb3e6/psutil-7.1.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1068c303be3a72f8e18e412c5b2a8f6d31750fb152f9cb106b54090296c9d251", size = 289904, upload-time = "2025-11-02T12:26:05.207Z" }, + { url = "https://files.pythonhosted.org/packages/a6/82/62d68066e13e46a5116df187d319d1724b3f437ddd0f958756fc052677f4/psutil-7.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:18349c5c24b06ac5612c0428ec2a0331c26443d259e2a0144a9b24b4395b58fa", size = 249642, upload-time = "2025-11-02T12:26:07.447Z" }, + { url = "https://files.pythonhosted.org/packages/df/ad/c1cd5fe965c14a0392112f68362cfceb5230819dbb5b1888950d18a11d9f/psutil-7.1.3-cp313-cp313t-win_arm64.whl", hash = "sha256:c525ffa774fe4496282fb0b1187725793de3e7c6b29e41562733cae9ada151ee", size = 245518, upload-time = "2025-11-02T12:26:09.719Z" }, + { url = "https://files.pythonhosted.org/packages/2e/bb/6670bded3e3236eb4287c7bcdc167e9fae6e1e9286e437f7111caed2f909/psutil-7.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b403da1df4d6d43973dc004d19cee3b848e998ae3154cc8097d139b77156c353", size = 239843, upload-time = "2025-11-02T12:26:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/b8/66/853d50e75a38c9a7370ddbeefabdd3d3116b9c31ef94dc92c6729bc36bec/psutil-7.1.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad81425efc5e75da3f39b3e636293360ad8d0b49bed7df824c79764fb4ba9b8b", size = 240369, upload-time = "2025-11-02T12:26:14.358Z" }, + { url = "https://files.pythonhosted.org/packages/41/bd/313aba97cb5bfb26916dc29cf0646cbe4dd6a89ca69e8c6edce654876d39/psutil-7.1.3-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f33a3702e167783a9213db10ad29650ebf383946e91bc77f28a5eb083496bc9", size = 288210, upload-time = "2025-11-02T12:26:16.699Z" }, + { url = "https://files.pythonhosted.org/packages/c2/fa/76e3c06e760927a0cfb5705eb38164254de34e9bd86db656d4dbaa228b04/psutil-7.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fac9cd332c67f4422504297889da5ab7e05fd11e3c4392140f7370f4208ded1f", size = 291182, upload-time = "2025-11-02T12:26:18.848Z" }, + { url = "https://files.pythonhosted.org/packages/0f/1d/5774a91607035ee5078b8fd747686ebec28a962f178712de100d00b78a32/psutil-7.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:3792983e23b69843aea49c8f5b8f115572c5ab64c153bada5270086a2123c7e7", size = 250466, upload-time = "2025-11-02T12:26:21.183Z" }, + { url = "https://files.pythonhosted.org/packages/00/ca/e426584bacb43a5cb1ac91fae1937f478cd8fbe5e4ff96574e698a2c77cd/psutil-7.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:31d77fcedb7529f27bb3a0472bea9334349f9a04160e8e6e5020f22c59893264", size = 245756, upload-time = "2025-11-02T12:26:23.148Z" }, + { url = "https://files.pythonhosted.org/packages/ef/94/46b9154a800253e7ecff5aaacdf8ebf43db99de4a2dfa18575b02548654e/psutil-7.1.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2bdbcd0e58ca14996a42adf3621a6244f1bb2e2e528886959c72cf1e326677ab", size = 238359, upload-time = "2025-11-02T12:26:25.284Z" }, + { url = "https://files.pythonhosted.org/packages/68/3a/9f93cff5c025029a36d9a92fef47220ab4692ee7f2be0fba9f92813d0cb8/psutil-7.1.3-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31fa00f1fbc3c3802141eede66f3a2d51d89716a194bf2cd6fc68310a19880", size = 239171, upload-time = "2025-11-02T12:26:27.23Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b1/5f49af514f76431ba4eea935b8ad3725cdeb397e9245ab919dbc1d1dc20f/psutil-7.1.3-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb428f9f05c1225a558f53e30ccbad9930b11c3fc206836242de1091d3e7dd3", size = 263261, upload-time = "2025-11-02T12:26:29.48Z" }, + { url = "https://files.pythonhosted.org/packages/e0/95/992c8816a74016eb095e73585d747e0a8ea21a061ed3689474fabb29a395/psutil-7.1.3-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56d974e02ca2c8eb4812c3f76c30e28836fffc311d55d979f1465c1feeb2b68b", size = 264635, upload-time = "2025-11-02T12:26:31.74Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/c3ed1a622b6ae2fd3c945a366e64eb35247a31e4db16cf5095e269e8eb3c/psutil-7.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:f39c2c19fe824b47484b96f9692932248a54c43799a84282cfe58d05a6449efd", size = 247633, upload-time = "2025-11-02T12:26:33.887Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ad/33b2ccec09bf96c2b2ef3f9a6f66baac8253d7565d8839e024a6b905d45d/psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1", size = 244608, upload-time = "2025-11-02T12:26:36.136Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.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/96/ad/a17bc283d7d81837c061c49e3eaa27a45991759a1b7eae1031921c6bd924/pydantic-2.12.4.tar.gz", hash = "sha256:0f8cb9555000a4b5b617f66bfd2566264c4984b27589d3b845685983e8ea85ac", size = 821038, upload-time = "2025-11-05T10:50:08.59Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/2f/e68750da9b04856e2a7ec56fc6f034a5a79775e9b9a81882252789873798/pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e", size = 463400, upload-time = "2025-11-05T10:50:06.732Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + +[[package]] +name = "pyobjc-core" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/b6/d5612eb40be4fd5ef88c259339e6313f46ba67577a95d86c3470b951fce0/pyobjc_core-12.1.tar.gz", hash = "sha256:2bb3903f5387f72422145e1466b3ac3f7f0ef2e9960afa9bcd8961c5cbf8bd21", size = 1000532, upload-time = "2025-11-14T10:08:28.292Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/df/d2b290708e9da86d6e7a9a2a2022b91915cf2e712a5a82e306cb6ee99792/pyobjc_core-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c918ebca280925e7fcb14c5c43ce12dcb9574a33cccb889be7c8c17f3bcce8b6", size = 671263, upload-time = "2025-11-14T09:31:35.231Z" }, + { url = "https://files.pythonhosted.org/packages/64/5a/6b15e499de73050f4a2c88fff664ae154307d25dc04da8fb38998a428358/pyobjc_core-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:818bcc6723561f207e5b5453efe9703f34bc8781d11ce9b8be286bb415eb4962", size = 678335, upload-time = "2025-11-14T09:32:20.107Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d2/29e5e536adc07bc3d33dd09f3f7cf844bf7b4981820dc2a91dd810f3c782/pyobjc_core-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:01c0cf500596f03e21c23aef9b5f326b9fb1f8f118cf0d8b66749b6cf4cbb37a", size = 677370, upload-time = "2025-11-14T09:33:05.273Z" }, + { url = "https://files.pythonhosted.org/packages/1b/f0/4b4ed8924cd04e425f2a07269943018d43949afad1c348c3ed4d9d032787/pyobjc_core-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:177aaca84bb369a483e4961186704f64b2697708046745f8167e818d968c88fc", size = 719586, upload-time = "2025-11-14T09:33:53.302Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/9f4ed07162de69603144ff480be35cd021808faa7f730d082b92f7ebf2b5/pyobjc_core-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:844515f5d86395b979d02152576e7dee9cc679acc0b32dc626ef5bda315eaa43", size = 670164, upload-time = "2025-11-14T09:34:37.458Z" }, + { url = "https://files.pythonhosted.org/packages/62/50/dc076965c96c7f0de25c0a32b7f8aa98133ed244deaeeacfc758783f1f30/pyobjc_core-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:453b191df1a4b80e756445b935491b974714456ae2cbae816840bd96f86db882", size = 712204, upload-time = "2025-11-14T09:35:24.148Z" }, +] + +[[package]] +name = "pyobjc-framework-avfoundation" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/42/c026ab308edc2ed5582d8b4b93da6b15d1b6557c0086914a4aabedd1f032/pyobjc_framework_avfoundation-12.1.tar.gz", hash = "sha256:eda0bb60be380f9ba2344600c4231dd58a3efafa99fdc65d3673ecfbb83f6fcb", size = 310047, upload-time = "2025-11-14T10:09:40.069Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/5a/4ef36b309138840ff8cd85364f66c29e27023f291004c335a99f6e87e599/pyobjc_framework_avfoundation-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:82cc2c2d9ab6cc04feeb4700ff251d00f1fcafff573c63d4e87168ff80adb926", size = 83328, upload-time = "2025-11-14T09:37:40.808Z" }, + { url = "https://files.pythonhosted.org/packages/a6/00/ca471e5dd33f040f69320832e45415d00440260bf7f8221a9df4c4662659/pyobjc_framework_avfoundation-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bf634f89265b4d93126153200d885b6de4859ed6b3bc65e69ff75540bc398406", size = 83375, upload-time = "2025-11-14T09:37:47.262Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d4/ade88067deff45858b457648dd82c9363977eb1915efd257232cd06bdac1/pyobjc_framework_avfoundation-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f8ac7f7e0884ac8f12009cdb9d4fefc2f269294ab2ccfd84520a560859b69cec", size = 83413, upload-time = "2025-11-14T09:37:53.759Z" }, + { url = "https://files.pythonhosted.org/packages/a7/3a/fa699d748d6351fa0aeca656ea2f9eacc36e31203dfa56bc13c8a3d26d7d/pyobjc_framework_avfoundation-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:51aba2c6816badfb1fb5a2de1b68b33a23f065bf9e3b99d46ede0c8c774ac7a4", size = 83860, upload-time = "2025-11-14T09:38:00.051Z" }, + { url = "https://files.pythonhosted.org/packages/0c/65/a79cf3b8935a78329ac1107056b91868a581096a90ab6ddff5fd28db4947/pyobjc_framework_avfoundation-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:9a3ffd1ae90bd72dbcf2875aa9254369e805b904140362a7338ebf1af54201a6", size = 83629, upload-time = "2025-11-14T09:38:06.697Z" }, + { url = "https://files.pythonhosted.org/packages/8a/03/4125204a17cd7b4de1fdfc38b280a47d0d8f8691a4ee306ebb41b58ff030/pyobjc_framework_avfoundation-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:394c99876b9a38db4851ddf8146db363556895c12e9c711ccd3c3f907ac8e273", size = 83962, upload-time = "2025-11-14T09:38:13.153Z" }, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/a3/16ca9a15e77c061a9250afbae2eae26f2e1579eb8ca9462ae2d2c71e1169/pyobjc_framework_cocoa-12.1.tar.gz", hash = "sha256:5556c87db95711b985d5efdaaf01c917ddd41d148b1e52a0c66b1a2e2c5c1640", size = 2772191, upload-time = "2025-11-14T10:13:02.069Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/07/5760735c0fffc65107e648eaf7e0991f46da442ac4493501be5380e6d9d4/pyobjc_framework_cocoa-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f52228bcf38da64b77328787967d464e28b981492b33a7675585141e1b0a01e6", size = 383812, upload-time = "2025-11-14T09:40:53.169Z" }, + { url = "https://files.pythonhosted.org/packages/95/bf/ee4f27ec3920d5c6fc63c63e797c5b2cc4e20fe439217085d01ea5b63856/pyobjc_framework_cocoa-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:547c182837214b7ec4796dac5aee3aa25abc665757b75d7f44f83c994bcb0858", size = 384590, upload-time = "2025-11-14T09:41:17.336Z" }, + { url = "https://files.pythonhosted.org/packages/ad/31/0c2e734165abb46215797bd830c4bdcb780b699854b15f2b6240515edcc6/pyobjc_framework_cocoa-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5a3dcd491cacc2f5a197142b3c556d8aafa3963011110102a093349017705118", size = 384689, upload-time = "2025-11-14T09:41:41.478Z" }, + { url = "https://files.pythonhosted.org/packages/23/3b/b9f61be7b9f9b4e0a6db18b3c35c4c4d589f2d04e963e2174d38c6555a92/pyobjc_framework_cocoa-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:914b74328c22d8ca261d78c23ef2befc29776e0b85555973927b338c5734ca44", size = 388843, upload-time = "2025-11-14T09:42:05.719Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/f777cc9e775fc7dae77b569254570fe46eb842516b3e4fe383ab49eab598/pyobjc_framework_cocoa-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:03342a60fc0015bcdf9b93ac0b4f457d3938e9ef761b28df9564c91a14f0129a", size = 384932, upload-time = "2025-11-14T09:42:29.771Z" }, + { url = "https://files.pythonhosted.org/packages/58/27/b457b7b37089cad692c8aada90119162dfb4c4a16f513b79a8b2b022b33b/pyobjc_framework_cocoa-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6ba1dc1bfa4da42d04e93d2363491275fb2e2be5c20790e561c8a9e09b8cf2cc", size = 388970, upload-time = "2025-11-14T09:42:53.964Z" }, +] + +[[package]] +name = "pyobjc-framework-coreaudio" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/d1/0b884c5564ab952ff5daa949128c64815300556019c1bba0cf2ca752a1a0/pyobjc_framework_coreaudio-12.1.tar.gz", hash = "sha256:a9e72925fcc1795430496ce0bffd4ddaa92c22460a10308a7283ade830089fe1", size = 75077, upload-time = "2025-11-14T10:13:22.345Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/25/491ff549fd9a40be4416793d335bff1911d3d1d1e1635e3b0defbd2cf585/pyobjc_framework_coreaudio-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a452de6b509fa4a20160c0410b72330ac871696cd80237883955a5b3a4de8f2a", size = 35327, upload-time = "2025-11-14T09:43:32.523Z" }, + { url = "https://files.pythonhosted.org/packages/a9/48/05b5192122e23140cf583eac99ccc5bf615591d6ff76483ba986c38ee750/pyobjc_framework_coreaudio-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a5ad6309779663f846ab36fe6c49647e470b7e08473c3e48b4f004017bdb68a4", size = 36908, upload-time = "2025-11-14T09:43:36.108Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ce/45808618fefc760e2948c363e0a3402ff77690c8934609cd07b19bc5b15f/pyobjc_framework_coreaudio-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3d8ef424850c8ae2146f963afaec6c4f5bf0c2e412871e68fb6ecfb209b8376f", size = 36935, upload-time = "2025-11-14T09:43:39.414Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f6/0d74d9464bfb4f39451abf745174ec0c4d5c5ebf1c2fcb7556263ae3f75a/pyobjc_framework_coreaudio-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6552624df39dbc68ff9328f244ba56f59234ecbde8455db1e617a71bc4f3dd3a", size = 38390, upload-time = "2025-11-14T09:43:43.194Z" }, + { url = "https://files.pythonhosted.org/packages/cf/f2/c5ca32d01c9d892bf189cfe9b17deaf996db3b4013f8a8ba9b0d22730d70/pyobjc_framework_coreaudio-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:78ea67483a5deb21625c189328152008d278fe1da4304da9fcc1babd12627038", size = 37012, upload-time = "2025-11-14T09:43:46.54Z" }, + { url = "https://files.pythonhosted.org/packages/00/be/c3d660cef1ef874f42057a74931a7a05f581f6a647f5209bef96b372db86/pyobjc_framework_coreaudio-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:8d81b0d0296ab4571a4ff302e5cdb52386e486eb8749e99b95b9141438558ca2", size = 38485, upload-time = "2025-11-14T09:43:49.883Z" }, +] + +[[package]] +name = "pyobjc-framework-coremedia" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/7d/5ad600ff7aedfef8ba8f51b11d9aaacdf247b870bd14045d6e6f232e3df9/pyobjc_framework_coremedia-12.1.tar.gz", hash = "sha256:166c66a9c01e7a70103f3ca44c571431d124b9070612ef63a1511a4e6d9d84a7", size = 89566, upload-time = "2025-11-14T10:13:49.788Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/bc/e66de468b3777d8fece69279cf6d2af51d2263e9a1ccad21b90c35c74b1b/pyobjc_framework_coremedia-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ee7b822c9bb674b5b0a70bfb133410acae354e9241b6983f075395f3562f3c46", size = 29503, upload-time = "2025-11-14T09:44:54.716Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ae/f773cdc33c34a3f9ce6db829dbf72661b65c28ea9efaec8940364185b977/pyobjc_framework_coremedia-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:161a627f5c8cd30a5ebb935189f740e21e6cd94871a9afd463efdb5d51e255fa", size = 29396, upload-time = "2025-11-14T09:44:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ea/aee26a475b4af8ed4152d3c50b1b8955241b8e95ae789aa9ee296953bc6a/pyobjc_framework_coremedia-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:98e885b7a092083fceaef0a7fc406a01ba7bcd3318fb927e59e055931c99cac8", size = 29414, upload-time = "2025-11-14T09:45:01.336Z" }, + { url = "https://files.pythonhosted.org/packages/db/9d/5ff10ee0ff539e125c96b8cff005457558766f942919814c968c3367cc32/pyobjc_framework_coremedia-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:d2b84149c1b3e65ec9050a3e5b617e6c0b4cdad2ab622c2d8c5747a20f013e16", size = 29477, upload-time = "2025-11-14T09:45:04.218Z" }, + { url = "https://files.pythonhosted.org/packages/08/e2/b890658face1290c8b6b6b53a1159c822bece248f883e42302548bef38da/pyobjc_framework_coremedia-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:737ec6e0b63414f42f7188030c85975d6d2124fbf6b15b52c99b6cc20250af4d", size = 29447, upload-time = "2025-11-14T09:45:07.17Z" }, + { url = "https://files.pythonhosted.org/packages/a4/9e/16981d0ee04b182481ce1e497b5e0326bad6d698fe0265bb7db72b1b26b5/pyobjc_framework_coremedia-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6a9419e0d143df16a1562520a13a389417386e2a53031530af6da60c34058ced", size = 29500, upload-time = "2025-11-14T09:45:10.506Z" }, +] + +[[package]] +name = "pyobjc-framework-quartz" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/18/cc59f3d4355c9456fc945eae7fe8797003c4da99212dd531ad1b0de8a0c6/pyobjc_framework_quartz-12.1.tar.gz", hash = "sha256:27f782f3513ac88ec9b6c82d9767eef95a5cf4175ce88a1e5a65875fee799608", size = 3159099, upload-time = "2025-11-14T10:21:24.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ef/dcd22b743e38b3c430fce4788176c2c5afa8bfb01085b8143b02d1e75201/pyobjc_framework_quartz-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:19f99ac49a0b15dd892e155644fe80242d741411a9ed9c119b18b7466048625a", size = 217795, upload-time = "2025-11-14T09:59:46.922Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9b/780f057e5962f690f23fdff1083a4cfda5a96d5b4d3bb49505cac4f624f2/pyobjc_framework_quartz-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7730cdce46c7e985535b5a42c31381af4aa6556e5642dc55b5e6597595e57a16", size = 218798, upload-time = "2025-11-14T10:00:01.236Z" }, + { url = "https://files.pythonhosted.org/packages/ba/2d/e8f495328101898c16c32ac10e7b14b08ff2c443a756a76fd1271915f097/pyobjc_framework_quartz-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:629b7971b1b43a11617f1460cd218bd308dfea247cd4ee3842eb40ca6f588860", size = 219206, upload-time = "2025-11-14T10:00:15.623Z" }, + { url = "https://files.pythonhosted.org/packages/67/43/b1f0ad3b842ab150a7e6b7d97f6257eab6af241b4c7d14cb8e7fde9214b8/pyobjc_framework_quartz-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:53b84e880c358ba1ddcd7e8d5ea0407d760eca58b96f0d344829162cda5f37b3", size = 224317, upload-time = "2025-11-14T10:00:30.703Z" }, + { url = "https://files.pythonhosted.org/packages/4a/00/96249c5c7e5aaca5f688ca18b8d8ad05cd7886ebd639b3c71a6a4cadbe75/pyobjc_framework_quartz-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:42d306b07f05ae7d155984503e0fb1b701fecd31dcc5c79fe8ab9790ff7e0de0", size = 219558, upload-time = "2025-11-14T10:00:45.476Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a6/708a55f3ff7a18c403b30a29a11dccfed0410485a7548c60a4b6d4cc0676/pyobjc_framework_quartz-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0cc08fddb339b2760df60dea1057453557588908e42bdc62184b6396ce2d6e9a", size = 224580, upload-time = "2025-11-14T10:01:00.091Z" }, +] + +[[package]] +name = "pyserial" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/7d/ae3f0a63f41e4d2f6cb66a5b57197850f919f59e558159a4dd3a818f5082/pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", size = 159125, upload-time = "2020-11-23T03:59:15.045Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0", size = 90585, upload-time = "2020-11-23T03:59:13.41Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, +] + +[[package]] +name = "pyusb" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/6b/ce3727395e52b7b76dfcf0c665e37d223b680b9becc60710d4bc08b7b7cb/pyusb-1.3.1.tar.gz", hash = "sha256:3af070b607467c1c164f49d5b0caabe8ac78dbed9298d703a8dbf9df4052d17e", size = 77281, upload-time = "2025-01-08T23:45:01.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/b8/27e6312e86408a44fe16bd28ee12dd98608b39f7e7e57884a24e8f29b573/pyusb-1.3.1-py3-none-any.whl", hash = "sha256:bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430", size = 58465, upload-time = "2025-01-08T23:45:00.029Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "reachy-mini" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "asgiref" }, + { name = "cv2-enumerate-cameras" }, + { name = "eclipse-zenoh" }, + { name = "fastapi" }, + { name = "huggingface-hub" }, + { name = "jinja2" }, + { name = "libusb-package" }, + { name = "log-throttling" }, + { name = "numpy" }, + { name = "opencv-python" }, + { name = "pip" }, + { name = "psutil" }, + { name = "pyserial" }, + { name = "pyusb" }, + { name = "reachy-mini-motor-controller" }, + { name = "reachy-mini-rust-kinematics" }, + { name = "scipy" }, + { name = "sounddevice" }, + { name = "soundfile" }, + { name = "uvicorn", extra = ["standard"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/6e/0ced70f87d1482a1e10d3b1cd0d72154013890e14c8b51a41fed696b78f1/reachy_mini-1.1.1.tar.gz", hash = "sha256:dfcac20e09869284bffc5e3243e4a3556eb9efd2ca1485ce752daabe4c5f74dc", size = 24573874, upload-time = "2025-11-25T18:03:18.583Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/41/4640e247a92f10d4e727ae50d158e44b277a7ac56cf53742fc08aec14b61/reachy_mini-1.1.1-py3-none-any.whl", hash = "sha256:9371fa52686c548817659a60170139520789be177315680465b4b6122f27fd61", size = 24632472, upload-time = "2025-11-25T18:03:15.914Z" }, +] + +[[package]] +name = "reachy-mini-motor-controller" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/8d/353b13636ebffae848c0d0b8c4bfc15c4673b059f62f9c310ee98986b0b7/reachy_mini_motor_controller-1.4.2.tar.gz", hash = "sha256:bd6e9f5c13394bc57478a09e76e01c28854ae0c80a9335a3a1b78dc80e0ee150", size = 28248, upload-time = "2025-11-25T17:56:55.263Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/20/ac97ac49969c02e0384888c73cccf0b50a7bba48b18842a96b082a8c8e89/reachy_mini_motor_controller-1.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f405d5f948abd26e423f156fc0d165b69ec964d3a4cbfa7d2d952313cc0ff972", size = 586684, upload-time = "2025-11-25T17:56:24.378Z" }, + { url = "https://files.pythonhosted.org/packages/68/21/796b9fd0616600b93d5b74ce2b4eb0f525f2773aae8635a8c0506a4145d7/reachy_mini_motor_controller-1.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:835e1d7e9383615b2684fb97cf18065f80498bb7d7d9ba980f8fe295cda68109", size = 572449, upload-time = "2025-11-25T17:56:17.627Z" }, + { url = "https://files.pythonhosted.org/packages/07/bd/661f6a44bd436c069d38ba0fdc1c1524178c4d039dcd4326fb1918bccf91/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8403bb4b6c23c088493967c8445e5cd1ec4784f5c2ae1dab289fb9ba456055b", size = 642034, upload-time = "2025-11-25T17:55:56.725Z" }, + { url = "https://files.pythonhosted.org/packages/cd/82/12b52b5eeee59387866db9370e43894f66dda8feedc15be38a6963be3e9a/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1cf6d2a6dc10b5f8acc4c61a89e2e201eca84c6be741becbf9775084d29fc6e", size = 647692, upload-time = "2025-11-25T17:56:02.499Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a0/4ad6ca320e303de61135219c3b9953b1ec1f7375181dbaaa98a43b65ecae/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a366aa59f9bde4f80f6c03757e431a3cea80f0b18992401169b484cf8928d14", size = 696265, upload-time = "2025-11-25T17:56:07.722Z" }, + { url = "https://files.pythonhosted.org/packages/8f/98/14cb24c497c295f91b11144bf639304116630de6862ba3095fe3a18dc3ff/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df475384deadcea1c8b430839addecb84126002d54649283cce5e6465d51b543", size = 660553, upload-time = "2025-11-25T17:56:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/c1/cb/9bc5c91075d5e551deb2d93fae89062bb94b5edd5f658b66c97c11c460d8/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e09e99bb325405f414013ce7d13f7ed36af5b9278dce2ee6bda9ea2affe6baf", size = 825331, upload-time = "2025-11-25T17:56:30.458Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/fd404636cb980604ed82dea5e7ec9c4de78a76324d36ff9efc55bb7549a7/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2f35c0b54ed396b8d9eb98dfe6dcc6d3b059433c2181030591dc84483531a25b", size = 911925, upload-time = "2025-11-25T17:56:36.802Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1c/6d48c4c3c5c9705e20265db04f040f42d1955cb0ded817e8915684999386/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:af23d02daff28470be0e775ce63666bea06ad24ce948649751f7122996d5363d", size = 854410, upload-time = "2025-11-25T17:56:43.296Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b8/55955b7b47c8ed65bda69a221cd4805bad3d07c3c95b7002e67deec43dff/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:610d74c3cfc28854137d00d206a6b4c4942a371376611781a244376fe3175277", size = 815823, upload-time = "2025-11-25T17:56:50.274Z" }, + { url = "https://files.pythonhosted.org/packages/12/7c/20672ab40d1d25cdddf49cb969bfa36043d9b760e4e82275a32853846192/reachy_mini_motor_controller-1.4.2-cp311-cp311-win32.whl", hash = "sha256:abe319839f78cc3e4e8ed0ced0bc519f97bfc1e6ff6b320dc8f84b772123237d", size = 377969, upload-time = "2025-11-25T17:57:02.781Z" }, + { url = "https://files.pythonhosted.org/packages/b5/5e/0725df6e698fe9a83eff0f86d61c5e62878c864ce521c1a1c12645409bc5/reachy_mini_motor_controller-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:d8f7ea29ca78ee86206989c30066e17b213f4cc8975f0a275f092588cd2debc8", size = 401027, upload-time = "2025-11-25T17:56:57.17Z" }, + { url = "https://files.pythonhosted.org/packages/e6/6a/af2786310d5ccf84a48ff0153c7be2346ef3730ca540b20d998020c36cb8/reachy_mini_motor_controller-1.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a41cc1bdc08b2fbba681804c6143319a6b4ef2d30093910f9776db01c5ba9595", size = 583808, upload-time = "2025-11-25T17:56:25.635Z" }, + { url = "https://files.pythonhosted.org/packages/dc/d3/6354fd9b34b89d2b5a639c56ae05f393d2ae7cef187bfcce60a71a40202d/reachy_mini_motor_controller-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af3cdd5197f57108044af81166dd755214f469c368e79221521b9a698da45223", size = 570332, upload-time = "2025-11-25T17:56:18.828Z" }, + { url = "https://files.pythonhosted.org/packages/da/eb/d30bc7517a2f7c860b95978af73beede33819e717978d5560f4b5b8a2953/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed2537a512098664d73a7575af763acd5446fc2325f37cf3b9b84d37368b5f7f", size = 641541, upload-time = "2025-11-25T17:55:58.117Z" }, + { url = "https://files.pythonhosted.org/packages/a4/63/8f9c091d0b210ebc6aa7762fa09155456a088df987d73dc39cda4fb9c241/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:554dd7392b9fef86cca8c12d5861d8f17e2eb7e1d69b49c65fbf54e1410f9567", size = 648054, upload-time = "2025-11-25T17:56:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/ac/15/a1bebc7acfcb02c12ba32e00dc1f9346fdf2468e441f983daf86ee4c7df3/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3f6ddd91e0228b3396f2c027f3e55eac0d3c4f280968ec73f2bdac37cdeda0", size = 696773, upload-time = "2025-11-25T17:56:08.895Z" }, + { url = "https://files.pythonhosted.org/packages/06/9f/a3ab6942383198e4c105075582c2355350ef33f90ef4f877105ada181e88/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0b357e49773bcd338e24ed17c4a93fb1890c97513c4cd07eec8c4f3ba06bc48", size = 660676, upload-time = "2025-11-25T17:56:13.77Z" }, + { url = "https://files.pythonhosted.org/packages/4c/09/7da09c39d2722d6323ed719de95f2f7777699b0049b81d25aaff9b0cc2db/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dd05b4bbf2aa30674b2955edf8fefbdb90b522077b3c549719afd4a1d2dd325b", size = 824841, upload-time = "2025-11-25T17:56:31.967Z" }, + { url = "https://files.pythonhosted.org/packages/97/68/2c4e8160a3d8e0e20a61ad491dccb9d17febbaa434da83e38060a7517fc9/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:377d47674a0429a01f509d9fe9b52365a715ca132bfdf4956a3b5bb219723941", size = 912195, upload-time = "2025-11-25T17:56:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/14/5f/a547e59efd62518afbb616c9e3bc2f057662fdd209f75b218ef1917bcd7b/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:742c1e077669c198a4261acf3213789ed679846a25714e74e9774984862bbc7a", size = 855751, upload-time = "2025-11-25T17:56:44.595Z" }, + { url = "https://files.pythonhosted.org/packages/76/58/8720be3e52e302052c6d10e3c0937271e8c376d6e5a10b2dac480c94c7f2/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9b2eb49965f2dba93a1d251b0beb4b22b81f5b18946d53ff8761097011ffaa43", size = 815778, upload-time = "2025-11-25T17:56:51.74Z" }, + { url = "https://files.pythonhosted.org/packages/aa/52/7af3228652ce3503243cbce68d736af00b11afd07f0f96effa6faaca677d/reachy_mini_motor_controller-1.4.2-cp312-cp312-win32.whl", hash = "sha256:e59bd6a1b89b94da835b1fbe3f483470ea0471fdb1b92d0d4bbb93a24ab7a1aa", size = 377018, upload-time = "2025-11-25T17:57:03.815Z" }, + { url = "https://files.pythonhosted.org/packages/a0/7a/090705f6e62ec10107ea20e78fd8b8f26f6421b9db49f7bf5e275084aa02/reachy_mini_motor_controller-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:ae99c65942130ce04a01d50dae359694a42fa91ede864ead0defd9a693b30b05", size = 399902, upload-time = "2025-11-25T17:56:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ac/fc016600786fbcdc8d048f7e42c946aa1a488e382e08b83e39934ee5f381/reachy_mini_motor_controller-1.4.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:43064e6c97be9f6fb2494ebf56dda18daa0366cd70b32ee548818c908d8b3564", size = 583599, upload-time = "2025-11-25T17:56:27.042Z" }, + { url = "https://files.pythonhosted.org/packages/07/c7/c79c33cf46bbe6301fef5520445649ce10a85a30754fce975df41f7b80b7/reachy_mini_motor_controller-1.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ebe3f763c011ecd3dc4bd017dfc886ecaf455d9866cab1ce8b81116d22eb6a3d", size = 570309, upload-time = "2025-11-25T17:56:20.391Z" }, + { url = "https://files.pythonhosted.org/packages/78/e0/d301987769c1504549c06cf0ce8e132df48bde0f47d28a8768c25b7ed8ae/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c86146d3631dd73efb77d591f8a33c288b9ad394d3a6805c0685f3c5ec05266f", size = 641472, upload-time = "2025-11-25T17:55:59.645Z" }, + { url = "https://files.pythonhosted.org/packages/ff/52/7884ee1c04b480f8e34b4c97697a0977d314a22f6766fd5e246dfbddb404/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36052e08d331ae768f4b562e950eaa767ae4ee8a91e9334498c1bcbafe841514", size = 648510, upload-time = "2025-11-25T17:56:05.286Z" }, + { url = "https://files.pythonhosted.org/packages/03/56/619bb25bb31f96d6172d1bfd5bbf516b5985b595f6e1c7c82481fff95c55/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b2ac6712f7a5493bb3be276fa53bb9b9e4770f13783f26ff0a18e7fc6f800d4", size = 697241, upload-time = "2025-11-25T17:56:09.99Z" }, + { url = "https://files.pythonhosted.org/packages/5a/b2/c82a31cf252ff6fb4d4c59a208d8375159cc796326812b7e946eea5c00a4/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fcb404dc2021175d4339fb3a8f9334cd999bf8a0369e0dacb02c430edf46a0b", size = 660207, upload-time = "2025-11-25T17:56:15.23Z" }, + { url = "https://files.pythonhosted.org/packages/83/6e/b2d9aecc4144cffcee14b023da20b8850a11cd35375561a7e60be7132e10/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f482f61eecdeb72a7722399d0d549872a239023c263968f9e2ffac9ee69687dc", size = 824941, upload-time = "2025-11-25T17:56:33.129Z" }, + { url = "https://files.pythonhosted.org/packages/c0/68/72b7d8a405fe7b1785b2caaaf917958dc6691015f6c15089bfee8b35f65d/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:88e1a5c1d4afe4e695d589715f0628536fe7399ec6d2751025dd785f4282a62e", size = 912805, upload-time = "2025-11-25T17:56:39.585Z" }, + { url = "https://files.pythonhosted.org/packages/c0/62/4ce77e08ea5dc428835202723671026f52d46e20ee2642af24ecd2c64858/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2d5c9e2645d7c6b29a8a46b4ecef72540bb2c0f983349cfcaf7c681386e7a002", size = 856256, upload-time = "2025-11-25T17:56:45.894Z" }, + { url = "https://files.pythonhosted.org/packages/71/a6/c031586c9dd8fc735b427c5fcdd20d9360c02a6c61ab3cbb59589ad15d9d/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffb5331150c0cdfac9910d341e82d788bc173e473e893e3f8e54938ede1e3523", size = 815565, upload-time = "2025-11-25T17:56:52.837Z" }, + { url = "https://files.pythonhosted.org/packages/c6/e3/5316b60491ecf3384b1b51db49317bc175561411edcc83fe1398b68736f4/reachy_mini_motor_controller-1.4.2-cp313-cp313-win32.whl", hash = "sha256:6edcf88f5d4c1bf3948328a6f65cd4518fda8cefbe55fb884fda088f363c2b60", size = 377394, upload-time = "2025-11-25T17:57:05.059Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/41f4efca4abaf31bff5fa891ae0f594623539afd936abea51e0e546a6700/reachy_mini_motor_controller-1.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:602cf3294f54ceae4fa84d006aa0e97dcfcd99f7ee556cbbcf3546ac42fe8fb3", size = 399788, upload-time = "2025-11-25T17:56:59.383Z" }, + { url = "https://files.pythonhosted.org/packages/3a/0b/3b118d1ed20da22c3844c88247a78f6fdee679fff149d0e1ee64fc5d8aa8/reachy_mini_motor_controller-1.4.2-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:aedcbebb270c3e6ad8898aac321f82a3d3060898ee33d75ae181b0f1df278f93", size = 581082, upload-time = "2025-11-25T17:56:28.189Z" }, + { url = "https://files.pythonhosted.org/packages/5a/e7/c24da5194f16714d6f2a67fefaba817e2a22f68f58269500fa4495d6a29e/reachy_mini_motor_controller-1.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4d8d7626e3655a96266cc88d9ae1327c8b42512b61e8acaeb782d8d3352125c2", size = 567918, upload-time = "2025-11-25T17:56:21.842Z" }, + { url = "https://files.pythonhosted.org/packages/89/69/cc9a51e04c1523213a8f4121bb1c454293d287f8c0fc4998e2640d053169/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8b27d6769f12a4bf75b8b6cb0e0dc20d154bc1422ff9e046f530434050552b86", size = 823910, upload-time = "2025-11-25T17:56:34.482Z" }, + { url = "https://files.pythonhosted.org/packages/cd/76/1f283234ec0fb1b349a24930485a9c584d94f064eb4d3d2e32e5607ec64e/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:07118c8cafed873541fb716928a3d4f807ac6ac7f769d7307faa4cd9bead6e6d", size = 910812, upload-time = "2025-11-25T17:56:40.804Z" }, + { url = "https://files.pythonhosted.org/packages/5c/22/771e3e02872c319f999c5e0830787c926d2b74b976c71f041d5429c4f785/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:d552fdf890c3040232b2db783fc03ffcee230b633208e62b7a4265fa5d076598", size = 856433, upload-time = "2025-11-25T17:56:47.095Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a3/c897ed4e7a43d205d43a985669dfbbc3943d1df8a101038c5384f34b9617/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4b250a7763a72d6864ef4cdcec088d56e4d17947a10493f7347f2001502f05ed", size = 816617, upload-time = "2025-11-25T17:56:54.099Z" }, + { url = "https://files.pythonhosted.org/packages/03/67/63dc13fe0fad1bafe12122b10479b2e22bb4562e58ed45e14f18b3f076c5/reachy_mini_motor_controller-1.4.2-cp314-cp314-win32.whl", hash = "sha256:d9a6be4852cb8cbec2e19d2037234dce39defce653f3af9d4a46cd56d624c617", size = 376862, upload-time = "2025-11-25T17:57:06.232Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/0c4b6fc4a761ad8bd362f571d3693c94aa0c15121e122f1c01e3f38bc873/reachy_mini_motor_controller-1.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:aa7b6ca1b6db09e6249fdb5a31376974e82928292950cd7df4480cbd5707a425", size = 400104, upload-time = "2025-11-25T17:57:00.616Z" }, +] + +[[package]] +name = "reachy-mini-rust-kinematics" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/82/485aa2f28973eee6198b2af0db9e76314fd909076f06782228fa686f0e3d/reachy_mini_rust_kinematics-1.0.2.tar.gz", hash = "sha256:ca14f9193c73a53612a32cd0bfb9abecb13343bc94fe5feb95f54736b7f3cd64", size = 17187, upload-time = "2025-10-22T08:35:50.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/fd/c3801f0579da40147c7cadc1226bc3f5b7413cc590b13f53822674a910f7/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b9fe481d3ae29415e9be3358493bd6d26add4b494650384c650181595da10204", size = 303080, upload-time = "2025-10-22T08:34:54.167Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5f/1b28508a05fde9bf80277222991273721462afa84a7a0ede6227692b6a75/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58c87c6cb62a020f325caf8344f003ba4ebb783e20f417c6d89e3b63a72bc8a1", size = 278691, upload-time = "2025-10-22T08:34:44.295Z" }, + { url = "https://files.pythonhosted.org/packages/de/22/9b4c4b007085db8fb329656146742414e64051d9deb8e108020fbb3aafa8/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af2f330760b5519dcf556c728ddaa889fbc1b5ef6d76a4f3ef2eee1ddd032cb4", size = 312649, upload-time = "2025-10-22T08:34:02.52Z" }, + { url = "https://files.pythonhosted.org/packages/c1/e7/b50b441d287e72864e32b1049ab6d740158a8330deba5ec2cfa62d5125e0/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d8bffa448b0a75a570c5b8625344de3a755bca7f3a7450b045df153cef0cb402", size = 321102, upload-time = "2025-10-22T08:34:14.669Z" }, + { url = "https://files.pythonhosted.org/packages/3b/4b/cddf709a7012450d3255d7ab6ee6a1216e761664657ffe68806712d95c42/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27ae0811ccc4132f9b034771af061c513bcb0bd18a73dad1d16abc6bad366caa", size = 337443, upload-time = "2025-10-22T08:34:35.544Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6d/908fca70c2dee3e066831fcde011fb0d8c563418c75e052208bc538105cb/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5777d235930be71186adf948388580317943a022aa3761d6f78bcffe7dfc5ee4", size = 351864, upload-time = "2025-10-22T08:34:26.064Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e8/ddbfbc71cc2a7246de06cd4a0e934c9613a3a814406afbf8dfcd071813bf/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cbf226d07d34a6a395635b90ebb4d6e083136f07ca2e746d4431c44b00fd2d5", size = 493208, upload-time = "2025-10-22T08:35:01.445Z" }, + { url = "https://files.pythonhosted.org/packages/75/d1/51af83f5b70c2eaf5f871efdf62c7d88116af2d5309898b2de9925857556/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bab5d550e2225c9d4d6ee69b98fd13cf75b8b3df4ab9824d7759668e04a6e5bf", size = 585005, upload-time = "2025-10-22T08:35:14.756Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a8/cef7d415d864c8fa04362485ecb1648947a194b90426d147972ce59f4263/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7fc0243f9abc3d14aadaaa19b86d4930bf1e3bace0bfbbde73048ed80928b0f5", size = 526789, upload-time = "2025-10-22T08:35:27.367Z" }, + { url = "https://files.pythonhosted.org/packages/d2/4e/98e8e72f3cf0758eb4e6eb7320438dfb9e08d6ff593f6cc3661e726cf9a1/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a060b9022becd8decf9868063099fe68e598f7c07406d96795408ca862d208b3", size = 498731, upload-time = "2025-10-22T08:35:38.944Z" }, + { url = "https://files.pythonhosted.org/packages/26/fc/d9b66b439ea27c20d01e6cc841b34b3a8cc17fb0e79acaaa8ba4f5a4c587/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-win32.whl", hash = "sha256:ebf961d3ae3cd0798ed8d4e2bec8aec57f33fe2fb713852ad0ba2de4386c9c1a", size = 176607, upload-time = "2025-10-22T08:35:58.496Z" }, + { url = "https://files.pythonhosted.org/packages/9b/be/848776e83114ee92d9799860860be6dff036f22c9d01e85805c02a6d05fc/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:8afa30ed7da49544c8215033d2375c2f76f3311a6a1f380fe9acd2c076f9d45f", size = 187332, upload-time = "2025-10-22T08:35:51.994Z" }, + { url = "https://files.pythonhosted.org/packages/11/39/6c40cca1970ce47d9ae1661c87230cd37a6e2d782f34e0aec745f155d831/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:356134c5df18a01226432fbd1fb24649aced5a14da3c0406ebe2d1b3b8c002d2", size = 299587, upload-time = "2025-10-22T08:34:55.208Z" }, + { url = "https://files.pythonhosted.org/packages/5c/30/f9ba417bc1782d6a256ef9024eb0329c50cb7a3d12e83afd4b67047a01d6/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a232408fb7c58d6da73c40a40a120bae4f51bf9119de108530572723a00280d7", size = 276656, upload-time = "2025-10-22T08:34:46.904Z" }, + { url = "https://files.pythonhosted.org/packages/75/e7/e3bb2597d86f2037a1e4537f2352d7e92ff4699ee725b43a90400f15894e/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e7c3d2c73f89bf817d8c3abb8f0b23a6efdfce330a749c6e29e1e0cf6db9d7d", size = 312798, upload-time = "2025-10-22T08:34:04.219Z" }, + { url = "https://files.pythonhosted.org/packages/62/2f/64d2c4b434ef413c948935a0f57b4a502cc7effad68dd97263cdee22df64/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba0faba18be71b68026c70ccf4db6d9ea588774053d22487f228b490204a8a00", size = 321023, upload-time = "2025-10-22T08:34:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/c8/0e/f4cbddd5c0ed10cdba7f4baffc68f2e8102eb1d55b309690a52af3b067f8/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bed2ec420ea354ce62572afe8672ae8701a139781d9d8da97932597907019ee", size = 337756, upload-time = "2025-10-22T08:34:36.66Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d5/ac043e65949ba904b7ac901d74b8514ab47203de3af44e96c44dd2da7a94/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a79f6517728463294d5ca4945b18d843dd16cc410815ce039b35c1198bdc355d", size = 351251, upload-time = "2025-10-22T08:34:27.06Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ef/80bb31cee07d2336013808ce3b76dee29ae04274f053e1694e3a285da555/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5404cf14cc8894962dbbc82594af453588539b4b9458b8f95f43c29bc8bd2e34", size = 493292, upload-time = "2025-10-22T08:35:02.56Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e2/4f6c5a0d2a77111a9806243160b1aa3531ad3024a59f05c7f6157917bcc5/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:2e1f9d9ce4222d7ecda5cb77c96fed763de3ac94993e60c73adf9749d26e16df", size = 584893, upload-time = "2025-10-22T08:35:15.981Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/b0b57c9c46b77aa3c03f4071fca0c92809e23f9b22df5f85446ec5329fe2/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7c29c3d7b70d0576c740969cfa3e35ba98cc8e378c0867a79f53d5fee3568f77", size = 525948, upload-time = "2025-10-22T08:35:28.451Z" }, + { url = "https://files.pythonhosted.org/packages/06/12/f4d94e8c0b1b19b47072c2041f31fb83701cff1a199d0fcf012c0489f32f/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5b94ca8e94058efcd89553144b0a0b0f7c4abfe67a4cd60e2993cd0833c9e130", size = 499239, upload-time = "2025-10-22T08:35:40.026Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b6/907870cb3f588a6da58b64357c03241a28dac8a9ec9f42e91c291cb95c51/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-win32.whl", hash = "sha256:edcbcedaa4aa99684588bd897733a33ff8f8d9eed8ae39bd7d0fd691874f0457", size = 176379, upload-time = "2025-10-22T08:35:59.841Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c0/a5c1db0bf8dc55cf6b41a11463285ef440a2efa74d8b75be8443234c1acf/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:eb5d6d27ce08e8816496b6049979cf64ffbf3901dd5bb290efe439f5455526c2", size = 187469, upload-time = "2025-10-22T08:35:53.307Z" }, + { url = "https://files.pythonhosted.org/packages/13/5c/fffb02be21f666cf880042804c703de2410f32a44b0412d6df20bb156d15/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2aae2b9424a111935e26977fe2ab25c130c766e8049d72073e31a7ad78c84fb5", size = 299868, upload-time = "2025-10-22T08:34:56.48Z" }, + { url = "https://files.pythonhosted.org/packages/a3/33/b7e610c6325ed4fe439bd0be3e96850b5a5b6dc360116741bdf4c3a57ce9/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38ba383417c472ac67945a57c62ba621128b4486bd9d818512929454f47ce76d", size = 276655, upload-time = "2025-10-22T08:34:47.905Z" }, + { url = "https://files.pythonhosted.org/packages/93/bf/a1f579e4a6930b2155c99f80ac5b96d256c0047537c0802c34f0adfcde81/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3788d9c5b5315eff026486c3367e97ea23cd4ccd3eb6c7c1e37e0d00ec6b7128", size = 312962, upload-time = "2025-10-22T08:34:05.504Z" }, + { url = "https://files.pythonhosted.org/packages/89/cf/bf2a450adb2e6fbc5a9baa3ad9bece4d7272341723f4e76eff710463b484/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6983b555c1af6fd2c1ca8b32ae374c2b060239bb04b9b562806771ddafe81abf", size = 320871, upload-time = "2025-10-22T08:34:16.889Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ad/1eab50e3c56a65ac2f14a4890ae5370984586f52adf13cd8a7963ebf423c/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca28a8cda1ab4973259ed9aa06c7173ac5899492a3140075c58225a0ed96be52", size = 337653, upload-time = "2025-10-22T08:34:37.679Z" }, + { url = "https://files.pythonhosted.org/packages/a0/ce/8d3802dde54f9595daa9bd7b12a3de42ba4b4b48d92d8abe7a43919d74a8/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c8591616ef354d4f0724affef58eb14374f4a06b649b7947e94b97ec22d2fb9", size = 351553, upload-time = "2025-10-22T08:34:28.126Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/5e1de72d044440afb8cb7480af0c9ddcdcd9654b0ac62c11113fedc731d4/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45f4d9f159714e60eef22c9c00232beb34a8d27a89acce7d3ffcec2b86992b06", size = 493556, upload-time = "2025-10-22T08:35:03.963Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8b/1a33d934b9720586dc261349b500fb6a969ff1d3ba7c6f9bb7ba87d61d37/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:02a525696238dc85e9a1f3260d7d0db25074bb54f1cc2a0a4052849344026806", size = 585019, upload-time = "2025-10-22T08:35:17.344Z" }, + { url = "https://files.pythonhosted.org/packages/b9/5e/8cf4011456e3262f2a67b66ee77838cc56655cdcd7941efd44cb6ff8eb85/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:342b4a9adb9714f98d6569121c053800ae0a5b3904a9863ca65603bb3b9e7f0a", size = 526143, upload-time = "2025-10-22T08:35:29.636Z" }, + { url = "https://files.pythonhosted.org/packages/0f/3e/0d1168324c288693c07abd0050b83f682cf12a27c850e42d2601d3da84ef/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b596910a1ba0aaf79fc525ec5a8405dcd41c28946667faa549e789e5c1b93a5", size = 499284, upload-time = "2025-10-22T08:35:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/66/4e/0f69c0287a9289a0bc78d623cbf8cbd652e54ff6e854979b4985eb7fa75e/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-win32.whl", hash = "sha256:d5437b5d7f9093e879859d83da6888738f281fe728fad0a9f1678fe01035b4d3", size = 176631, upload-time = "2025-10-22T08:36:00.974Z" }, + { url = "https://files.pythonhosted.org/packages/94/00/eff3fa6480da3c2b486b8bcec55ea650b4955fb874664e9e7dce205a9885/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:c3c813012eacc7e779c81388f3dcb30811bee461672f9f9dc03835c73e3a5bc4", size = 187334, upload-time = "2025-10-22T08:35:54.464Z" }, + { url = "https://files.pythonhosted.org/packages/0a/e2/2c19fbf08a5e3836147ee345b9d75fbe1cd26df8d1f9e83b9cefa4bc80ae/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e1f563b31cbb0e0ee9f015801ef2eba31b9c37c306e3ca7737097a482355e0a", size = 312043, upload-time = "2025-10-22T08:34:06.505Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d4/873c4317a598e9709dd2aa68f0a072568b1f2db3616a2ffa76259618889e/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:874b986c44a94e1e1752f8f0b159342b0f60d4610e4df9c4bdf421e2749d949e", size = 320190, upload-time = "2025-10-22T08:34:17.889Z" }, + { url = "https://files.pythonhosted.org/packages/1f/11/64941229b39bfb1c39ea2ccb5fd02998915f87e40e277e4b0b744a2c3a2b/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f5060865aba96d3ffe1ac5cb93dc6439154a78ef8fdbb8a4313e4dc33064efb5", size = 492437, upload-time = "2025-10-22T08:35:05.014Z" }, + { url = "https://files.pythonhosted.org/packages/20/47/82704725e0d5cae887a4604e9bbf7688e6a676768ab47202b018ef9f7f32/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f7ddeef8610a936afbfd7dda1713be18d207032e18604e46963729996c3d1a41", size = 583980, upload-time = "2025-10-22T08:35:18.517Z" }, + { url = "https://files.pythonhosted.org/packages/97/6d/bfcdc6912531c62885450646f629aa581fb116ee5806dba00c01712b02f4/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2f498398c933e87a63a5747a2c813df09dcb68ded3ba79f86d092801ced36da8", size = 525181, upload-time = "2025-10-22T08:35:30.819Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6d/4f32bc65f83307a6eba5b62231e276bde8509d26dd8ba1a9997fb6c4b924/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6464868b209ec5cc0e50829b25bdad8cf765a48c943a5a7f504a3ec4ed7aedcb", size = 498743, upload-time = "2025-10-22T08:35:42.183Z" }, + { url = "https://files.pythonhosted.org/packages/85/26/2af509eb72c556a5f8628454122f61bcd55ae760ed74c2a1d8cfe21ebafe/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:419cba0b2ca01b52aba79004681201e1ad16d5a06a2ae9f4f74c45ea82e88f11", size = 276979, upload-time = "2025-10-22T08:34:49.023Z" }, + { url = "https://files.pythonhosted.org/packages/82/62/5fdf253c4293447fe2b95329891a46292fed02fd15f71a7eafbcca842194/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c654f6e06da8c6f8f5f2613c7a8d1841dca730ba2397125418f1b26bfeb46330", size = 337650, upload-time = "2025-10-22T08:34:38.745Z" }, + { url = "https://files.pythonhosted.org/packages/01/2e/eee9bed34de89569f52965fdbf6bd16c914c1b87f4f233e49ffa1f3f0590/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:58a36591b27a80c0836ab08ff21bf605413213f079baeef6fd1e3d6b47d8a341", size = 352082, upload-time = "2025-10-22T08:34:29.451Z" }, + { url = "https://files.pythonhosted.org/packages/bc/2d/c4492e19625f81348c812e5e17e97e777c521fe7200006bc41ebc904dd14/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305793e3097db1a93eabeeb5bcf7a581dedb859740d5f5164d7f2b695ce90953", size = 312932, upload-time = "2025-10-22T08:34:11.265Z" }, + { url = "https://files.pythonhosted.org/packages/9a/b2/d6cdc7960650c609b3e902734dcd10d6eb44373ba4f0aadaefde401244ba/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dda63846d7196737bad42d9de847b3c4702e68e40fc0a691fed50a87b9ef0898", size = 321183, upload-time = "2025-10-22T08:34:22.468Z" }, + { url = "https://files.pythonhosted.org/packages/51/74/d92143a61237d3f83ba9f6398f7d546cdefd8d43f820677bcf4d7ed3a265/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b307111f6ff46a1e8dc5b0d600c836ccf237106cf0bb9b87d85e079199fb733", size = 337577, upload-time = "2025-10-22T08:34:42.092Z" }, + { url = "https://files.pythonhosted.org/packages/05/e4/5ab1e64bd201e388f3fc0bb1ee89ef166479c8482d582ee58d603ba1b6ba/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64649a8ca74f3f528d57adf02f3b5ad6eaab4e5ab40bf837554ad878f0f4ea64", size = 351547, upload-time = "2025-10-22T08:34:33.109Z" }, + { url = "https://files.pythonhosted.org/packages/5f/19/f754c4cac653d3133145694abb6bb2d0da15b2459c1361b35528b3d16287/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6f0eda0e6cb8d86e80937a78b44e3db5e338039480fc077503aca3c23af008e6", size = 493554, upload-time = "2025-10-22T08:35:10.535Z" }, + { url = "https://files.pythonhosted.org/packages/af/81/14e1848dc1fb662a9dd8108bb3be4161a241055d38bac65eb9ee1fe5926c/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:12b9c538544352ee829338b3ae34623e3903294cd09ebb286f9467cad9882360", size = 585142, upload-time = "2025-10-22T08:35:23.413Z" }, + { url = "https://files.pythonhosted.org/packages/bb/47/a74608d37b58a162a3204ad4a1b7981ca79dc598b6c76533922cdc2bcb48/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:56eb81ad90e2b04506b4adf809b48a449fbd3972e2b32bd49038b745a6ff2d38", size = 526427, upload-time = "2025-10-22T08:35:35.379Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8e/c48f621c8d954849deb081a7a8840c57e38385dad999aaf5b82e10a09f84/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2af9062ffb5970b3318a85eaa7ce78042e7b023e7c096e34002da5aa083920dd", size = 499551, upload-time = "2025-10-22T08:35:47.616Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "rmscript" +version = "0.1.0" +source = { directory = "../../rmscript" } +dependencies = [ + { name = "numpy" }, + { name = "reachy-mini" }, +] + +[package.metadata] +requires-dist = [ + { name = "numpy", specifier = ">=1.24.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, + { name = "reachy-mini", specifier = ">=1.0.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, + { name = "scipy", marker = "extra == 'dev'", specifier = ">=1.10.0" }, +] +provides-extras = ["dev"] + +[[package]] +name = "rmscript-web-backend" +version = "1.0.0" +source = { editable = "." } +dependencies = [ + { name = "fastapi" }, + { name = "pydantic" }, + { name = "rmscript" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[package.metadata] +requires-dist = [ + { name = "fastapi", specifier = ">=0.104.0" }, + { name = "pydantic", specifier = ">=2.4.0" }, + { name = "rmscript", extras = ["reachy", "scipy"], directory = "../../rmscript" }, + { name = "uvicorn", extras = ["standard"], specifier = ">=0.24.0" }, +] + +[[package]] +name = "scipy" +version = "1.16.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/5f/6f37d7439de1455ce9c5a556b8d1db0979f03a796c030bafdf08d35b7bf9/scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97", size = 36630881, upload-time = "2025-10-28T17:31:47.104Z" }, + { url = "https://files.pythonhosted.org/packages/7c/89/d70e9f628749b7e4db2aa4cd89735502ff3f08f7b9b27d2e799485987cd9/scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511", size = 28941012, upload-time = "2025-10-28T17:31:53.411Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a8/0e7a9a6872a923505dbdf6bb93451edcac120363131c19013044a1e7cb0c/scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005", size = 20931935, upload-time = "2025-10-28T17:31:57.361Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c7/020fb72bd79ad798e4dbe53938543ecb96b3a9ac3fe274b7189e23e27353/scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb", size = 23534466, upload-time = "2025-10-28T17:32:01.875Z" }, + { url = "https://files.pythonhosted.org/packages/be/a0/668c4609ce6dbf2f948e167836ccaf897f95fb63fa231c87da7558a374cd/scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876", size = 33593618, upload-time = "2025-10-28T17:32:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6e/8942461cf2636cdae083e3eb72622a7fbbfa5cf559c7d13ab250a5dbdc01/scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2", size = 35899798, upload-time = "2025-10-28T17:32:12.665Z" }, + { url = "https://files.pythonhosted.org/packages/79/e8/d0f33590364cdbd67f28ce79368b373889faa4ee959588beddf6daef9abe/scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e", size = 36226154, upload-time = "2025-10-28T17:32:17.961Z" }, + { url = "https://files.pythonhosted.org/packages/39/c1/1903de608c0c924a1749c590064e65810f8046e437aba6be365abc4f7557/scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733", size = 38878540, upload-time = "2025-10-28T17:32:23.907Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d0/22ec7036ba0b0a35bccb7f25ab407382ed34af0b111475eb301c16f8a2e5/scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78", size = 38722107, upload-time = "2025-10-28T17:32:29.921Z" }, + { url = "https://files.pythonhosted.org/packages/7b/60/8a00e5a524bb3bf8898db1650d350f50e6cffb9d7a491c561dc9826c7515/scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184", size = 25506272, upload-time = "2025-10-28T17:32:34.577Z" }, + { url = "https://files.pythonhosted.org/packages/40/41/5bf55c3f386b1643812f3a5674edf74b26184378ef0f3e7c7a09a7e2ca7f/scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6", size = 36659043, upload-time = "2025-10-28T17:32:40.285Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0f/65582071948cfc45d43e9870bf7ca5f0e0684e165d7c9ef4e50d783073eb/scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07", size = 28898986, upload-time = "2025-10-28T17:32:45.325Z" }, + { url = "https://files.pythonhosted.org/packages/96/5e/36bf3f0ac298187d1ceadde9051177d6a4fe4d507e8f59067dc9dd39e650/scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9", size = 20889814, upload-time = "2025-10-28T17:32:49.277Z" }, + { url = "https://files.pythonhosted.org/packages/80/35/178d9d0c35394d5d5211bbff7ac4f2986c5488b59506fef9e1de13ea28d3/scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686", size = 23565795, upload-time = "2025-10-28T17:32:53.337Z" }, + { url = "https://files.pythonhosted.org/packages/fa/46/d1146ff536d034d02f83c8afc3c4bab2eddb634624d6529a8512f3afc9da/scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203", size = 33349476, upload-time = "2025-10-28T17:32:58.353Z" }, + { url = "https://files.pythonhosted.org/packages/79/2e/415119c9ab3e62249e18c2b082c07aff907a273741b3f8160414b0e9193c/scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1", size = 35676692, upload-time = "2025-10-28T17:33:03.88Z" }, + { url = "https://files.pythonhosted.org/packages/27/82/df26e44da78bf8d2aeaf7566082260cfa15955a5a6e96e6a29935b64132f/scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe", size = 36019345, upload-time = "2025-10-28T17:33:09.773Z" }, + { url = "https://files.pythonhosted.org/packages/82/31/006cbb4b648ba379a95c87262c2855cd0d09453e500937f78b30f02fa1cd/scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70", size = 38678975, upload-time = "2025-10-28T17:33:15.809Z" }, + { url = "https://files.pythonhosted.org/packages/c2/7f/acbd28c97e990b421af7d6d6cd416358c9c293fc958b8529e0bd5d2a2a19/scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc", size = 38555926, upload-time = "2025-10-28T17:33:21.388Z" }, + { url = "https://files.pythonhosted.org/packages/ce/69/c5c7807fd007dad4f48e0a5f2153038dc96e8725d3345b9ee31b2b7bed46/scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2", size = 25463014, upload-time = "2025-10-28T17:33:25.975Z" }, + { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" }, + { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" }, + { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" }, + { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" }, + { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" }, + { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" }, + { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" }, + { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" }, + { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" }, + { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" }, + { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" }, + { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" }, + { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" }, + { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" }, + { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" }, + { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" }, + { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" }, + { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" }, + { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" }, + { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" }, + { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" }, + { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" }, + { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" }, + { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" }, + { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, +] + +[[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 = "sounddevice" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/2d/b04ae180312b81dbb694504bee170eada5372242e186f6298139fd3a0513/sounddevice-0.5.1.tar.gz", hash = "sha256:09ca991daeda8ce4be9ac91e15a9a81c8f81efa6b695a348c9171ea0c16cb041", size = 52896, upload-time = "2024-10-12T09:40:12.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/d1/464b5fca3decdd0cfec8c47f7b4161a0b12972453201c1bf03811f367c5e/sounddevice-0.5.1-py3-none-any.whl", hash = "sha256:e2017f182888c3f3c280d9fbac92e5dbddac024a7e3442f6e6116bd79dab8a9c", size = 32276, upload-time = "2024-10-12T09:40:05.605Z" }, + { url = "https://files.pythonhosted.org/packages/6f/f6/6703fe7cf3d7b7279040c792aeec6334e7305956aba4a80f23e62c8fdc44/sounddevice-0.5.1-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d16cb23d92322526a86a9490c427bf8d49e273d9ccc0bd096feecd229cde6031", size = 107916, upload-time = "2024-10-12T09:40:07.436Z" }, + { url = "https://files.pythonhosted.org/packages/57/a5/78a5e71f5ec0faedc54f4053775d61407bfbd7d0c18228c7f3d4252fd276/sounddevice-0.5.1-py3-none-win32.whl", hash = "sha256:d84cc6231526e7a08e89beff229c37f762baefe5e0cc2747cbe8e3a565470055", size = 312494, upload-time = "2024-10-12T09:40:09.355Z" }, + { url = "https://files.pythonhosted.org/packages/af/9b/15217b04f3b36d30de55fef542389d722de63f1ad81f9c72d8afc98cb6ab/sounddevice-0.5.1-py3-none-win_amd64.whl", hash = "sha256:4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1", size = 363634, upload-time = "2024-10-12T09:40:11.065Z" }, +] + +[[package]] +name = "soundfile" +version = "0.13.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/41/9b873a8c055582859b239be17902a85339bec6a30ad162f98c9b0288a2cc/soundfile-0.13.1.tar.gz", hash = "sha256:b2c68dab1e30297317080a5b43df57e302584c49e2942defdde0acccc53f0e5b", size = 46156, upload-time = "2025-01-25T09:17:04.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/28/e2a36573ccbcf3d57c00626a21fe51989380636e821b341d36ccca0c1c3a/soundfile-0.13.1-py2.py3-none-any.whl", hash = "sha256:a23c717560da2cf4c7b5ae1142514e0fd82d6bbd9dfc93a50423447142f2c445", size = 25751, upload-time = "2025-01-25T09:16:44.235Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ab/73e97a5b3cc46bba7ff8650a1504348fa1863a6f9d57d7001c6b67c5f20e/soundfile-0.13.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:82dc664d19831933fe59adad199bf3945ad06d84bc111a5b4c0d3089a5b9ec33", size = 1142250, upload-time = "2025-01-25T09:16:47.583Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e5/58fd1a8d7b26fc113af244f966ee3aecf03cb9293cb935daaddc1e455e18/soundfile-0.13.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:743f12c12c4054921e15736c6be09ac26b3b3d603aef6fd69f9dde68748f2593", size = 1101406, upload-time = "2025-01-25T09:16:49.662Z" }, + { url = "https://files.pythonhosted.org/packages/58/ae/c0e4a53d77cf6e9a04179535766b3321b0b9ced5f70522e4caf9329f0046/soundfile-0.13.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9c9e855f5a4d06ce4213f31918653ab7de0c5a8d8107cd2427e44b42df547deb", size = 1235729, upload-time = "2025-01-25T09:16:53.018Z" }, + { url = "https://files.pythonhosted.org/packages/57/5e/70bdd9579b35003a489fc850b5047beeda26328053ebadc1fb60f320f7db/soundfile-0.13.1-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:03267c4e493315294834a0870f31dbb3b28a95561b80b134f0bd3cf2d5f0e618", size = 1313646, upload-time = "2025-01-25T09:16:54.872Z" }, + { url = "https://files.pythonhosted.org/packages/fe/df/8c11dc4dfceda14e3003bb81a0d0edcaaf0796dd7b4f826ea3e532146bba/soundfile-0.13.1-py2.py3-none-win32.whl", hash = "sha256:c734564fab7c5ddf8e9be5bf70bab68042cd17e9c214c06e365e20d64f9a69d5", size = 899881, upload-time = "2025-01-25T09:16:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/14/e9/6b761de83277f2f02ded7e7ea6f07828ec78e4b229b80e4ca55dd205b9dc/soundfile-0.13.1-py2.py3-none-win_amd64.whl", hash = "sha256:1e70a05a0626524a69e9f0f4dd2ec174b4e9567f4d8b6c11d38b5c289be36ee9", size = 1019162, upload-time = "2025-01-25T09:16:59.573Z" }, +] + +[[package]] +name = "starlette" +version = "0.50.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[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 = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/f06b84e2697fef4688ca63bdb2fdf113ca0a3be33f94488f2cadb690b0cf/uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d", size = 80605, upload-time = "2025-10-18T13:46:44.63Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109, upload-time = "2025-10-18T13:46:42.958Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9", size = 1352420, upload-time = "2025-10-16T22:16:21.187Z" }, + { url = "https://files.pythonhosted.org/packages/a8/73/c4e271b3bce59724e291465cc936c37758886a4868787da0278b3b56b905/uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77", size = 748677, upload-time = "2025-10-16T22:16:22.558Z" }, + { url = "https://files.pythonhosted.org/packages/86/94/9fb7fad2f824d25f8ecac0d70b94d0d48107ad5ece03769a9c543444f78a/uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21", size = 3753819, upload-time = "2025-10-16T22:16:23.903Z" }, + { url = "https://files.pythonhosted.org/packages/74/4f/256aca690709e9b008b7108bc85fba619a2bc37c6d80743d18abad16ee09/uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702", size = 3804529, upload-time = "2025-10-16T22:16:25.246Z" }, + { url = "https://files.pythonhosted.org/packages/7f/74/03c05ae4737e871923d21a76fe28b6aad57f5c03b6e6bfcfa5ad616013e4/uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733", size = 3621267, upload-time = "2025-10-16T22:16:26.819Z" }, + { url = "https://files.pythonhosted.org/packages/75/be/f8e590fe61d18b4a92070905497aec4c0e64ae1761498cad09023f3f4b3e/uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473", size = 3723105, upload-time = "2025-10-16T22:16:28.252Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, + { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, + { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" }, + { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/60249e9fd07b32c665192cec7af29e06c7cd96fa1d08b84f012a56a0b38e/uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25", size = 4292101, upload-time = "2025-10-16T22:16:49.318Z" }, + { url = "https://files.pythonhosted.org/packages/02/62/67d382dfcb25d0a98ce73c11ed1a6fba5037a1a1d533dcbb7cab033a2636/uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6", size = 4114158, upload-time = "2025-10-16T22:16:50.517Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/f1171b4a882a5d13c8b7576f348acfe6074d72eaf52cccef752f748d4a9f/uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079", size = 4177360, upload-time = "2025-10-16T22:16:52.646Z" }, + { url = "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289", size = 1454790, upload-time = "2025-10-16T22:16:54.355Z" }, + { url = "https://files.pythonhosted.org/packages/d4/31/0bb232318dd838cad3fa8fb0c68c8b40e1145b32025581975e18b11fab40/uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3", size = 796783, upload-time = "2025-10-16T22:16:55.906Z" }, + { url = "https://files.pythonhosted.org/packages/42/38/c9b09f3271a7a723a5de69f8e237ab8e7803183131bc57c890db0b6bb872/uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c", size = 4647548, upload-time = "2025-10-16T22:16:57.008Z" }, + { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" }, + { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f8/2c5f479fb531ce2f0564eda479faecf253d886b1ab3630a39b7bf7362d46/watchfiles-1.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f57b396167a2565a4e8b5e56a5a1c537571733992b226f4f1197d79e94cf0ae5", size = 406529, upload-time = "2025-10-14T15:04:32.899Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cd/f515660b1f32f65df671ddf6f85bfaca621aee177712874dc30a97397977/watchfiles-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:421e29339983e1bebc281fab40d812742268ad057db4aee8c4d2bce0af43b741", size = 394384, upload-time = "2025-10-14T15:04:33.761Z" }, + { url = "https://files.pythonhosted.org/packages/7b/c3/28b7dc99733eab43fca2d10f55c86e03bd6ab11ca31b802abac26b23d161/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e43d39a741e972bab5d8100b5cdacf69db64e34eb19b6e9af162bccf63c5cc6", size = 448789, upload-time = "2025-10-14T15:04:34.679Z" }, + { url = "https://files.pythonhosted.org/packages/4a/24/33e71113b320030011c8e4316ccca04194bf0cbbaeee207f00cbc7d6b9f5/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f537afb3276d12814082a2e9b242bdcf416c2e8fd9f799a737990a1dbe906e5b", size = 460521, upload-time = "2025-10-14T15:04:35.963Z" }, + { url = "https://files.pythonhosted.org/packages/f4/c3/3c9a55f255aa57b91579ae9e98c88704955fa9dac3e5614fb378291155df/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2cd9e04277e756a2e2d2543d65d1e2166d6fd4c9b183f8808634fda23f17b14", size = 488722, upload-time = "2025-10-14T15:04:37.091Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/506447b73eb46c120169dc1717fe2eff07c234bb3232a7200b5f5bd816e9/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3f58818dc0b07f7d9aa7fe9eb1037aecb9700e63e1f6acfed13e9fef648f5d", size = 596088, upload-time = "2025-10-14T15:04:38.39Z" }, + { url = "https://files.pythonhosted.org/packages/82/ab/5f39e752a9838ec4d52e9b87c1e80f1ee3ccdbe92e183c15b6577ab9de16/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb9f66367023ae783551042d31b1d7fd422e8289eedd91f26754a66f44d5cff", size = 472923, upload-time = "2025-10-14T15:04:39.666Z" }, + { url = "https://files.pythonhosted.org/packages/af/b9/a419292f05e302dea372fa7e6fda5178a92998411f8581b9830d28fb9edb/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aebfd0861a83e6c3d1110b78ad54704486555246e542be3e2bb94195eabb2606", size = 456080, upload-time = "2025-10-14T15:04:40.643Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c3/d5932fd62bde1a30c36e10c409dc5d54506726f08cb3e1d8d0ba5e2bc8db/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5fac835b4ab3c6487b5dbad78c4b3724e26bcc468e886f8ba8cc4306f68f6701", size = 629432, upload-time = "2025-10-14T15:04:41.789Z" }, + { url = "https://files.pythonhosted.org/packages/f7/77/16bddd9779fafb795f1a94319dc965209c5641db5bf1edbbccace6d1b3c0/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:399600947b170270e80134ac854e21b3ccdefa11a9529a3decc1327088180f10", size = 623046, upload-time = "2025-10-14T15:04:42.718Z" }, + { url = "https://files.pythonhosted.org/packages/46/ef/f2ecb9a0f342b4bfad13a2787155c6ee7ce792140eac63a34676a2feeef2/watchfiles-1.1.1-cp311-cp311-win32.whl", hash = "sha256:de6da501c883f58ad50db3a32ad397b09ad29865b5f26f64c24d3e3281685849", size = 271473, upload-time = "2025-10-14T15:04:43.624Z" }, + { url = "https://files.pythonhosted.org/packages/94/bc/f42d71125f19731ea435c3948cad148d31a64fccde3867e5ba4edee901f9/watchfiles-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:35c53bd62a0b885bf653ebf6b700d1bf05debb78ad9292cf2a942b23513dc4c4", size = 287598, upload-time = "2025-10-14T15:04:44.516Z" }, + { url = "https://files.pythonhosted.org/packages/57/c9/a30f897351f95bbbfb6abcadafbaca711ce1162f4db95fc908c98a9165f3/watchfiles-1.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:57ca5281a8b5e27593cb7d82c2ac927ad88a96ed406aa446f6344e4328208e9e", size = 277210, upload-time = "2025-10-14T15:04:45.883Z" }, + { url = "https://files.pythonhosted.org/packages/74/d5/f039e7e3c639d9b1d09b07ea412a6806d38123f0508e5f9b48a87b0a76cc/watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d", size = 404745, upload-time = "2025-10-14T15:04:46.731Z" }, + { url = "https://files.pythonhosted.org/packages/a5/96/a881a13aa1349827490dab2d363c8039527060cfcc2c92cc6d13d1b1049e/watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610", size = 391769, upload-time = "2025-10-14T15:04:48.003Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5b/d3b460364aeb8da471c1989238ea0e56bec24b6042a68046adf3d9ddb01c/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af", size = 449374, upload-time = "2025-10-14T15:04:49.179Z" }, + { url = "https://files.pythonhosted.org/packages/b9/44/5769cb62d4ed055cb17417c0a109a92f007114a4e07f30812a73a4efdb11/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6", size = 459485, upload-time = "2025-10-14T15:04:50.155Z" }, + { url = "https://files.pythonhosted.org/packages/19/0c/286b6301ded2eccd4ffd0041a1b726afda999926cf720aab63adb68a1e36/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce", size = 488813, upload-time = "2025-10-14T15:04:51.059Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2b/8530ed41112dd4a22f4dcfdb5ccf6a1baad1ff6eed8dc5a5f09e7e8c41c7/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa", size = 594816, upload-time = "2025-10-14T15:04:52.031Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d2/f5f9fb49489f184f18470d4f99f4e862a4b3e9ac2865688eb2099e3d837a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb", size = 475186, upload-time = "2025-10-14T15:04:53.064Z" }, + { url = "https://files.pythonhosted.org/packages/cf/68/5707da262a119fb06fbe214d82dd1fe4a6f4af32d2d14de368d0349eb52a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803", size = 456812, upload-time = "2025-10-14T15:04:55.174Z" }, + { url = "https://files.pythonhosted.org/packages/66/ab/3cbb8756323e8f9b6f9acb9ef4ec26d42b2109bce830cc1f3468df20511d/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94", size = 630196, upload-time = "2025-10-14T15:04:56.22Z" }, + { url = "https://files.pythonhosted.org/packages/78/46/7152ec29b8335f80167928944a94955015a345440f524d2dfe63fc2f437b/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43", size = 622657, upload-time = "2025-10-14T15:04:57.521Z" }, + { url = "https://files.pythonhosted.org/packages/0a/bf/95895e78dd75efe9a7f31733607f384b42eb5feb54bd2eb6ed57cc2e94f4/watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9", size = 272042, upload-time = "2025-10-14T15:04:59.046Z" }, + { url = "https://files.pythonhosted.org/packages/87/0a/90eb755f568de2688cb220171c4191df932232c20946966c27a59c400850/watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9", size = 288410, upload-time = "2025-10-14T15:05:00.081Z" }, + { url = "https://files.pythonhosted.org/packages/36/76/f322701530586922fbd6723c4f91ace21364924822a8772c549483abed13/watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404", size = 278209, upload-time = "2025-10-14T15:05:01.168Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, + { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, + { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, + { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, + { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, + { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, + { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, + { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, + { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, + { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, + { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, + { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, + { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, + { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" }, + { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" }, + { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" }, + { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" }, + { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" }, + { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" }, + { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" }, + { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" }, + { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" }, + { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" }, + { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" }, + { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, + { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, + { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8e/e500f8b0b77be4ff753ac94dc06b33d8f0d839377fee1b78e8c8d8f031bf/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db476ab59b6765134de1d4fe96a1a9c96ddf091683599be0f26147ea1b2e4b88", size = 408250, upload-time = "2025-10-14T15:06:10.264Z" }, + { url = "https://files.pythonhosted.org/packages/bd/95/615e72cd27b85b61eec764a5ca51bd94d40b5adea5ff47567d9ebc4d275a/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89eef07eee5e9d1fda06e38822ad167a044153457e6fd997f8a858ab7564a336", size = 396117, upload-time = "2025-10-14T15:06:11.28Z" }, + { url = "https://files.pythonhosted.org/packages/c9/81/e7fe958ce8a7fb5c73cc9fb07f5aeaf755e6aa72498c57d760af760c91f8/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce19e06cbda693e9e7686358af9cd6f5d61312ab8b00488bc36f5aabbaf77e24", size = 450493, upload-time = "2025-10-14T15:06:12.321Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" }, +] + +[[package]] +name = "websockets" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +] + +[[package]] +name = "yarl" +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, + { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, + { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, + { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, + { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, + { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, + { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, + { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, + { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, + { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, + { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, + { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, + { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" }, + { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" }, + { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" }, + { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" }, + { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" }, + { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" }, + { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" }, + { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" }, + { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" }, + { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" }, + { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" }, + { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, + { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, + { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, + { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, + { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, + { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, + { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, + { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, + { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, + { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, + { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, + { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, + { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, + { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, + { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, + { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, + { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, + { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, + { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, + { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, + { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, + { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +] diff --git a/frontend/app.js b/frontend/app.js new file mode 100644 index 0000000000000000000000000000000000000000..b23d833dd4124491dc206f3eb2a1b56db2c06a2b --- /dev/null +++ b/frontend/app.js @@ -0,0 +1,436 @@ +// RMScript Web Demo - Frontend Application +// Connects to: +// - Backend API for compilation/verification +// - Robot WebSocket (localhost:8000) for execution + +// Auto-detect backend URL based on environment +// If opened as file:// (local development), use localhost:8001 +// If served from web server (production/Space), use relative URLs +const BACKEND_URL = window.location.protocol === 'file:' + ? 'http://localhost:8001' + : ''; // Use relative URLs when served from web server +const ROBOT_WS_URL = 'ws://localhost:8000/api/move/ws/set_target'; + +// Global state +const state = { + robotWs: null, + robotConnected: false, + currentIR: null, + isExecuting: false +}; + +// DOM elements +const elements = { + editor: document.getElementById('editor'), + compileStatus: document.getElementById('compileStatus'), + robotStatus: document.getElementById('robotStatus'), + console: document.getElementById('console'), + irDisplay: document.getElementById('irDisplay'), + executionInfo: document.getElementById('executionInfo'), + executeBtn: document.getElementById('executeBtn') +}; + +// Example scripts +const examples = { + basic: `DESCRIPTION Simple head movement +look left +wait 1s +look right +wait 1s +look center`, + + complex: `DESCRIPTION Wave hello +look left +antenna both up +wait 1s +look right +antenna both down +wait 0.5s +look center`, + + repeat: `DESCRIPTION Repeat demo +REPEAT 3 + look left + wait 0.5s + look right + wait 0.5s +END +look center` +}; + +// Initialize robot WebSocket connection +function connectRobotWebSocket() { + log('Connecting to robot...', 'info'); + + state.robotWs = new WebSocket(ROBOT_WS_URL); + + state.robotWs.onopen = () => { + state.robotConnected = true; + updateRobotStatus(true); + log('Robot connected!', 'success'); + }; + + state.robotWs.onclose = () => { + state.robotConnected = false; + updateRobotStatus(false); + log('Robot disconnected. Reconnecting...', 'warning'); + setTimeout(connectRobotWebSocket, 2000); + }; + + state.robotWs.onerror = (error) => { + log(`Robot connection error: ${error}`, 'error'); + }; + + state.robotWs.onmessage = (event) => { + try { + const message = JSON.parse(event.data); + if (message.status === 'error') { + log(`Robot error: ${message.detail}`, 'error'); + } + } catch (e) { + console.error('Failed to parse robot message:', e); + } + }; +} + +// Update robot connection status UI +function updateRobotStatus(connected) { + if (connected) { + elements.robotStatus.className = 'status connected'; + elements.robotStatus.innerHTML = 'Connected'; + elements.executeBtn.disabled = false; + } else { + elements.robotStatus.className = 'status disconnected'; + elements.robotStatus.innerHTML = 'Disconnected'; + elements.executeBtn.disabled = true; + } +} + +// Update compile status UI +function updateCompileStatus(status, message) { + const dot = status === 'success' ? 'green' : status === 'error' ? 'red' : 'gray'; + elements.compileStatus.className = `status ${status}`; + elements.compileStatus.innerHTML = `${message}`; +} + +// Log to console +function log(message, type = 'info') { + const line = document.createElement('div'); + line.className = `console-line ${type}`; + line.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; + elements.console.appendChild(line); + elements.console.scrollTop = elements.console.scrollHeight; +} + +// Clear console +function clearConsole() { + elements.console.innerHTML = ''; +} + +// Load example script +function loadExample(exampleName) { + if (examples[exampleName]) { + elements.editor.value = examples[exampleName]; + log(`Loaded ${exampleName} example`, 'info'); + } +} + +// Clear editor +function clearEditor() { + elements.editor.value = ''; + state.currentIR = null; + elements.irDisplay.innerHTML = '
No IR yet. Verify a script first!
'; + updateCompileStatus('idle', 'Ready'); +} + +// Verify script (syntax and semantics only) +async function verifyScript() { + const source = elements.editor.value.trim(); + + if (!source) { + log('Editor is empty', 'warning'); + return; + } + + clearConsole(); + log('Verifying script...', 'info'); + updateCompileStatus('idle', 'Verifying...'); + + try { + const response = await fetch(`${BACKEND_URL}/api/verify`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ source }) + }); + + const result = await response.json(); + + if (result.success) { + log('✓ Verification successful!', 'success'); + if (result.name) log(` Name: ${result.name}`, 'info'); + if (result.description) log(` Description: ${result.description}`, 'info'); + + if (result.warnings.length > 0) { + result.warnings.forEach(w => { + log(` Warning (line ${w.line}): ${w.message}`, 'warning'); + }); + } + + updateCompileStatus('success', 'Valid script'); + } else { + log('✗ Verification failed', 'error'); + result.errors.forEach(e => { + log(` Error (line ${e.line}): ${e.message}`, 'error'); + }); + updateCompileStatus('error', 'Invalid script'); + } + } catch (error) { + log(`Backend error: ${error.message}`, 'error'); + updateCompileStatus('error', 'Backend error'); + } +} + +// Compile script to IR +async function compileScript() { + const source = elements.editor.value.trim(); + + if (!source) { + log('Editor is empty', 'warning'); + return null; + } + + log('Compiling script to IR...', 'info'); + updateCompileStatus('idle', 'Compiling...'); + + try { + const response = await fetch(`${BACKEND_URL}/api/compile`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ source }) + }); + + const result = await response.json(); + + if (result.success) { + log(`✓ Compiled ${result.ir.length} actions`, 'success'); + + if (result.warnings.length > 0) { + result.warnings.forEach(w => { + log(` Warning (line ${w.line}): ${w.message}`, 'warning'); + }); + } + + state.currentIR = result.ir; + displayIR(result.ir); + updateCompileStatus('success', `${result.ir.length} actions ready`); + return result.ir; + } else { + log('✗ Compilation failed', 'error'); + result.errors.forEach(e => { + log(` Error (line ${e.line}): ${e.message}`, 'error'); + }); + updateCompileStatus('error', 'Compilation failed'); + return null; + } + } catch (error) { + log(`Backend error: ${error.message}`, 'error'); + updateCompileStatus('error', 'Backend error'); + return null; + } +} + +// Display IR in the UI +function displayIR(ir) { + if (!ir || ir.length === 0) { + elements.irDisplay.innerHTML = '
No actions
'; + return; + } + + const html = ir.map((action, idx) => { + let details = ''; + + if (action.type === 'action') { + details = `Duration: ${action.duration}s`; + if (action.head_pose) details += ', Head movement'; + if (action.antennas) details += `, Antennas: [${action.antennas.map(a => a.toFixed(2)).join(', ')}]`; + if (action.body_yaw !== null) details += `, Body yaw: ${action.body_yaw.toFixed(2)}`; + } else if (action.type === 'wait') { + details = `Wait ${action.duration}s`; + } else if (action.type === 'picture') { + details = 'Take picture'; + } else if (action.type === 'sound') { + details = `Play "${action.sound_name}"`; + if (action.blocking) details += ' (blocking)'; + if (action.loop) details += ' (loop)'; + } + + return ` +
+
${idx + 1}. ${action.type.toUpperCase()}
+
${details}
+
+ `; + }).join(''); + + elements.irDisplay.innerHTML = html; +} + +// Execute compiled script on robot +async function executeScript() { + if (!state.robotConnected) { + log('Robot not connected!', 'error'); + return; + } + + if (state.isExecuting) { + log('Already executing a script', 'warning'); + return; + } + + // Always compile the current editor content before executing + const ir = await compileScript(); + if (!ir) { + log('Cannot execute - compilation failed', 'error'); + return; + } + + // Execute IR actions sequentially + state.isExecuting = true; + elements.executeBtn.disabled = true; + clearExecutionInfo(); + logExecution('Starting execution...', 'info'); + + try { + for (let i = 0; i < ir.length; i++) { + const action = ir[i]; + logExecution(`Action ${i + 1}/${ir.length}: ${action.type}`, 'info'); + + if (action.type === 'action') { + await executeIRAction(action); + } else if (action.type === 'wait') { + await sleep(action.duration * 1000); + } else if (action.type === 'picture') { + logExecution('Picture action skipped (not implemented)', 'warning'); + } else if (action.type === 'sound') { + logExecution('Sound action skipped (not implemented)', 'warning'); + } + } + + logExecution('✓ Execution complete!', 'success'); + } catch (error) { + logExecution(`✗ Execution error: ${error.message}`, 'error'); + } finally { + state.isExecuting = false; + if (state.robotConnected) { + elements.executeBtn.disabled = false; + } + } +} + +// Extract euler angles (roll, pitch, yaw) from 3x3 rotation matrix +// Uses XYZ euler convention to match scipy's R.from_matrix().as_euler("xyz") +function matrixToEulerXYZ(rotMatrix) { + // Extract 3x3 rotation matrix from 4x4 pose matrix if needed + const R = rotMatrix; + + // For XYZ euler order: R = Rz(yaw) * Ry(pitch) * Rx(roll) + // pitch = asin(-R[2][0]) + // roll = atan2(R[2][1], R[2][2]) + // yaw = atan2(R[1][0], R[0][0]) + + let pitch = Math.asin(-R[2][0]); + + // Check for gimbal lock + if (Math.abs(Math.cos(pitch)) > 1e-6) { + // Normal case + const roll = Math.atan2(R[2][1], R[2][2]); + const yaw = Math.atan2(R[1][0], R[0][0]); + return { roll, pitch, yaw }; + } else { + // Gimbal lock case + const roll = Math.atan2(-R[0][1], R[1][1]); + const yaw = 0; + return { roll, pitch, yaw }; + } +} + +// Execute a single IR action (send to robot) +async function executeIRAction(action) { + if (!state.robotWs || state.robotWs.readyState !== WebSocket.OPEN) { + throw new Error('Robot WebSocket not connected'); + } + + const message = {}; + + if (action.head_pose) { + // Extract translation from 4x4 matrix + const x = action.head_pose[0][3]; + const y = action.head_pose[1][3]; + const z = action.head_pose[2][3]; + + // Extract rotation (euler angles) from 3x3 rotation matrix portion + const euler = matrixToEulerXYZ(action.head_pose); + + message.target_head_pose = { + x: x, + y: y, + z: z, + roll: euler.roll, + pitch: euler.pitch, + yaw: euler.yaw + }; + } + + if (action.antennas) { + message.target_antennas = action.antennas; + } + + if (action.body_yaw !== null) { + message.target_body_yaw = action.body_yaw; + } + + // Send to robot + state.robotWs.send(JSON.stringify(message)); + + // Wait for the action duration + await sleep(action.duration * 1000); +} + +// Log execution info +function logExecution(message, type = 'info') { + const line = document.createElement('div'); + line.className = `console-line ${type}`; + line.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; + elements.executionInfo.appendChild(line); + elements.executionInfo.scrollTop = elements.executionInfo.scrollHeight; +} + +// Clear execution info +function clearExecutionInfo() { + elements.executionInfo.innerHTML = ''; +} + +// Sleep helper +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +// Initialize application +function init() { + console.log('Initializing RMScript Web Demo'); + + // Connect to robot + connectRobotWebSocket(); + + // Load default example + loadExample('basic'); + + console.log('RMScript Web Demo ready'); +} + +// Start when DOM is loaded +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000000000000000000000000000000000000..c321f0f4c617a19faeaacea0a02c18dcc4ab610a --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,331 @@ + + + + + + RMScript Web Demo + + + +
+ +
+

🤖 RMScript Editor

+

Write and test your rmscript code

+ +
+ Ready +
+ +
Examples
+
+ + + + +
+ + + +
+ + +
+ +
Console
+
+
Ready. Write some rmscript and click Verify!
+
+
+ + +
+

🔗 Robot Connection

+

Connect to Reachy Mini on localhost:8000

+ +
+ Disconnected +
+ +
Compiled IR
+
+
+ No IR yet. Verify a script first! +
+
+ +
Execution Info
+
+
Ready to execute when robot is connected
+
+
+
+ + + + + diff --git a/reachy_mini/.gitattributes b/reachy_mini/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..bf1727ba32644d4c4d06ac899b729db42b0cdcb2 --- /dev/null +++ b/reachy_mini/.gitattributes @@ -0,0 +1,15 @@ +*.png filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.jpeg filter=lfs diff=lfs merge=lfs -text +*.gif filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text +*.avi filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.tar.gz filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.obj filter=lfs diff=lfs merge=lfs -text +*.stl filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.svg filter=lfs diff=lfs merge=lfs -text diff --git a/reachy_mini/.github/workflows/lint.yml b/reachy_mini/.github/workflows/lint.yml new file mode 100644 index 0000000000000000000000000000000000000000..980524f6d7afa0d0953c75c88174ce006559d216 --- /dev/null +++ b/reachy_mini/.github/workflows/lint.yml @@ -0,0 +1,27 @@ +name: Linters +on: [ push, pull_request ] +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/ruff-action@v3 + with: + version: "0.12.0" + + mypy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: 'pip' # caching pip dependencies + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install .[dev] + - name : Lint with mypy + run : | + mypy --install-types --non-interactive diff --git a/reachy_mini/.github/workflows/pytest.yml b/reachy_mini/.github/workflows/pytest.yml new file mode 100644 index 0000000000000000000000000000000000000000..1a8c75fdd271a497eb4b8fe5d259fb1aa9982e3b --- /dev/null +++ b/reachy_mini/.github/workflows/pytest.yml @@ -0,0 +1,28 @@ +name: Pytest +on: [pull_request] +jobs: + pytest: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + steps: + - uses: actions/checkout@v4 + with: + lfs: "true" + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: "pip" + - name: Install system dependencies (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get update && sudo apt-get install -y libportaudio2 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install .[dev] + - name: Run tests + run: | + pytest -vv -m 'not audio and not video and not audio_gstreamer and not video_gstreamer and not wireless and not wireless_gstreamer' --tb=short + env: + MUJOCO_GL: disable diff --git a/reachy_mini/.github/workflows/wheels.yml b/reachy_mini/.github/workflows/wheels.yml new file mode 100644 index 0000000000000000000000000000000000000000..dca1e95cab0816e05abd01fc2cbf6c48ae6e8f84 --- /dev/null +++ b/reachy_mini/.github/workflows/wheels.yml @@ -0,0 +1,26 @@ +name: Publish + +on: + release: + types: + - created + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + id-token: write + steps: + - uses: actions/checkout@v5 + with: + lfs: true + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.10" + - name: Install build dependencies + run: pip install build + - name: Build distribution + run: python -m build + - name: Publish + uses: pypa/gh-action-pypi-publish@v1.13.0 \ No newline at end of file diff --git a/reachy_mini/.github/workflows/wheels.yml.bak b/reachy_mini/.github/workflows/wheels.yml.bak new file mode 100644 index 0000000000000000000000000000000000000000..256d8da0e8dcfbd26880be47094a606b1e3b5813 --- /dev/null +++ b/reachy_mini/.github/workflows/wheels.yml.bak @@ -0,0 +1,181 @@ +name: Build and Release Wheels + +on: + push: + tags: + - "*" + workflow_dispatch: + +jobs: + linux: + runs-on: ${{ matrix.platform.runner }} + if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} + strategy: + matrix: + platform: + - runner: ubuntu-22.04 + target: x86_64 + - runner: ubuntu-22.04 + target: x86 + - runner: ubuntu-22.04 + target: aarch64 + - runner: ubuntu-22.04 + target: armv7 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: | + 3.8 + 3.9 + 3.10 + 3.11 + 3.12 + 3.13 + - name: Build wheels + run: | + pip install build + python -m build --wheel --outdir dist + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-linux-${{ matrix.platform.target }} + path: dist/*.whl + + musllinux: + runs-on: ${{ matrix.platform.runner }} + if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} + strategy: + matrix: + platform: + - runner: ubuntu-22.04 + target: x86_64 + - runner: ubuntu-22.04 + target: x86 + - runner: ubuntu-22.04 + target: aarch64 + - runner: ubuntu-22.04 + target: armv7 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: | + 3.8 + 3.9 + 3.10 + 3.11 + 3.12 + 3.13 + - name: Build wheels + run: | + pip install build + python -m build --wheel --outdir dist + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-musllinux-${{ matrix.platform.target }} + path: dist/*.whl + + windows: + runs-on: ${{ matrix.platform.runner }} + if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} + strategy: + matrix: + platform: + - runner: windows-latest + target: x64 + - runner: windows-latest + target: x86 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: | + 3.8 + 3.9 + 3.10 + 3.11 + 3.12 + 3.13 + architecture: ${{ matrix.platform.target }} + - name: Build wheels + run: | + pip install build + python -m build --wheel --outdir dist + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-windows-${{ matrix.platform.target }} + path: dist/*.whl + + macos: + runs-on: ${{ matrix.platform.runner }} + if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} + strategy: + matrix: + platform: + - runner: macos-13 + target: x86_64 + - runner: macos-14 + target: aarch64 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: | + 3.8 + 3.9 + 3.10 + 3.11 + 3.12 + 3.13 + - name: Build wheels + run: | + pip install build + python -m build --wheel --outdir dist + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-macos-${{ matrix.platform.target }} + path: dist/*.whl + + sdist: + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} + steps: + - uses: actions/checkout@v4 + - name: Build sdist + run: | + pip install build + python -m build --sdist --outdir dist + - name: Upload sdist + uses: actions/upload-artifact@v4 + with: + name: wheels-sdist + path: dist/*.tar.gz + + release: + name: Release + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} + needs: [linux, musllinux, windows, macos, sdist] + permissions: + id-token: write + contents: write + attestations: write + steps: + - uses: actions/download-artifact@v4 + with: + pattern: wheels-* + merge-multiple: true + path: dist + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v1 + with: + subject-path: 'dist/*' + - name: Publish to PyPI + if: ${{ startsWith(github.ref, 'refs/tags/') }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ \ No newline at end of file diff --git a/reachy_mini/.gitignore b/reachy_mini/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..511e897669bb76553c0e63496a2f0e323b8e3045 --- /dev/null +++ b/reachy_mini/.gitignore @@ -0,0 +1,256 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +# Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +# poetry.lock +# poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +# pdm.lock +# pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +# pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# Redis +*.rdb +*.aof +*.pid + +# RabbitMQ +mnesia/ +rabbitmq/ +rabbitmq-data/ + +# ActiveMQ +activemq-data/ + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml +.idea/**/contentModel.xml + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets +!*.code-workspace + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# Streamlit +.streamlit/secrets.toml + +# General for macOS +.DS_Store +__MACOSX/ +.AppleDouble +.LSOverride +Icon[] + +# General for Linux +*~ +.fuse_hidden* +.directory +.Trash-* +.nfs* +nohup.out + +# General for Windows +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db +[Dd]esktop.ini +*.stackdump +$RECYCLE.BIN/ +*.lnk + +# Project specific ignores +src/reachy_mini_dashboard/installed_apps/* +examples/debug/measures/* +.DS_Store \ No newline at end of file diff --git a/reachy_mini/.pre-commit-config.yaml b/reachy_mini/.pre-commit-config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..273d3502025f81c79f18c30971e9aaa6f0e45cee --- /dev/null +++ b/reachy_mini/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: +- repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. Make sure it matches the version in .github/workflows/lint.yml. + rev: v0.12.0 + hooks: + # Run the linter. + - id: ruff-check + args: ["--select", "I", "--select", "D", "--ignore", "D203", "--ignore", "D213"] + # Run the formatter. + - id: ruff-format \ No newline at end of file diff --git a/reachy_mini/LICENSE b/reachy_mini/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..2bae156ba764607d491a34535fb0fb5a02022793 --- /dev/null +++ b/reachy_mini/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Pollen Robotics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/reachy_mini/MANIFEST.in b/reachy_mini/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..f51342cf3346a74203c815f86556947c51e99f8a --- /dev/null +++ b/reachy_mini/MANIFEST.in @@ -0,0 +1,3 @@ +recursive-include src/reachy_mini/assets * +recursive-include src/reachy_mini/templates * +recursive-include src/reachy_mini/descriptions * diff --git a/reachy_mini/README.md b/reachy_mini/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e2079c0905d627a54a0424e5d0ea1a34ff9c2f79 --- /dev/null +++ b/reachy_mini/README.md @@ -0,0 +1,246 @@ +# Reachy Mini + +> ⚠️ Reachy Mini is still in beta. Expect bugs, some of them we won't fix right away if they are not a priority. + +[Reachy Mini](https://www.pollen-robotics.com/reachy-mini/) is an expressive, open-source robot designed for human-robot interaction, creative coding, and AI experimentation. We made it to be affordable, easy to use, hackable and cute, so that you can focus on building cool AI applications! + +[![Reachy Mini Hello](/docs/assets/reachy_mini_hello.gif)](https://www.pollen-robotics.com/reachy-mini/) + +### Versions Lite & Wireless + +Reachy Mini's hardware comes in two flavors: +- **Reachy Mini lite**: where the robot is directly connected to your computer via USB. And the code that controls the robot (the daemon) runs on your computer. +- **Reachy Mini wireless**: where an Raspberry Pi is embedded in the robot, and the code that controls the robot (the daemon) runs on the Raspberry Pi. You can connect to it via Wi-Fi from your computer (see [Wireless Setup](./docs/wireless-version.md)). + +There is also a simulated version of Reachy Mini in [MuJoCo](https://mujoco.org) that you can use to prototype your applications before deploying them on the real robot. It behaves like the lite version where the daemon runs on your computer. + +## Assembly guide + +📖 Follow our step-by-step [Assembly Guide](https://huggingface.co/spaces/pollen-robotics/Reachy_Mini_Assembly_Guide). + +Most builders finish in about 3 hours, our current speed record is 43 minutes. The guide walks you through every step with clear visuals so you can assemble Reachy Mini confidently from start to finish. Enjoy the build! + +▶️ View the [Assembly Video](https://youtu.be/_r0cHySFbeY?si=6Mw4js8HSUs4cwoJ). + +## Software overview + +This repository provides everything you need to control Reachy Mini, both in simulation and on the real robot. It consists of two main parts: + +- **The 😈 Daemon 😈**: A background service that manages communication with the robot's motors and sensors, or with the simulation environment. It should be running before you can control the robot. It can run either for the simulation (MuJoCo) or for the real robot. +- **🐍 SDK & 🕸️ API** to control the robot's main features (head, antennas, camera, speakers, microphone, etc.) and connect with your AI experimentation. Depending on your preferences and needs, there is a [Python SDK](#using-the-python-sdk) and a [HTTP REST API](#using-the-rest-api). + +Using the [Python SDK](#using-the-python-sdk), making your robot move only require a few lines of code, as illustrated in the example below: + +```python +from reachy_mini import ReachyMini +from reachy_mini.utils import create_head_pose + +with ReachyMini() as reachy_mini: + # Move the head up (10mm on z-axis) and roll it 15 degrees + pose = create_head_pose(z=10, roll=15, degrees=True, mm=True) + reachy_mini.goto_target(head=pose, duration=2.0) + + # Reset to default pose + pose = create_head_pose() + reachy_mini.goto_target(head=pose, duration=2.0) +``` + +and using the [REST API](#using-the-rest-api), reading the current state of the robot: + +```bash +curl 'http://localhost:8000/api/state/full' +``` + +Those two examples above assume that the daemon is already running (either in simulation or on the real robot) locally. + +## Installation of the daemon and Python SDK + +As mentioned above, before being able to use the robot, you need to run the daemon that will handle the communication with the motors. + +We support and test on Linux and macOS. It's also working on Windows, but it is less tested at the moment. Do not hesitate to open an issue if you encounter any problem. + +The daemon is built in Python, so you need to have Python installed on your computer (versions from 3.10 to 3.13 are supported). We recommend using a virtual environment to avoid dependency conflicts with your other Python projects. + +You can install Reachy Mini from the source code or from PyPI. + +First, make sure `git-lfs` is installed on your system: + +- On Linux: `sudo apt install git-lfs` +- On macOS: `brew install git-lfs` +- On Windows: [Follow the instructions here](https://docs.github.com/en/repositories/working-with-files/managing-large-files/installing-git-large-file-storage?platform=windows) + +From PyPI, you can install the package with: + +```bash +pip install reachy-mini +``` + +From the source code, you can install the package with: + +```bash +git clone https://github.com/pollen-robotics/reachy_mini +pip install -e ./reachy_mini +``` + +*Note that uv users can directly run the daemon with:* +```bash +uv run reachy-mini-daemon +``` + +The same package provides both the daemon and the Python SDK. + + +## Run the reachy mini daemon + +Before being able to use the robot, you need to run the daemon that will handle the communication with the motors. This daemon can run either in simulation (MuJoCo) or on the real robot. + +```bash +reachy-mini-daemon +``` + +or run it via the Python module: + +```bash +python -m reachy_mini.daemon.app.main +``` + +Additional argument for both simulation and real robot: + +```bash +--localhost-only: (default behavior). The server will only accept connections from localhost. +``` + +or + +```bash +--no-localhost-only: If set, the server will accept connections from any connection on the local network. +``` + +### In simulation ([MuJoCo](https://mujoco.org)) + +You first have to install the optional dependency `mujoco`. + +```bash +pip install reachy-mini[mujoco] +``` + +Then run the daemon with the `--sim` argument. + +```bash +reachy-mini-daemon --sim +``` + +Additional arguments: + +```bash +--scene : (Default empty). Choose between a basic empty scene, or a scene with a table and some objects. +``` + +Reachy Mini in MuJoCo + + +*Note: On OSX in order to run mujoco, you need to use mjpython (see [here](https://mujoco.readthedocs.io/en/stable/python.html#passive-viewer)). So, you should run the daemon with:* + +```bash + mjpython -m reachy_mini.daemon.app.main --sim + ``` + +### For the lite version (connected via USB) + +It should automatically detect the serial port of the robot. If it does not, you can specify it manually with the `-p` option: + +```bash +reachy-mini-daemon -p +``` + +### Usage + +For more information about the daemon and its options, you can run: + +```bash +reachy-mini-daemon --help +``` + +### Dashboard + +You can access a simple dashboard to monitor the robot's status at [http://localhost:8000/](http://localhost:8000/) when the daemon is running. This lets you turn your robot on and off, run some basic movements, and browse spaces for Reachy Mini! + +![Reachy Mini Dashboard](docs/assets/dashboard.png) + +## Run the demo & awesome apps + +Conversational demo for the Reachy Mini robot combining LLM realtime APIs, vision pipelines, and choreographed motion libraries: [reachy_mini_conversation_demo](https://github.com/pollen-robotics/reachy_mini_conversation_demo). + +You can find more awesome apps and demos for Reachy Mini on [Hugging Face spaces](https://huggingface.co/spaces?q=reachy_mini)! + +## Using the Python SDK + +The API is designed to be simple and intuitive. You can control the robot's features such as the head, antennas, camera, speakers, and microphone. For instance, to move the head of the robot, you can use the `goto_target` method as shown in the example below: + +```python +from reachy_mini import ReachyMini +from reachy_mini.utils import create_head_pose + +with ReachyMini() as reachy_mini: + # Move the head up (10mm on z-axis) and roll it 15 degrees + pose = create_head_pose(z=10, roll=15, degrees=True, mm=True) + reachy_mini.goto_target(head=pose, duration=2.0) + + # Reset to default pose + pose = create_head_pose() + reachy_mini.goto_target(head=pose, duration=2.0) +``` + +For a full description of the SDK, please refer to the [Python SDK documentation](./docs/python-sdk.md). + +## Using the REST API + +The daemon also provides a REST API via [fastapi](https://fastapi.tiangolo.com/) that you can use to control the robot and get its state. The API is accessible via HTTP and WebSocket. + +By default, the API server runs on `http://localhost:8000`. The API is documented using OpenAPI, and you can access the documentation at `http://localhost:8000/docs` when the daemon is running. + +More information about the API can be found in the [HTTP API documentation](./docs/rest-api.md). + +## Open source & contribution + +This project is actively developed and maintained by the [Pollen Robotics team](https://www.pollen-robotics.com) and the [Hugging Face team](https://huggingface.co/). + +We welcome contributions from the community! If you want to report a bug or request a feature, please open an issue on GitHub. If you want to contribute code, please fork the repository and submit a pull request. + +### 3D models + +TODO + +### Contributing + +Development tools are available in the optional dependencies. + +```bash +pip install -e .[dev] +pre-commit install +``` + +Your files will be checked before any commit. Checks may also be manually run with + +```bash +pre-commit run --all-files +``` + +Checks are performed by Ruff. You may want to [configure your IDE to support it](https://docs.astral.sh/ruff/editors/setup/). + +## Troubleshooting + +see [dedicated section](docs/troubleshooting.md) + +## License + +This project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details. + +The robot design files are licensed under the [TODO](TODO) license. + +### Simulation model used + +- https://polyhaven.com/a/food_apple_01 +- https://polyhaven.com/a/croissant +- https://polyhaven.com/a/wooden_table_02 +- https://polyhaven.com/a/rubber_duck_toy diff --git a/reachy_mini/conftest.py b/reachy_mini/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/reachy_mini/pyproject.toml b/reachy_mini/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..f243ea1aa781f040f4efe15558f218acec865699 --- /dev/null +++ b/reachy_mini/pyproject.toml @@ -0,0 +1,111 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "reachy_mini" +version = "1.1.1" +authors = [{ name = "Pollen Robotics", email = "contact@pollen-robotics.com" }] +description = "" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "numpy>=2.2.5", + "scipy>=1.15.3, <2.0.0", + "reachy_mini_motor_controller>=1.4.2", + "eclipse-zenoh>=1.4.0", + "opencv-python<=5.0", + "cv2_enumerate_cameras>=1.2.1", + "psutil", + "jinja2", + "uvicorn[standard]", + "fastapi", + "pyserial", + "huggingface-hub==0.34.4", + "sounddevice==0.5.1", + "soundfile==0.13.1", + "reachy-mini-rust-kinematics>=1.0.2", + "asgiref", + "aiohttp", + "log-throttling==0.0.3", + "pyusb>=1.2.1", + "libusb_package>=1.0.26.3", + "pip>=25", +] + + +[project.optional-dependencies] +dev = [ + "pytest", + "pytest-asyncio", + "ruff==0.12.0", + "onshape-to-robot==1.7.6", + "mujoco==3.3.0", + "placo==0.9.14", + "pre-commit", + "mypy==1.18.2", + "rustypot>=1.4.0", + "types-requests", + "rerun-sdk>=0.27.2", + "urdf-parser-py==0.0.4", +] +examples = ["pynput"] +mujoco = ["mujoco==3.3.0"] +nn_kinematics = ["onnxruntime==1.22.1"] +placo_kinematics = ["placo==0.9.14"] +gstreamer = ["PyGObject>=3.42.2,<=3.46.0", "gst-signalling>=1.1.2"] +rerun = ["rerun-sdk>=0.27.2", "urdf-parser-py==0.0.4"] +wireless-version = [ + "semver>=3,<4", + "nmcli>=1.5", + "pollen_BMI088_imu_library", + "gpiozero>=2.0.0", + "lgpio>=0.2.2.0", +] + +[project.scripts] +reachy-mini-daemon = "reachy_mini.daemon.app.main:main" +reachy-mini-apps-helper = "reachy_mini.apps.app:main" + +[tool.setuptools] +package-dir = { "" = "src" } +include-package-data = true + + +[tool.setuptools.packages.find] +where = ["src"] + + +[tool.setuptools.package-data] +reachy_mini = ["**/*"] # Inclut tous les fichiers non .py + +[tool.ruff] +exclude = [ + "src/reachy_mini/__init__.py", + "build/*", + "conftest.py", + "src/reachy_mini_dashboard/*", + "tests/*", +] +lint.extend-select = ["I", "D"] +lint.ignore = [ + "D203", # Incompatible with D211 + "D213", # Incompatible with D212 +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +markers = [ + "audio: mark test as requiring audio hardware", + "audio_gstreamer: mark test as requiring GStreamer for audio", + "video: mark test as requiring video hardware", + "video_gstreamer: mark test as requiring GStreamer for video", + "wireless: mark test as requiring wireless Reachy Mini", + "wireless_gstreamer: mark test as requiring GStreamer for wireless Reachy Mini", +] + +[tool.mypy] +python_version = "3.10" +files = ["src/"] +ignore_missing_imports = true +strict = true diff --git a/reachy_mini/src/reachy_mini/__init__.py b/reachy_mini/src/reachy_mini/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9dc26157e7280df3751f8fa238af92dff3a06f66 --- /dev/null +++ b/reachy_mini/src/reachy_mini/__init__.py @@ -0,0 +1,4 @@ +"""Reachy Mini SDK.""" + +from reachy_mini.apps.app import ReachyMiniApp # noqa: F401 +from reachy_mini.reachy_mini import ReachyMini # noqa: F401 diff --git a/reachy_mini/src/reachy_mini/apps/__init__.py b/reachy_mini/src/reachy_mini/apps/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..94c3e5fcf6b4b7e5c913b171674d681665867860 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/__init__.py @@ -0,0 +1,25 @@ +"""Metadata about apps.""" + +from dataclasses import dataclass, field +from enum import Enum +from typing import Any, Dict + + +class SourceKind(str, Enum): + """Kinds of app source.""" + + HF_SPACE = "hf_space" + DASHBOARD_SELECTION = "dashboard_selection" + LOCAL = "local" + INSTALLED = "installed" + + +@dataclass +class AppInfo: + """Metadata about an app.""" + + name: str + source_kind: SourceKind + description: str = "" + url: str | None = None + extra: Dict[str, Any] = field(default_factory=dict) diff --git a/reachy_mini/src/reachy_mini/apps/app.py b/reachy_mini/src/reachy_mini/apps/app.py new file mode 100644 index 0000000000000000000000000000000000000000..552871785b776b161bdcff74691ce880c3f9bb5f --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/app.py @@ -0,0 +1,169 @@ +"""Reachy Mini Application Base Class. + +This module provides a base class for creating Reachy Mini applications. +It includes methods for running the application, stopping it gracefully, +and creating a new app project with a specified name and path. + +It uses Jinja2 templates to generate the necessary files for the app project. +""" + +import os +import threading +import traceback +from abc import ABC, abstractmethod +from pathlib import Path +from typing import Any, Dict + +from jinja2 import Environment, FileSystemLoader + +from reachy_mini.reachy_mini import ReachyMini + + +class ReachyMiniApp(ABC): + """Base class for Reachy Mini applications.""" + + custom_app_url: str | None = None + + def __init__(self) -> None: + """Initialize the Reachy Mini app.""" + self.stop_event = threading.Event() + self.error: str = "" + + def wrapped_run(self, *args: Any, **kwargs: Any) -> None: + """Wrap the run method with Reachy Mini context management.""" + try: + with ReachyMini(*args, **kwargs) as reachy_mini: + self.run(reachy_mini, self.stop_event) + except Exception: + self.error = traceback.format_exc() + raise + + @abstractmethod + def run(self, reachy_mini: ReachyMini, stop_event: threading.Event) -> None: + """Run the main logic of the app. + + Args: + reachy_mini (ReachyMini): The Reachy Mini instance to interact with. + stop_event (threading.Event): An event that can be set to stop the app gracefully. + + """ + pass + + def stop(self) -> None: + """Stop the app gracefully.""" + self.stop_event.set() + print("App is stopping...") + + +def make_app_project(app_name: str, path: Path) -> None: + """Create a new Reachy Mini app project with the given name at the specified path. + + Args: + app_name (str): The name of the app to create. + path (Path): The directory where the app project will be created. + + """ + TEMPLATE_DIR = Path(__file__).parent / "templates" + env = Environment(loader=FileSystemLoader(TEMPLATE_DIR)) + + def render_template(filename: str, context: Dict[str, str]) -> str: + template = env.get_template(filename) + return template.render(context) + + base_path = Path(path).resolve() / app_name + if base_path.exists(): + print(f"❌ Folder {base_path} already exists.") + return + + module_name = app_name.replace("-", "_") + class_name = "".join(word.capitalize() for word in module_name.split("_")) + class_name_display = " ".join(word.capitalize() for word in module_name.split("_")) + + base_path.mkdir() + (base_path / module_name).mkdir() + + # Generate files + context = { + "app_name": app_name, + "package_name": app_name, + "module_name": module_name, + "class_name": class_name, + "class_name_display": class_name_display, + } + + (base_path / module_name / "__init__.py").touch() + (base_path / module_name / "main.py").write_text( + render_template("main.py.j2", context) + ) + (base_path / "pyproject.toml").write_text( + render_template("pyproject.toml.j2", context) + ) + (base_path / "README.md").write_text(render_template("README.md.j2", context)) + + (base_path / "index.html").write_text(render_template("index.html.j2", context)) + (base_path / "style.css").write_text(render_template("style.css.j2", context)) + + print(f"✅ Created app in {base_path}/") + + +def publish_app(app_path: str, hf_space_url: Path) -> None: + """Publish the app to the Reachy Mini app store. + + Args: + app_path (str): Local path to the app to publish. + hf_space_url (Path): Url to the space on Hugging Face. + + """ + # Placeholder for publishing logic + assert os.path.exists(app_path), f"App path {app_path} does not exist." + print(f"Publishing app from {app_path} to {hf_space_url}...") + os.system( + f"cd {app_path} && git init && git remote add space {hf_space_url} && git add . && git commit -m 'Initial commit' && git push -f space main:main" + ) + print("✅ App published successfully.") + + +def main() -> None: + """Run the command line interface to create a new Reachy Mini app project.""" + import argparse + + parser = argparse.ArgumentParser( + description="Create a new Reachy Mini app project." + ) + subparsers = parser.add_subparsers( + dest="command", help="Available commands", required=True + ) + + make_parser = subparsers.add_parser("make", help="Make a new app project") + make_parser.add_argument( + "--option", type=str, help="An option for the make command" + ) + make_parser.add_argument("app_name", type=str, help="Name of the app to create.") + make_parser.add_argument( + "path", + type=Path, + default=Path.cwd(), + help="Path where the app project will be created.", + ) + + publish_parser = subparsers.add_parser( + "publish", help="Publish the app to the Reachy Mini app store" + ) + publish_parser.add_argument( + "app_path", type=str, help="Local path to the app to publish." + ) + publish_parser.add_argument( + "hf_space_url", type=Path, help="Url to the space on Hugging Face." + ) + + args = parser.parse_args() + + if args.command == "make": + make_app_project(args.app_name, args.path) + + elif args.command == "publish": + publish_app(args.app_path, args.hf_space_url) + + +if __name__ == "__main__": + main() diff --git a/reachy_mini/src/reachy_mini/apps/manager.py b/reachy_mini/src/reachy_mini/apps/manager.py new file mode 100644 index 0000000000000000000000000000000000000000..070c857d349f65db7f7c1637f9a35016ac1aa3b4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/manager.py @@ -0,0 +1,185 @@ +"""App management for Reachy Mini.""" + +import asyncio +import logging +from dataclasses import dataclass +from enum import Enum +from importlib.metadata import entry_points +from threading import Thread +from typing import TYPE_CHECKING, Any, Optional + +from pydantic import BaseModel + +from . import AppInfo, SourceKind +from .sources import hf_space, local_common_venv + +if TYPE_CHECKING: + from .app import ReachyMiniApp + + +class AppState(str, Enum): + """Status of a running app.""" + + STARTING = "starting" + RUNNING = "running" + DONE = "done" + STOPPING = "stopping" + ERROR = "error" + + +class AppStatus(BaseModel): + """Status of an app.""" + + info: AppInfo + state: AppState + error: str | None = None + + +@dataclass +class RunningApp: + """Information about a running app.""" + + app: "ReachyMiniApp" + thread: Thread + status: AppStatus + + +class AppManager: + """Manager for Reachy Mini apps.""" + + def __init__(self) -> None: + """Initialize the AppManager.""" + self.current_app = None # type: RunningApp | None + self.logger = logging.getLogger("reachy_mini.apps.manager") + + async def close(self) -> None: + """Clean up the AppManager, stopping any running app.""" + if self.is_app_running(): + await self.stop_current_app() + + # App lifecycle management + # Only one app can be started at a time for now + def is_app_running(self) -> bool: + """Check if an app is currently running.""" + return self.current_app is not None and self.current_app.status.state in ( + AppState.STARTING, + AppState.RUNNING, + AppState.ERROR, + ) + + async def start_app(self, app_name: str, *args: Any, **kwargs: Any) -> AppStatus: + """Start the app, raises RuntimeError if an app is already running.""" + if self.is_app_running(): + raise RuntimeError("An app is already running") + + (ep,) = entry_points(group="reachy_mini_apps", name=app_name) + app = ep.load()() + + def wrapped_run() -> None: + assert self.current_app is not None + + try: + self.current_app.status.state = AppState.RUNNING + self.logger.getChild("runner").info(f"App {app_name} is running") + app.wrapped_run(*args, **kwargs) + self.current_app.status.state = AppState.DONE + self.logger.getChild("runner").info(f"App {app_name} finished") + except Exception as e: + self.logger.getChild("runner").error( + f"An error occurred in the app {app_name}: {e}" + ) + self.logger.getChild("runner").error( + f"Exception details: '{app.error}'", + ) + self.current_app.status.state = AppState.ERROR + self.current_app.status.error = str(app.error) + + self.current_app = RunningApp( + status=AppStatus( + info=AppInfo(name=app_name, source_kind=SourceKind.INSTALLED), + state=AppState.STARTING, + error=None, + ), + app=app, + thread=Thread(target=wrapped_run), + ) + self.logger.getChild("runner").info(f"Starting app {app_name}") + self.current_app.thread.start() + + return self.current_app.status + + async def stop_current_app(self, timeout: float | None = 5.0) -> None: + """Stop the current app.""" + if not self.is_app_running(): + raise RuntimeError("No app is currently running") + + assert self.current_app is not None + + self.current_app.status.state = AppState.STOPPING + self.logger.getChild("runner").info( + f"Stopping app {self.current_app.status.info.name}" + ) + self.current_app.app.stop() + self.current_app.thread.join(timeout) + + if self.current_app.thread.is_alive(): + self.logger.getChild("runner").warning( + "The app did not stop within the timeout" + ) + else: + self.logger.getChild("runner").info("App stopped successfully") + + self.current_app = None + + async def restart_current_app(self) -> AppStatus: + """Restart the current app.""" + if not self.is_app_running(): + raise RuntimeError("No app is currently running") + + assert self.current_app is not None + + app_info = self.current_app.status.info + + await self.stop_current_app() + await self.start_app(app_info.name) + + return self.current_app.status + + async def current_app_status(self) -> Optional[AppStatus]: + """Get the current status of the app.""" + if self.current_app is not None: + return self.current_app.status + return None + + # Apps management interface + async def list_all_available_apps(self) -> list[AppInfo]: + """List available apps (parallel async).""" + results = await asyncio.gather( + *[self.list_available_apps(kind) for kind in SourceKind] + ) + return sum(results, []) + + async def list_available_apps(self, source: SourceKind) -> list[AppInfo]: + """List available apps for given source kind.""" + if source == SourceKind.HF_SPACE: + return await hf_space.list_all_apps() + elif source == SourceKind.DASHBOARD_SELECTION: + return await hf_space.list_available_apps() + elif source == SourceKind.INSTALLED: + return await local_common_venv.list_available_apps() + elif source == SourceKind.LOCAL: + return [] + else: + raise NotImplementedError(f"Unknown source kind: {source}") + + async def install_new_app(self, app: AppInfo, logger: logging.Logger) -> None: + """Install a new app by name.""" + success = await local_common_venv.install_package(app, logger) + if success != 0: + raise RuntimeError(f"Failed to install app '{app.name}'") + + async def remove_app(self, app_name: str, logger: logging.Logger) -> None: + """Remove an installed app by name.""" + success = await local_common_venv.uninstall_package(app_name, logger) + if success != 0: + raise RuntimeError(f"Failed to uninstall app '{app_name}'") diff --git a/reachy_mini/src/reachy_mini/apps/sources/__init__.py b/reachy_mini/src/reachy_mini/apps/sources/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9c83411aac64dca6fe6597f174ab5e7f22ab5f16 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/sources/__init__.py @@ -0,0 +1,4 @@ +"""Specific app sources. + +For the moment, only huggingface spaces is implemented. +""" diff --git a/reachy_mini/src/reachy_mini/apps/sources/hf_space.py b/reachy_mini/src/reachy_mini/apps/sources/hf_space.py new file mode 100644 index 0000000000000000000000000000000000000000..23dc5d2752168487bacfe0cc5ceb7433c5b6d9e7 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/sources/hf_space.py @@ -0,0 +1,105 @@ +"""Hugging Face Spaces app source.""" + +import asyncio +import json +from typing import Any, Dict + +import aiohttp + +from .. import AppInfo, SourceKind + +# Constants +AUTHORIZED_APP_LIST_URL = "https://huggingface.co/datasets/pollen-robotics/reachy-mini-official-app-store/raw/main/app-list.json" +HF_SPACES_API_URL = "https://huggingface.co/api/spaces" +HF_SPACES_FILTER_URL = "https://huggingface.co/api/spaces?filter=reachy_mini&sort=likes&direction=-1&limit=50&full=true" +REQUEST_TIMEOUT = aiohttp.ClientTimeout(total=30) + + +async def _fetch_space_data( + session: aiohttp.ClientSession, space_id: str +) -> Dict[str, Any] | None: + """Fetch data for a single space from Hugging Face API.""" + url = f"{HF_SPACES_API_URL}/{space_id}" + try: + async with session.get(url, timeout=REQUEST_TIMEOUT) as response: + if response.status == 200: + data: Dict[str, Any] = await response.json() + return data + else: + return None + except (aiohttp.ClientError, asyncio.TimeoutError): + return None + + +async def list_available_apps() -> list[AppInfo]: + """List apps available on Hugging Face Spaces.""" + async with aiohttp.ClientSession(timeout=REQUEST_TIMEOUT) as session: + # Fetch the list of authorized app IDs + try: + async with session.get(AUTHORIZED_APP_LIST_URL) as response: + response.raise_for_status() + text = await response.text() + authorized_ids = json.loads(text) + except (aiohttp.ClientError, json.JSONDecodeError): + return [] + + if not isinstance(authorized_ids, list): + return [] + + # Filter to only string elements + authorized_ids = [ + space_id for space_id in authorized_ids if isinstance(space_id, str) + ] + + # Fetch data for each space in parallel + tasks = [_fetch_space_data(session, space_id) for space_id in authorized_ids] + spaces_data = await asyncio.gather(*tasks) + + # Build AppInfo list from fetched data + apps = [] + for item in spaces_data: + if item is None or "id" not in item: + continue + + apps.append( + AppInfo( + name=item["id"].split("/")[-1], + description=item.get("cardData", {}).get("short_description", ""), + url=f"https://huggingface.co/spaces/{item['id']}", + source_kind=SourceKind.HF_SPACE, + extra=item, + ) + ) + + return apps + + +async def list_all_apps() -> list[AppInfo]: + """List all apps available on Hugging Face Spaces (including unofficial ones).""" + async with aiohttp.ClientSession(timeout=REQUEST_TIMEOUT) as session: + try: + async with session.get(HF_SPACES_FILTER_URL) as response: + response.raise_for_status() + data: list[Dict[str, Any]] = await response.json() + except (aiohttp.ClientError, json.JSONDecodeError, asyncio.TimeoutError): + return [] + + if not isinstance(data, list): + return [] + + apps = [] + for item in data: + if item is None or "id" not in item: + continue + + apps.append( + AppInfo( + name=item["id"].split("/")[-1], + description=item.get("cardData", {}).get("short_description", ""), + url=f"https://huggingface.co/spaces/{item['id']}", + source_kind=SourceKind.HF_SPACE, + extra=item, + ) + ) + + return apps diff --git a/reachy_mini/src/reachy_mini/apps/sources/local_common_venv.py b/reachy_mini/src/reachy_mini/apps/sources/local_common_venv.py new file mode 100644 index 0000000000000000000000000000000000000000..9100adb1efbe7c49c5fecace50cda77be126d217 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/sources/local_common_venv.py @@ -0,0 +1,61 @@ +"""Utilities for local common venv apps source.""" + +import logging +import sys +from importlib.metadata import entry_points + +from .. import AppInfo, SourceKind +from ..utils import running_command + + +async def list_available_apps() -> list[AppInfo]: + """List apps available from entry points.""" + entry_point_apps = list(entry_points(group="reachy_mini_apps")) + + apps = [] + + for ep in entry_point_apps: + custom_app_url = None + try: + app = ep.load() + custom_app_url = app.custom_app_url + except Exception as e: + logging.getLogger("reachy_mini.apps").warning( + f"Could not load app '{ep.name}' from entry point: {e}" + ) + apps.append( + AppInfo( + name=ep.name, + source_kind=SourceKind.INSTALLED, + extra={"custom_app_url": custom_app_url}, + ) + ) + + return apps + + +async def install_package(app: AppInfo, logger: logging.Logger) -> int: + """Install a package given an AppInfo object, streaming logs.""" + if app.source_kind == SourceKind.HF_SPACE: + target = f"git+{app.url}" if app.url is not None else app.name + elif app.source_kind == SourceKind.LOCAL: + target = app.extra.get("path", app.name) + else: + raise ValueError(f"Cannot install app from source kind '{app.source_kind}'") + + return await running_command( + [sys.executable, "-m", "pip", "install", target], + logger=logger, + ) + + +async def uninstall_package(app_name: str, logger: logging.Logger) -> int: + """Uninstall a package given an app name.""" + existing_apps = await list_available_apps() + if app_name not in [app.name for app in existing_apps]: + raise ValueError(f"Cannot uninstall app '{app_name}': it is not installed") + + return await running_command( + [sys.executable, "-m", "pip", "uninstall", "-y", app_name], + logger=logger, + ) diff --git a/reachy_mini/src/reachy_mini/apps/templates/README.md.j2 b/reachy_mini/src/reachy_mini/apps/templates/README.md.j2 new file mode 100644 index 0000000000000000000000000000000000000000..965c2474d5b21abcca0606a3abc401bb2a310a89 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/templates/README.md.j2 @@ -0,0 +1,11 @@ +--- +title: {{ class_name_display }} +emoji: 👋 +colorFrom: red +colorTo: blue +sdk: static +pinned: false +short_description: Write your description here +tags: + - reachy_mini +--- \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/apps/templates/index.html.j2 b/reachy_mini/src/reachy_mini/apps/templates/index.html.j2 new file mode 100644 index 0000000000000000000000000000000000000000..2f0ce85c63c071b48a36f3d7234f3743b3084413 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/templates/index.html.j2 @@ -0,0 +1,235 @@ + + + + + + + {{ class_name_display }} + + + + +
+
+
🤖⚡
+

{{ class_name_display }}

+

Enter your tagline here

+
+
+ +
+
+
+
+
🛠️
+
+
+
+
+ +
+
+

Install This App

+ +
+ + +
+ + + +
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/apps/templates/main.py.j2 b/reachy_mini/src/reachy_mini/apps/templates/main.py.j2 new file mode 100644 index 0000000000000000000000000000000000000000..2db6dd065981435fbe9d07f23b23ac7edf7f2e8f --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/templates/main.py.j2 @@ -0,0 +1,50 @@ +import threading + +from reachy_mini import ReachyMini, ReachyMiniApp +from reachy_mini.utils import create_head_pose + + +class {{ class_name }}(ReachyMiniApp): + # Optional: URL to a custom configuration page for the app + # eg. "http://localhost:8042/settings" + custom_app_url: str | None = None + + def run(self, reachy_mini: ReachyMini, stop_event: threading.Event): + # Write your code here + # ReachyMini is already initialized and connected + # Check the stop_event to gracefully exit the loop + # Example: + # import time + # import numpy as np + # + # t0 = time.time() + # + # while not stop_event.is_set(): + # t = time.time() - t0 + # + # yaw = 30 * np.sin(2 * np.pi * 0.5 * t) + # head_pose = create_head_pose(yaw=yaw, degrees=True) + # + # reachy_mini.set_target(head=head_pose) + # + # time.sleep(0.01) + + print("This is a placeholder for your app logic.") + + +if __name__ == "__main__": + # You can run the app directly from this script + with ReachyMini() as mini: + app = {{ class_name }}() + + stop = threading.Event() + + try: + print("Running '{{ app_name }}' a ReachyMiniApp...") + print("Press Ctrl+C to stop the app.") + app.run(mini, stop) + print("App has stopped.") + + except KeyboardInterrupt: + print("Stopping the app...") + stop.set() diff --git a/reachy_mini/src/reachy_mini/apps/templates/pyproject.toml.j2 b/reachy_mini/src/reachy_mini/apps/templates/pyproject.toml.j2 new file mode 100644 index 0000000000000000000000000000000000000000..196f71436980b01e5c8f4aad537ea02b87cf4e66 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/templates/pyproject.toml.j2 @@ -0,0 +1,18 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + + +[project] +name = "{{ app_name }}" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "reachy-mini" +] +keywords = ["reachy-mini-app"] + +[project.entry-points."reachy_mini_apps"] +{{ app_name }} = "{{ module_name }}.main:{{ class_name }}" \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/apps/templates/style.css.j2 b/reachy_mini/src/reachy_mini/apps/templates/style.css.j2 new file mode 100644 index 0000000000000000000000000000000000000000..64fab914657a8fb5757e9038c31683d933f773d7 --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/templates/style.css.j2 @@ -0,0 +1,411 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + line-height: 1.6; + color: #333; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; +} + +.hero { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 4rem 2rem; + text-align: center; +} + +.hero-content { + max-width: 800px; + margin: 0 auto; +} + +.app-icon { + font-size: 4rem; + margin-bottom: 1rem; + display: inline-block; +} + +.hero h1 { + font-size: 3rem; + font-weight: 700; + margin-bottom: 1rem; + background: linear-gradient(45deg, #fff, #f0f9ff); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.tagline { + font-size: 1.25rem; + opacity: 0.9; + max-width: 600px; + margin: 0 auto; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 2rem; + position: relative; + z-index: 2; +} + +.main-card { + background: white; + border-radius: 20px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); + margin-top: -2rem; + overflow: hidden; + margin-bottom: 3rem; +} + +.app-preview { + background: linear-gradient(135deg, #1e3a8a, #3b82f6); + padding: 3rem; + color: white; + text-align: center; + position: relative; +} + +.preview-image { + background: #000; + border-radius: 15px; + padding: 2rem; + max-width: 500px; + margin: 0 auto; + position: relative; + overflow: hidden; +} + +.camera-feed { + font-size: 4rem; + margin-bottom: 1rem; + opacity: 0.7; +} + +.detection-overlay { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 100%; +} + +.bbox { + background: rgba(34, 197, 94, 0.9); + color: white; + padding: 0.5rem 1rem; + border-radius: 8px; + font-size: 0.9rem; + font-weight: 600; + margin: 0.5rem; + display: inline-block; + border: 2px solid #22c55e; +} + +.app-details { + padding: 3rem; +} + +.app-details h2 { + font-size: 2rem; + color: #1e293b; + margin-bottom: 2rem; + text-align: center; +} + +.template-info { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 2rem; + margin-bottom: 3rem; +} + +.info-box { + background: #f0f9ff; + border: 2px solid #e0f2fe; + border-radius: 12px; + padding: 2rem; +} + +.info-box h3 { + color: #0c4a6e; + margin-bottom: 1rem; + font-size: 1.2rem; +} + +.info-box p { + color: #0369a1; + line-height: 1.6; +} + +.how-to-use { + background: #fefce8; + border: 2px solid #fde047; + border-radius: 12px; + padding: 2rem; + margin-top: 3rem; +} + +.how-to-use h3 { + color: #a16207; + margin-bottom: 1.5rem; + font-size: 1.3rem; + text-align: center; +} + +.steps { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.step { + display: flex; + align-items: flex-start; + gap: 1rem; +} + +.step-number { + background: #eab308; + color: white; + width: 2rem; + height: 2rem; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + flex-shrink: 0; +} + +.step h4 { + color: #a16207; + margin-bottom: 0.5rem; + font-size: 1.1rem; +} + +.step p { + color: #ca8a04; +} + +.download-card { + background: white; + border-radius: 20px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); + padding: 3rem; + text-align: center; +} + +.download-card h2 { + font-size: 2rem; + color: #1e293b; + margin-bottom: 1rem; +} + +.download-card>p { + color: #64748b; + font-size: 1.1rem; + margin-bottom: 2rem; +} + +.dashboard-config { + margin-bottom: 2rem; + text-align: left; + max-width: 400px; + margin-left: auto; + margin-right: auto; +} + +.dashboard-config label { + display: block; + color: #374151; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.dashboard-config input { + width: 100%; + padding: 0.75rem 1rem; + border: 2px solid #e5e7eb; + border-radius: 8px; + font-size: 0.95rem; + transition: border-color 0.2s; +} + +.dashboard-config input:focus { + outline: none; + border-color: #667eea; +} + +.install-btn { + background: linear-gradient(135deg, #667eea, #764ba2); + color: white; + border: none; + padding: 1.25rem 3rem; + border-radius: 16px; + font-size: 1.2rem; + font-weight: 700; + cursor: pointer; + transition: all 0.3s ease; + display: inline-flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 2rem; + box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3); +} + +.install-btn:hover:not(:disabled) { + transform: translateY(-3px); + box-shadow: 0 15px 35px rgba(102, 126, 234, 0.4); +} + +.install-btn:disabled { + opacity: 0.7; + cursor: not-allowed; + transform: none; +} + +.manual-option { + background: #f8fafc; + border-radius: 12px; + padding: 2rem; + margin-top: 2rem; +} + +.manual-option h3 { + color: #1e293b; + margin-bottom: 1rem; + font-size: 1.2rem; +} + +.manual-option>p { + color: #64748b; + margin-bottom: 1rem; +} + +.btn-icon { + font-size: 1.1rem; +} + +.install-status { + padding: 1rem; + border-radius: 8px; + font-size: 0.9rem; + text-align: center; + display: none; + margin-top: 1rem; +} + +.install-status.success { + background: #dcfce7; + color: #166534; + border: 1px solid #bbf7d0; +} + +.install-status.error { + background: #fef2f2; + color: #dc2626; + border: 1px solid #fecaca; +} + +.install-status.loading { + background: #dbeafe; + color: #1d4ed8; + border: 1px solid #bfdbfe; +} + +.install-status.info { + background: #e0f2fe; + color: #0369a1; + border: 1px solid #7dd3fc; +} + +.manual-install { + background: #1f2937; + border-radius: 8px; + padding: 1rem; + margin-bottom: 1rem; + display: flex; + align-items: center; + gap: 1rem; +} + +.manual-install code { + color: #10b981; + font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace; + font-size: 0.85rem; + flex: 1; + overflow-x: auto; +} + +.copy-btn { + background: #374151; + color: white; + border: none; + padding: 0.5rem 1rem; + border-radius: 6px; + font-size: 0.8rem; + cursor: pointer; + transition: background-color 0.2s; +} + +.copy-btn:hover { + background: #4b5563; +} + +.manual-steps { + color: #6b7280; + font-size: 0.9rem; + line-height: 1.8; +} + +.footer { + text-align: center; + padding: 2rem; + color: white; + opacity: 0.8; +} + +.footer a { + color: white; + text-decoration: none; + font-weight: 600; +} + +.footer a:hover { + text-decoration: underline; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .hero { + padding: 2rem 1rem; + } + + .hero h1 { + font-size: 2rem; + } + + .container { + padding: 0 1rem; + } + + .app-details, + .download-card { + padding: 2rem; + } + + .features-grid { + grid-template-columns: 1fr; + } + + .download-options { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/apps/utils.py b/reachy_mini/src/reachy_mini/apps/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..f039ff996ba8924501483617ba931836f7142fdc --- /dev/null +++ b/reachy_mini/src/reachy_mini/apps/utils.py @@ -0,0 +1,30 @@ +"""Utility functions for Reachy Mini apps manager.""" + +import asyncio +import logging + + +async def running_command(command: list[str], logger: logging.Logger) -> int: + """Run a shell command and stream its output to the provided logger.""" + logger.info(f"Running command: {' '.join(command)}") + + proc = await asyncio.create_subprocess_exec( + *command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + + assert proc.stdout is not None # for mypy + assert proc.stderr is not None # for mypy + + # Stream output line by line + while True: + line = await proc.stdout.readline() + if not line: + break + logger.info(line.decode().rstrip()) + + # Also log any remaining stderr + err = await proc.stderr.read() + if err: + logger.error(err.decode().rstrip()) + + return await proc.wait() diff --git a/reachy_mini/src/reachy_mini/assets/config/hardware_config.yaml b/reachy_mini/src/reachy_mini/assets/config/hardware_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..18feed39927a238ac3828ba38f3fe425d22cadd0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/config/hardware_config.yaml @@ -0,0 +1,155 @@ +version: beta + +serial: + baudrate: 1000000 + +# Limits measured on the robot (in degrees) +# s1 +# lower : -48° : -546 +# upper : +80° : 910 + +# s2 +# lower: +70° : 796 +# upper: -80° : -910 + +# s3 +# lower: -48° : -546 +# upper: +80° : 910 + +# s4 +# lower: +48° : 546 +# upper: -80° : -910 + +# s5 +# lower: -70° : -796 +# upper: +80° : 910 + +# s6 +# lower : +48° : 546 +# upper : -80° : -910 + +# s1: +# lower: 2048 - 546 : 1502 +# upper: 2048 + 910 : 2958 + +# s2: +# lower: 2048 - 910 : 1138 +# upper: 2048 + 796 : 2844 + +# s3: +# lower: 2048 - 546 : 1502 +# upper: 2048 + 910 : 2958 + +# s4: +# lower: 2048 - 910 : 1138 +# upper: 2048 + 546 : 2594 + +# s5: +# lower: 2048 - 796 : 1252 +# upper: 2048 + 910 : 2958 + +# s6: +# lower: 2048 - 910 : 1138 +# upper: 2048 + 546 : 2594 + + +motors: + - body_rotation: + id: 10 + offset: 0 + lower_limit: 0 + upper_limit: 4095 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 0 + - stewart_1: + id: 11 + offset: 1024 + lower_limit: 1502 + upper_limit: 2958 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 0 + - stewart_2: + id: 12 + offset: -1024 + lower_limit: 1138 + upper_limit: 2844 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 0 + - stewart_3: + id: 13 + offset: 1024 + lower_limit: 1502 + upper_limit: 2958 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 0 + - stewart_4: + id: 14 + offset: -1024 + lower_limit: 1138 + upper_limit: 2594 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 0 + - stewart_5: + id: 15 + offset: 1024 + lower_limit: 1252 + upper_limit: 2958 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 0 + - stewart_6: + id: 16 + offset: -1024 + lower_limit: 1138 + upper_limit: 2594 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 0 + - right_antenna: + id: 17 + offset: 0 + lower_limit: 0 + upper_limit: 4095 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 400 + - left_antenna: + id: 18 + offset: 0 + lower_limit: 0 + upper_limit: 4095 + return_delay_time: 0 + shutdown_error: 52 + pid: + - 400 + - 0 + - 400 diff --git a/reachy_mini/src/reachy_mini/assets/firmware/CHANGELOG.md b/reachy_mini/src/reachy_mini/assets/firmware/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..db473c4690bf31e683494c8e314080a0efc41f60 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/firmware/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog of Reachy Mini Audio Firmware + + +## 2.1.3 + +*For Beta units only* + +Fixes the initialization issue on Reachy Mini beta hardware. An additional 2-second delay is added during initialization to prevent the XMOS chip from starting before the other components. + +There is no need to apply this firmware to the Lite and Wireless versions, as the issue is fixed at the hardware level. + +## 2.1.2 + +Improved parameters for acoustic echo cancellation (AEC). +PP_DTSENSITIVE is set to 1 by default. \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.2.bin b/reachy_mini/src/reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.2.bin new file mode 100644 index 0000000000000000000000000000000000000000..6314af04676bac273aab5a795a36632813afe685 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.2.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:661429a93b155cdbfed1e6c214820fd42e3372a08c3930f14fcd4e6db5be6796 +size 933888 diff --git a/reachy_mini/src/reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.3.bin b/reachy_mini/src/reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.3.bin new file mode 100644 index 0000000000000000000000000000000000000000..680a99700de092ac1d191848518ea6aa9fe2c846 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.3.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e35fa9a43a4e75890fd6299e62e85310d8081087e6a9702aaef0c81bd3af283 +size 933888 diff --git a/reachy_mini/src/reachy_mini/assets/firmware/update.sh b/reachy_mini/src/reachy_mini/assets/firmware/update.sh new file mode 100755 index 0000000000000000000000000000000000000000..e6f0f3243a81e1edb4667e09660a30f13ae51b01 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/firmware/update.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Firmware update script for Reachy Mini +# Usage: ./update.sh +firmware="$1" +if [ -z "$firmware" ]; then + echo "Usage: $0 " + exit 1 +fi +dfu-util -R -e -a 1 -D "$firmware" \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/assets/kinematics_data.json b/reachy_mini/src/reachy_mini/assets/kinematics_data.json new file mode 100644 index 0000000000000000000000000000000000000000..c20b364f6c386f17f8cc2c3901df873583fc1d31 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/kinematics_data.json @@ -0,0 +1,253 @@ +{ + "motor_arm_length": 0.04000000000000001, + "rod_length": 0.08499999999999995, + "head_z_offset": 0.177, + "motors": [ + { + "name": "stewart_1", + "branch_frame": "closing_1_2", + "offset": 0, + "solution": 0, + "T_motor_world": [ + [ + 0.8660247915798898, + -0.5000010603626028, + -2.298079077119539e-06, + -0.009999848080267933 + ], + [ + 4.490195936008854e-06, + 3.1810770986818273e-06, + 0.999999999984859, + -0.07663346037245178 + ], + [ + -0.500001060347722, + -0.8660247915770963, + 4.999994360718464e-06, + 0.03666015757925319 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "branch_position": [ + 0.020648178337122566, + 0.021763723638894568, + 1.0345743467476964e-07 + ], + "limits": [ + -3.141592653589793, + 3.141592653589793 + ] + }, + { + "name": "stewart_2", + "branch_frame": "closing_2_2", + "offset": 0, + "solution": 1, + "T_motor_world": [ + [ + -0.8660211183436269, + 0.5000074225224785, + 2.298069723064582e-06, + -0.01000055227585102 + ], + [ + -4.490219645842903e-06, + -3.181063409649239e-06, + -0.999999999984859, + 0.07663346037219607 + ], + [ + -0.5000074225075973, + -0.8660211183408337, + 5.00001124330122e-06, + 0.03666008712637943 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "branch_position": [ + 0.00852381571767217, + 0.028763668526131346, + 1.183437210727778e-07 + ], + "limits": [ + -3.141592653589793, + 3.141592653589793 + ] + }, + { + "name": "stewart_3", + "branch_frame": "closing_3_2", + "offset": 0, + "solution": 0, + "T_motor_world": [ + [ + 6.326794896519466e-06, + 0.9999999999799852, + -7.0550646912150425e-12, + -0.009999884140839245 + ], + [ + -1.0196153102346142e-06, + 1.3505961633338446e-11, + 0.9999999999994795, + -0.07663346037438698 + ], + [ + 0.9999999999794655, + -6.326794896940104e-06, + 1.0196153098685706e-06, + 0.036660683387545835 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "branch_position": [ + -0.029172011376922807, + 0.0069999429399361995, + 4.0290270064691214e-08 + ], + "limits": [ + -3.141592653589793, + 3.141592653589793 + ] + }, + { + "name": "stewart_4", + "branch_frame": "closing_4_2", + "offset": 0, + "solution": 1, + "T_motor_world": [ + [ + -3.673205069955933e-06, + -0.9999999999932537, + -6.767968877969483e-14, + -0.010000000000897517 + ], + [ + 1.0196153102837198e-06, + -3.6775764393585005e-12, + -0.9999999999994795, + 0.0766334603742898 + ], + [ + 0.9999999999927336, + -3.673205070385213e-06, + 1.0196153102903487e-06, + 0.03666065685180194 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "branch_position": [ + -0.029172040355214434, + -0.0069999960097160766, + -3.1608172912367394e-08 + ], + "limits": [ + -3.141592653589793, + 3.141592653589793 + ] + }, + { + "name": "stewart_5", + "branch_frame": "closing_5_2", + "offset": 0, + "solution": 0, + "T_motor_world": [ + [ + -0.8660284647694133, + -0.4999946981757419, + 2.298079429767357e-06, + -0.010000231529504576 + ], + [ + 4.490172883391843e-06, + -3.1811099293773187e-06, + 0.9999999999848591, + -0.07663346037246624 + ], + [ + -0.4999946981608617, + 0.8660284647666201, + 4.999994384073154e-06, + 0.03666016059492482 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "branch_position": [ + 0.008523809101930114, + -0.028763713010385224, + -1.4344916837716326e-07 + ], + "limits": [ + -3.141592653589793, + 3.141592653589793 + ] + }, + { + "name": "stewart_6", + "branch_frame": "passive_7_link_y", + "offset": 0, + "solution": 1, + "T_motor_world": [ + [ + 0.8660247915798897, + 0.5000010603626025, + -2.298069644866714e-06, + -0.009999527331574583 + ], + [ + -4.490196220318687e-06, + 3.1810964558725514e-06, + -0.9999999999848591, + 0.07663346037272492 + ], + [ + -0.500001060347722, + 0.8660247915770967, + 5.000011266610794e-06, + 0.036660231042625266 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "branch_position": [ + 0.020648186722822436, + -0.02176369606185343, + -8.957920105689965e-08 + ], + "limits": [ + -3.141592653589793, + 3.141592653589793 + ] + } + ] +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/assets/models/fknetwork.dynamic.onnx b/reachy_mini/src/reachy_mini/assets/models/fknetwork.dynamic.onnx new file mode 100644 index 0000000000000000000000000000000000000000..c7edae28297689eed85a3306345b8931cd6be1c4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/models/fknetwork.dynamic.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:baeb97ce5f28c649151bebe8fc6a0a8e481b21e8e31346c9a665e792e41f9289 +size 75827 diff --git a/reachy_mini/src/reachy_mini/assets/models/fknetwork.onnx b/reachy_mini/src/reachy_mini/assets/models/fknetwork.onnx new file mode 100644 index 0000000000000000000000000000000000000000..67f4c79c4f44fe2a3bf8c6684143218d96b2b3bd --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/models/fknetwork.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf0d2350c67636349a5f3de056cb8823a68fedfd31c4ac6fcde2dd245dee5f57 +size 75209 diff --git a/reachy_mini/src/reachy_mini/assets/models/fknetwork_int8.onnx b/reachy_mini/src/reachy_mini/assets/models/fknetwork_int8.onnx new file mode 100644 index 0000000000000000000000000000000000000000..df0fd772e892eea675ed2667adb6121388297051 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/models/fknetwork_int8.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c693ac748a340d1398d6d2b8b906e76ffe9aec066b709412b4a618b34f57422 +size 42162 diff --git a/reachy_mini/src/reachy_mini/assets/models/iknetwork.onnx b/reachy_mini/src/reachy_mini/assets/models/iknetwork.onnx new file mode 100644 index 0000000000000000000000000000000000000000..7b955057ecabc5779fa30e3a826de13a809a2930 --- /dev/null +++ b/reachy_mini/src/reachy_mini/assets/models/iknetwork.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:538be065edaf18f75ae05f4c17fe36b5b098cd5c72d6d4d3cb6152c40de68d27 +size 75213 diff --git a/reachy_mini/src/reachy_mini/daemon/__init__.py b/reachy_mini/src/reachy_mini/daemon/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..945ec88eb820cd78614e4fde4c38f86bcb615ffc --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/__init__.py @@ -0,0 +1 @@ +"""Daemon for Reachy Mini.""" diff --git a/reachy_mini/src/reachy_mini/daemon/app/__init__.py b/reachy_mini/src/reachy_mini/daemon/app/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7d7c49bda267ff648789e31738bbd5f0895a8108 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/__init__.py @@ -0,0 +1 @@ +"""FastAPI app initialization.""" diff --git a/reachy_mini/src/reachy_mini/daemon/app/bg_job_register.py b/reachy_mini/src/reachy_mini/daemon/app/bg_job_register.py new file mode 100644 index 0000000000000000000000000000000000000000..ec4ae598cb1ec98bcefe1e1446284287cb8920ed --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/bg_job_register.py @@ -0,0 +1,142 @@ +"""Background jobs management for Reachy Mini Daemon.""" + +import asyncio +import logging +import threading +import uuid +from dataclasses import dataclass +from enum import Enum +from typing import Any, Awaitable, Callable + +from fastapi import WebSocket, WebSocketDisconnect +from pydantic import BaseModel + + +class JobStatus(Enum): + """Enum for job status.""" + + PENDING = "pending" + IN_PROGRESS = "in_progress" + DONE = "done" + FAILED = "failed" + + +class JobInfo(BaseModel): + """Pydantic model for install job status.""" + + command: str + status: JobStatus + logs: list[str] + + +@dataclass +class JobHandler: + """Handler for background jobs.""" + + uuid: str + info: JobInfo + new_log_evt: dict[str, asyncio.Event] + + +register: dict[str, JobHandler] = {} + + +def run_command( + command: str, + coro_func: Callable[..., Awaitable[None]], + *args: Any, +) -> str: + """Start a background job, with a custom logger and return its job_id.""" + job_uuid = str(uuid.uuid4()) + + jh = JobHandler( + uuid=job_uuid, + info=JobInfo(command=command, status=JobStatus.PENDING, logs=[]), + new_log_evt={}, + ) + register[job_uuid] = jh + + start_evt = threading.Event() + + async def wrapper() -> None: + jh.info.status = JobStatus.IN_PROGRESS + + class JobLogger(logging.Handler): + def emit(self, record: logging.LogRecord) -> None: + jh.info.logs.append(self.format(record)) + for ws in jh.new_log_evt.values(): + ws.set() + + logger = logging.getLogger(f"logs_job_{job_uuid}") + logger.setLevel(logging.INFO) + logger.handlers.clear() + logger.addHandler(JobLogger()) + + start_evt.set() + + try: + await coro_func(*args, logger=logger) + jh.info.status = JobStatus.DONE + logger.info(f"Job '{command}' completed successfully") + except Exception as e: + jh.info.status = JobStatus.FAILED + logger.error(f"Job '{command}' failed with error: {e}") + + t = threading.Thread(target=lambda: asyncio.run(wrapper())) + t.start() + # background_tasks.add_task(wrapper) + start_evt.wait() + + return job_uuid + + +def get_info(job_id: str) -> JobInfo: + """Get the info of a job by its ID.""" + job = register.get(job_id) + + if not job: + raise ValueError("Job ID not found") + + return job.info + + +async def ws_poll_info(websocket: WebSocket, job_uuid: str) -> None: + """WebSocket endpoint to stream job logs in real time.""" + job = register.get(job_uuid) + if not job: + await websocket.send_json({"error": "Job ID not found"}) + await websocket.close() + return + + assert job is not None + + ws_uuid = str(uuid.uuid4()) + last_log_len = 0 + + try: + job.new_log_evt[ws_uuid] = asyncio.Event() + + while True: + await job.new_log_evt[ws_uuid].wait() + job.new_log_evt[ws_uuid].clear() + + new_logs = job.info.logs[last_log_len:] + + if new_logs: + for log_entry in new_logs: + await websocket.send_text(log_entry) + last_log_len = len(job.info.logs) + + await websocket.send_text( + JobInfo( + command=job.info.command, + status=job.info.status, + logs=new_logs, + ).model_dump_json() + ) + if job.info.status in (JobStatus.DONE, JobStatus.FAILED): + break + except WebSocketDisconnect: + pass + finally: + job.new_log_evt.pop(ws_uuid, None) diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/KO-cartoon-static.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/KO-cartoon-static.svg new file mode 100644 index 0000000000000000000000000000000000000000..98262b9c367727ebbf14d39128164308f607286e --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/KO-cartoon-static.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ad9c44f9971b0d5129493f099f182d6ea42d790f9d9e25e79b31acecba5e414 +size 5677 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon-static.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon-static.svg new file mode 100644 index 0000000000000000000000000000000000000000..a9c0a5395a9e595294a6cf3805b50a59a3fb5bec --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon-static.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c752c76e3786b07cc3c25b97dc09da49d7388fdf2cb044d3747aa38f56535ae4 +size 544172 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon.svg new file mode 100644 index 0000000000000000000000000000000000000000..a03162a458b2ab45182aea1039a4ebfb6b22316b --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8867ef0f9bd9edd64c2863e99d722fbf45f9f0bb232c4a9df2e63c8c2c2a3213 +size 46179 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/go-to-sleep-cartoon.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/go-to-sleep-cartoon.svg new file mode 100644 index 0000000000000000000000000000000000000000..e38bf61908b47769784228f4d0316caeceb13d1e --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/go-to-sleep-cartoon.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6c68f0fdae00154dc687e68684c945dd4a8ffc9e626add679150174974a818d +size 46008 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon-static.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon-static.svg new file mode 100644 index 0000000000000000000000000000000000000000..6a83dd99b256b478b6d9c64bb41329aa015bb4c8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon-static.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2803946419f768faa7b9bc5c63a513fc677069df7c463981ac64f31e89f40cec +size 7648 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon.svg new file mode 100644 index 0000000000000000000000000000000000000000..c9509e78855e191f6dcd6b6aa5bce2599f25cbe9 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5ff91ca4030d428fd71f9e572bd5a97be6c0704e98fcaecd5d985ee15a7b053 +size 47411 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-awake.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-awake.svg new file mode 100644 index 0000000000000000000000000000000000000000..7c5bd3e899bb9a6c224a859a515ab0975ad055e5 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-awake.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc04ba0461049d0ddb26bc18dd24d61a56743f7ae0a6b8967cf3c03e660187e4 +size 2541 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-connection-lost-animation.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-connection-lost-animation.svg new file mode 100644 index 0000000000000000000000000000000000000000..7217dc20bb2652bd538eef9a85842cf708e8c7b8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-connection-lost-animation.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2bba63d3b2c480f92d551e1fdb0d372672793803caacd3aaeb896967c1a64cb +size 44803 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-go-to-sleep-animation.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-go-to-sleep-animation.svg new file mode 100644 index 0000000000000000000000000000000000000000..52e8e9386662924a4b77a56f50b199393f757d79 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-go-to-sleep-animation.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6adbf645766a903289ec673ff3b04df5731691c0ab0c6a52cbb9bcd9f47f621 +size 43776 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko-animation.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko-animation.svg new file mode 100644 index 0000000000000000000000000000000000000000..b5b16f34cdbe57fa0bedbebfaf29b45c1909d2d3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko-animation.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c3c13332ae04bbb408be3f10bd176d9a6487c4daf110af95bb17f4526a5df510 +size 43684 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko.svg new file mode 100644 index 0000000000000000000000000000000000000000..14a872bfe00e3f2512f2788512299882a33a37f7 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d98d1352eb846fd1ae44453ca082e382b9fae43690159d4660edd6a1dd15c739 +size 3005 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping-static.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping-static.svg new file mode 100644 index 0000000000000000000000000000000000000000..a8f7f0f3d4d0277960c29284664a11420de0e512 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping-static.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:80dda399747505fba019b9392a151a90c812731fe31d5a06bb17276c61ad19d2 +size 6163 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping.svg new file mode 100644 index 0000000000000000000000000000000000000000..9d96eadf7b0903d7832e6ca7aa4a2af9f65df11b --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e36a601426886c7ee278b4e97e35a70f6616ec3583f9c89062bc39a868b8240d +size 2520 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-wake-up-animation.svg b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-wake-up-animation.svg new file mode 100644 index 0000000000000000000000000000000000000000..3872e016d9ed12c0442383b850f4097d88599105 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-wake-up-animation.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb5546e131073597f6b1d0f06aabfca05639432b3af8d7667904ed827fc15809 +size 44077 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/css/app.css b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/css/app.css new file mode 100644 index 0000000000000000000000000000000000000000..8d5a9c7ab463e68d51a3e19203c6af858b8b6e57 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/css/app.css @@ -0,0 +1,1433 @@ +/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */ +@layer properties; +@layer theme, base, components, utilities; +@layer theme { + :root, :host { + --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + --color-red-300: oklch(80.8% 0.114 19.571); + --color-red-400: oklch(70.4% 0.191 22.216); + --color-red-500: oklch(63.7% 0.237 25.331); + --color-red-600: oklch(57.7% 0.245 27.325); + --color-red-700: oklch(50.5% 0.213 27.518); + --color-red-800: oklch(44.4% 0.177 26.899); + --color-yellow-500: oklch(79.5% 0.184 86.047); + --color-green-300: oklch(87.1% 0.15 154.449); + --color-green-400: oklch(79.2% 0.209 151.711); + --color-green-500: oklch(72.3% 0.219 149.579); + --color-green-600: oklch(62.7% 0.194 149.214); + --color-green-700: oklch(52.7% 0.154 150.069); + --color-green-800: oklch(44.8% 0.119 151.328); + --color-blue-300: oklch(80.9% 0.105 251.813); + --color-blue-500: oklch(62.3% 0.214 259.815); + --color-blue-600: oklch(54.6% 0.245 262.881); + --color-blue-700: oklch(48.8% 0.243 264.376); + --color-blue-800: oklch(42.4% 0.199 265.638); + --color-gray-50: oklch(98.5% 0.002 247.839); + --color-gray-100: oklch(96.7% 0.003 264.542); + --color-gray-200: oklch(92.8% 0.006 264.531); + --color-gray-300: oklch(87.2% 0.01 258.338); + --color-gray-400: oklch(70.7% 0.022 261.325); + --color-gray-500: oklch(55.1% 0.027 264.364); + --color-gray-600: oklch(44.6% 0.03 256.802); + --color-gray-700: oklch(37.3% 0.034 259.733); + --color-gray-900: oklch(21% 0.034 264.665); + --color-white: #fff; + --spacing: 0.25rem; + --container-md: 28rem; + --container-2xl: 42rem; + --text-xs: 0.75rem; + --text-xs--line-height: calc(1 / 0.75); + --text-sm: 0.875rem; + --text-sm--line-height: calc(1.25 / 0.875); + --text-base: 1rem; + --text-base--line-height: calc(1.5 / 1); + --text-lg: 1.125rem; + --text-lg--line-height: calc(1.75 / 1.125); + --text-xl: 1.25rem; + --text-xl--line-height: calc(1.75 / 1.25); + --font-weight-medium: 500; + --font-weight-semibold: 600; + --radius-lg: 0.5rem; + --default-transition-duration: 150ms; + --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + --default-font-family: var(--font-sans); + --default-mono-font-family: var(--font-mono); + } +} +@layer base { + *, ::after, ::before, ::backdrop, ::file-selector-button { + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0 solid; + } + html, :host { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + tab-size: 4; + font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); + font-feature-settings: var(--default-font-feature-settings, normal); + font-variation-settings: var(--default-font-variation-settings, normal); + -webkit-tap-highlight-color: transparent; + } + hr { + height: 0; + color: inherit; + border-top-width: 1px; + } + abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + } + h1, h2, h3, h4, h5, h6 { + font-size: inherit; + font-weight: inherit; + } + a { + color: inherit; + -webkit-text-decoration: inherit; + text-decoration: inherit; + } + b, strong { + font-weight: bolder; + } + code, kbd, samp, pre { + font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); + font-feature-settings: var(--default-mono-font-feature-settings, normal); + font-variation-settings: var(--default-mono-font-variation-settings, normal); + font-size: 1em; + } + small { + font-size: 80%; + } + sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + sub { + bottom: -0.25em; + } + sup { + top: -0.5em; + } + table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; + } + :-moz-focusring { + outline: auto; + } + progress { + vertical-align: baseline; + } + summary { + display: list-item; + } + ol, ul, menu { + list-style: none; + } + img, svg, video, canvas, audio, iframe, embed, object { + display: block; + vertical-align: middle; + } + img, video { + max-width: 100%; + height: auto; + } + button, input, select, optgroup, textarea, ::file-selector-button { + font: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + letter-spacing: inherit; + color: inherit; + border-radius: 0; + background-color: transparent; + opacity: 1; + } + :where(select:is([multiple], [size])) optgroup { + font-weight: bolder; + } + :where(select:is([multiple], [size])) optgroup option { + padding-inline-start: 20px; + } + ::file-selector-button { + margin-inline-end: 4px; + } + ::placeholder { + opacity: 1; + } + @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { + ::placeholder { + color: currentcolor; + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, currentcolor 50%, transparent); + } + } + } + textarea { + resize: vertical; + } + ::-webkit-search-decoration { + -webkit-appearance: none; + } + ::-webkit-date-and-time-value { + min-height: 1lh; + text-align: inherit; + } + ::-webkit-datetime-edit { + display: inline-flex; + } + ::-webkit-datetime-edit-fields-wrapper { + padding: 0; + } + ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field { + padding-block: 0; + } + ::-webkit-calendar-picker-indicator { + line-height: 1; + } + :-moz-ui-invalid { + box-shadow: none; + } + button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button { + appearance: button; + } + ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { + height: auto; + } + [hidden]:where(:not([hidden="until-found"])) { + display: none !important; + } +} +@layer utilities { + .pointer-events-none { + pointer-events: none; + } + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; + border-width: 0; + } + .absolute { + position: absolute; + } + .fixed { + position: fixed; + } + .relative { + position: relative; + } + .static { + position: static; + } + .inset-0 { + inset: calc(var(--spacing) * 0); + } + .start-1\.5 { + inset-inline-start: calc(var(--spacing) * 1.5); + } + .end-2\.5 { + inset-inline-end: calc(var(--spacing) * 2.5); + } + .top-0 { + top: calc(var(--spacing) * 0); + } + .top-0\.5 { + top: calc(var(--spacing) * 0.5); + } + .top-1\/2 { + top: calc(1/2 * 100%); + } + .right-0 { + right: calc(var(--spacing) * 0); + } + .left-0 { + left: calc(var(--spacing) * 0); + } + .left-0\.5 { + left: calc(var(--spacing) * 0.5); + } + .z-50 { + z-index: 50; + } + .row-span-2 { + grid-row: span 2 / span 2; + } + .container { + width: 100%; + @media (width >= 40rem) { + max-width: 40rem; + } + @media (width >= 48rem) { + max-width: 48rem; + } + @media (width >= 64rem) { + max-width: 64rem; + } + @media (width >= 80rem) { + max-width: 80rem; + } + @media (width >= 96rem) { + max-width: 96rem; + } + } + .mx-auto { + margin-inline: auto; + } + .my-1 { + margin-block: calc(var(--spacing) * 1); + } + .my-2 { + margin-block: calc(var(--spacing) * 2); + } + .mt-2 { + margin-top: calc(var(--spacing) * 2); + } + .mt-3 { + margin-top: calc(var(--spacing) * 3); + } + .mt-4 { + margin-top: calc(var(--spacing) * 4); + } + .mr-2 { + margin-right: calc(var(--spacing) * 2); + } + .mb-1 { + margin-bottom: calc(var(--spacing) * 1); + } + .mb-2 { + margin-bottom: calc(var(--spacing) * 2); + } + .mb-4 { + margin-bottom: calc(var(--spacing) * 4); + } + .ml-2 { + margin-left: calc(var(--spacing) * 2); + } + .block { + display: block; + } + .flex { + display: flex; + } + .grid { + display: grid; + } + .hidden { + display: none; + } + .inline { + display: inline; + } + .inline-block { + display: inline-block; + } + .size-7 { + width: calc(var(--spacing) * 7); + height: calc(var(--spacing) * 7); + } + .h-2 { + height: calc(var(--spacing) * 2); + } + .h-4 { + height: calc(var(--spacing) * 4); + } + .h-5 { + height: calc(var(--spacing) * 5); + } + .h-7 { + height: calc(var(--spacing) * 7); + } + .h-8 { + height: calc(var(--spacing) * 8); + } + .h-auto { + height: auto; + } + .h-full { + height: 100%; + } + .max-h-48 { + max-height: calc(var(--spacing) * 48); + } + .max-h-96 { + max-height: calc(var(--spacing) * 96); + } + .max-h-full { + max-height: 100%; + } + .min-h-screen { + min-height: 100vh; + } + .w-4 { + width: calc(var(--spacing) * 4); + } + .w-5 { + width: calc(var(--spacing) * 5); + } + .w-7 { + width: calc(var(--spacing) * 7); + } + .w-12 { + width: calc(var(--spacing) * 12); + } + .w-16 { + width: calc(var(--spacing) * 16); + } + .w-20 { + width: calc(var(--spacing) * 20); + } + .w-28 { + width: calc(var(--spacing) * 28); + } + .w-full { + width: 100%; + } + .max-w-2xl { + max-width: var(--container-2xl); + } + .max-w-md { + max-width: var(--container-md); + } + .min-w-\[50\%\] { + min-width: 50%; + } + .flex-1 { + flex: 1; + } + .flex-grow { + flex-grow: 1; + } + .-translate-x-4 { + --tw-translate-x: calc(var(--spacing) * -4); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .-translate-x-8 { + --tw-translate-x: calc(var(--spacing) * -8); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .-translate-y-1 { + --tw-translate-y: calc(var(--spacing) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .-translate-y-1\/2 { + --tw-translate-y: calc(calc(1/2 * 100%) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .transform { + transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); + } + .cursor-not-allowed { + cursor: not-allowed; + } + .cursor-pointer { + cursor: pointer; + } + .list-inside { + list-style-position: inside; + } + .list-disc { + list-style-type: disc; + } + .appearance-none { + appearance: none; + } + .grid-cols-\[2rem_auto_8rem\] { + grid-template-columns: 2rem auto 8rem; + } + .grid-cols-\[auto_6rem_2rem\] { + grid-template-columns: auto 6rem 2rem; + } + .flex-col { + flex-direction: column; + } + .flex-row { + flex-direction: row; + } + .items-center { + align-items: center; + } + .justify-between { + justify-content: space-between; + } + .justify-center { + justify-content: center; + } + .justify-stretch { + justify-content: stretch; + } + .gap-2 { + gap: calc(var(--spacing) * 2); + } + .gap-4 { + gap: calc(var(--spacing) * 4); + } + .space-y-4 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); + } + } + .gap-x-2 { + column-gap: calc(var(--spacing) * 2); + } + .gap-x-6 { + column-gap: calc(var(--spacing) * 6); + } + .overflow-y-auto { + overflow-y: auto; + } + .rounded { + border-radius: 0.25rem; + } + .rounded-full { + border-radius: calc(infinity * 1px); + } + .rounded-lg { + border-radius: var(--radius-lg); + } + .rounded-t { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; + } + .rounded-b { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + } + .border { + border-style: var(--tw-border-style); + border-width: 1px; + } + .border-t { + border-top-style: var(--tw-border-style); + border-top-width: 1px; + } + .border-b { + border-bottom-style: var(--tw-border-style); + border-bottom-width: 1px; + } + .border-l-2 { + border-left-style: var(--tw-border-style); + border-left-width: 2px; + } + .border-gray-200 { + border-color: var(--color-gray-200); + } + .border-gray-300 { + border-color: var(--color-gray-300); + } + .border-red-600 { + border-color: var(--color-red-600); + } + .bg-blue-500 { + background-color: var(--color-blue-500); + } + .bg-blue-600 { + background-color: var(--color-blue-600); + } + .bg-blue-700 { + background-color: var(--color-blue-700); + } + .bg-gray-50 { + background-color: var(--color-gray-50); + } + .bg-gray-100 { + background-color: var(--color-gray-100); + } + .bg-gray-200 { + background-color: var(--color-gray-200); + } + .bg-gray-300 { + background-color: var(--color-gray-300); + } + .bg-gray-400 { + background-color: var(--color-gray-400); + } + .bg-green-400 { + background-color: var(--color-green-400); + } + .bg-green-500 { + background-color: var(--color-green-500); + } + .bg-green-700 { + background-color: var(--color-green-700); + } + .bg-red-500 { + background-color: var(--color-red-500); + } + .bg-red-700 { + background-color: var(--color-red-700); + } + .bg-white { + background-color: var(--color-white); + } + .bg-yellow-500 { + background-color: var(--color-yellow-500); + } + .p-1 { + padding: calc(var(--spacing) * 1); + } + .p-2\.5 { + padding: calc(var(--spacing) * 2.5); + } + .p-4 { + padding: calc(var(--spacing) * 4); + } + .px-2 { + padding-inline: calc(var(--spacing) * 2); + } + .px-4 { + padding-inline: calc(var(--spacing) * 4); + } + .px-5 { + padding-inline: calc(var(--spacing) * 5); + } + .py-1 { + padding-block: calc(var(--spacing) * 1); + } + .py-2 { + padding-block: calc(var(--spacing) * 2); + } + .py-2\.5 { + padding-block: calc(var(--spacing) * 2.5); + } + .py-4 { + padding-block: calc(var(--spacing) * 4); + } + .pt-1 { + padding-top: calc(var(--spacing) * 1); + } + .pt-4 { + padding-top: calc(var(--spacing) * 4); + } + .pr-4 { + padding-right: calc(var(--spacing) * 4); + } + .pb-2 { + padding-bottom: calc(var(--spacing) * 2); + } + .pl-4 { + padding-left: calc(var(--spacing) * 4); + } + .text-center { + text-align: center; + } + .align-middle { + vertical-align: middle; + } + .font-mono { + font-family: var(--font-mono); + } + .text-base { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + } + .text-lg { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + } + .text-sm { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .text-xl { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); + } + .text-xs { + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .font-medium { + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + } + .font-semibold { + --tw-font-weight: var(--font-weight-semibold); + font-weight: var(--font-weight-semibold); + } + .text-blue-700 { + color: var(--color-blue-700); + } + .text-gray-400 { + color: var(--color-gray-400); + } + .text-gray-500 { + color: var(--color-gray-500); + } + .text-gray-600 { + color: var(--color-gray-600); + } + .text-gray-700 { + color: var(--color-gray-700); + } + .text-gray-900 { + color: var(--color-gray-900); + } + .text-green-700 { + color: var(--color-green-700); + } + .text-white { + color: var(--color-white); + } + .overline { + text-decoration-line: overline; + } + .opacity-50 { + opacity: 50%; + } + .shadow { + --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .shadow-sm { + --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .transition-all { + transition-property: all; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .transition-colors { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .duration-150 { + --tw-duration: 150ms; + transition-duration: 150ms; + } + .duration-200 { + --tw-duration: 200ms; + transition-duration: 200ms; + } + .select-none { + -webkit-user-select: none; + user-select: none; + } + .peer-checked\:bg-blue-800 { + &:is(:where(.peer):checked ~ *) { + background-color: var(--color-blue-800); + } + } + .peer-checked\:bg-green-400 { + &:is(:where(.peer):checked ~ *) { + background-color: var(--color-green-400); + } + } + .peer-checked\:text-gray-400 { + &:is(:where(.peer):checked ~ *) { + color: var(--color-gray-400); + } + } + .peer-checked\:text-gray-900 { + &:is(:where(.peer):checked ~ *) { + color: var(--color-gray-900); + } + } + .peer-checked\:text-white { + &:is(:where(.peer):checked ~ *) { + color: var(--color-white); + } + } + .peer-focus\:ring-4 { + &:is(:where(.peer):focus ~ *) { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + } + .peer-focus\:ring-gray-100 { + &:is(:where(.peer):focus ~ *) { + --tw-ring-color: var(--color-gray-100); + } + } + .peer-focus\:outline-none { + &:is(:where(.peer):focus ~ *) { + --tw-outline-style: none; + outline-style: none; + } + } + .after\:absolute { + &::after { + content: var(--tw-content); + position: absolute; + } + } + .after\:start-0\.5 { + &::after { + content: var(--tw-content); + inset-inline-start: calc(var(--spacing) * 0.5); + } + } + .after\:top-0\.5 { + &::after { + content: var(--tw-content); + top: calc(var(--spacing) * 0.5); + } + } + .after\:h-7 { + &::after { + content: var(--tw-content); + height: calc(var(--spacing) * 7); + } + } + .after\:w-7 { + &::after { + content: var(--tw-content); + width: calc(var(--spacing) * 7); + } + } + .after\:rounded-full { + &::after { + content: var(--tw-content); + border-radius: calc(infinity * 1px); + } + } + .after\:border { + &::after { + content: var(--tw-content); + border-style: var(--tw-border-style); + border-width: 1px; + } + } + .after\:border-gray-300 { + &::after { + content: var(--tw-content); + border-color: var(--color-gray-300); + } + } + .after\:bg-white { + &::after { + content: var(--tw-content); + background-color: var(--color-white); + } + } + .after\:transition-all { + &::after { + content: var(--tw-content); + transition-property: all; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + } + .after\:content-\[\'\'\] { + &::after { + --tw-content: ''; + content: var(--tw-content); + } + } + .peer-checked\:after\:translate-x-\[46px\] { + &:is(:where(.peer):checked ~ *) { + &::after { + content: var(--tw-content); + --tw-translate-x: 46px; + translate: var(--tw-translate-x) var(--tw-translate-y); + } + } + } + .peer-checked\:after\:border-white { + &:is(:where(.peer):checked ~ *) { + &::after { + content: var(--tw-content); + border-color: var(--color-white); + } + } + } + .hover\:bg-blue-600 { + &:hover { + @media (hover: hover) { + background-color: var(--color-blue-600); + } + } + } + .hover\:bg-blue-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-blue-700); + } + } + } + .hover\:bg-blue-800 { + &:hover { + @media (hover: hover) { + background-color: var(--color-blue-800); + } + } + } + .hover\:bg-gray-200 { + &:hover { + @media (hover: hover) { + background-color: var(--color-gray-200); + } + } + } + .hover\:bg-gray-300 { + &:hover { + @media (hover: hover) { + background-color: var(--color-gray-300); + } + } + } + .hover\:bg-green-500 { + &:hover { + @media (hover: hover) { + background-color: var(--color-green-500); + } + } + } + .hover\:bg-green-800 { + &:hover { + @media (hover: hover) { + background-color: var(--color-green-800); + } + } + } + .hover\:bg-red-600 { + &:hover { + @media (hover: hover) { + background-color: var(--color-red-600); + } + } + } + .hover\:bg-red-800 { + &:hover { + @media (hover: hover) { + background-color: var(--color-red-800); + } + } + } + .hover\:text-gray-900 { + &:hover { + @media (hover: hover) { + color: var(--color-gray-900); + } + } + } + .focus\:border-blue-500 { + &:focus { + border-color: var(--color-blue-500); + } + } + .focus\:ring-4 { + &:focus { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + } + .focus\:ring-blue-300 { + &:focus { + --tw-ring-color: var(--color-blue-300); + } + } + .focus\:ring-blue-500 { + &:focus { + --tw-ring-color: var(--color-blue-500); + } + } + .focus\:ring-green-300 { + &:focus { + --tw-ring-color: var(--color-green-300); + } + } + .focus\:ring-red-300 { + &:focus { + --tw-ring-color: var(--color-red-300); + } + } + .focus\:outline-none { + &:focus { + --tw-outline-style: none; + outline-style: none; + } + } + .disabled\:bg-gray-300 { + &:disabled { + background-color: var(--color-gray-300); + } + } + .disabled\:text-gray-500 { + &:disabled { + color: var(--color-gray-500); + } + } + .sm\:w-auto { + @media (width >= 40rem) { + width: auto; + } + } + .sm\:px-8 { + @media (width >= 40rem) { + padding-inline: calc(var(--spacing) * 8); + } + } + .md\:w-2\/3 { + @media (width >= 48rem) { + width: calc(2/3 * 100%); + } + } + .md\:flex-row { + @media (width >= 48rem) { + flex-direction: row; + } + } + .md\:p-5 { + @media (width >= 48rem) { + padding: calc(var(--spacing) * 5); + } + } + .md\:px-8 { + @media (width >= 48rem) { + padding-inline: calc(var(--spacing) * 8); + } + } + .lg\:px-8 { + @media (width >= 64rem) { + padding-inline: calc(var(--spacing) * 8); + } + } + .xl\:px-8 { + @media (width >= 80rem) { + padding-inline: calc(var(--spacing) * 8); + } + } + .rtl\:peer-checked\:after\:-translate-x-full { + &:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) { + &:is(:where(.peer):checked ~ *) { + &::after { + content: var(--tw-content); + --tw-translate-x: -100%; + translate: var(--tw-translate-x) var(--tw-translate-y); + } + } + } + } + .dark\:border-gray-600 { + @media (prefers-color-scheme: dark) { + border-color: var(--color-gray-600); + } + } + .dark\:bg-blue-600 { + @media (prefers-color-scheme: dark) { + background-color: var(--color-blue-600); + } + } + .dark\:bg-gray-400 { + @media (prefers-color-scheme: dark) { + background-color: var(--color-gray-400); + } + } + .dark\:bg-gray-700 { + @media (prefers-color-scheme: dark) { + background-color: var(--color-gray-700); + } + } + .dark\:bg-green-600 { + @media (prefers-color-scheme: dark) { + background-color: var(--color-green-600); + } + } + .dark\:bg-red-400 { + @media (prefers-color-scheme: dark) { + background-color: var(--color-red-400); + } + } + .dark\:bg-red-600 { + @media (prefers-color-scheme: dark) { + background-color: var(--color-red-600); + } + } + .dark\:text-gray-400 { + @media (prefers-color-scheme: dark) { + color: var(--color-gray-400); + } + } + .dark\:text-white { + @media (prefers-color-scheme: dark) { + color: var(--color-white); + } + } + .dark\:peer-checked\:bg-blue-800 { + @media (prefers-color-scheme: dark) { + &:is(:where(.peer):checked ~ *) { + background-color: var(--color-blue-800); + } + } + } + .dark\:peer-checked\:bg-green-400 { + @media (prefers-color-scheme: dark) { + &:is(:where(.peer):checked ~ *) { + background-color: var(--color-green-400); + } + } + } + .dark\:peer-focus\:ring-gray-100 { + @media (prefers-color-scheme: dark) { + &:is(:where(.peer):focus ~ *) { + --tw-ring-color: var(--color-gray-100); + } + } + } + .dark\:hover\:bg-blue-700 { + @media (prefers-color-scheme: dark) { + &:hover { + @media (hover: hover) { + background-color: var(--color-blue-700); + } + } + } + } + .dark\:hover\:bg-green-700 { + @media (prefers-color-scheme: dark) { + &:hover { + @media (hover: hover) { + background-color: var(--color-green-700); + } + } + } + } + .dark\:hover\:bg-red-700 { + @media (prefers-color-scheme: dark) { + &:hover { + @media (hover: hover) { + background-color: var(--color-red-700); + } + } + } + } + .dark\:focus\:ring-blue-800 { + @media (prefers-color-scheme: dark) { + &:focus { + --tw-ring-color: var(--color-blue-800); + } + } + } + .dark\:focus\:ring-green-800 { + @media (prefers-color-scheme: dark) { + &:focus { + --tw-ring-color: var(--color-green-800); + } + } + } + .dark\:focus\:ring-red-800 { + @media (prefers-color-scheme: dark) { + &:focus { + --tw-ring-color: var(--color-red-800); + } + } + } +} +@font-face { + font-family: 'Asap'; + src: url('/static/fonts/Asap-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-style: normal; +} +@font-face { + font-family: 'Asap'; + src: url('/static/fonts/Asap-Italic-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-style: italic; +} +@font-face { + font-family: 'Archivo'; + src: url('/static/fonts/Archivo-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-style: normal; +} +@font-face { + font-family: 'Archivo'; + src: url('/static/fonts/Archivo-Italic-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-style: italic; +} +html { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +body { + font-family: 'Archivo', 'Asap', sans-serif; +} +.daemon-status-title { + font-size: 36px; + font-weight: 500; + letter-spacing: 0.3px; +} +.daemon-status-collapse { + font-family: 'Asap', sans-serif; + font-weight: 400; + color: rgba(0, 0, 0, 0.7); +} +.app-section { + border-radius: 8px; + border-width: 1px; + padding: 16px; + gap: 16px; + background: #FFFFFF; +} +.installed-app-title { + font-weight: 600; +} +.app-section-title { + font-weight: 500; + font-size: 24px; + letter-spacing: 0px; +} +.app-list-item { + padding: 4px; +} +.hf-app-icon { + width: 42px; + height: 42px; + border-radius: 10px; + text-align: center; + font-size: 31px; + background-color: rgba(0, 0, 0, 0.1); +} +.hf-app-title { + font-weight: 500; + font-size: 18px; +} +.hf-app-description { + font-family: 'Asap', sans-serif; + font-weight: 400; + font-size: 16px; + line-height: 75%; + color: rgba(0, 0, 0, 0.4); +} +.hf-app-install-button { + font-weight: 500; + font-size: 20px; + font-style: Bold; + text-align: center; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; +} +.wifi-status { + font-family: 'Asap', sans-serif; + font-weight: 500; + color: rgba(0, 0, 0, 0.9); +} +.wifi-status-info { + font-family: 'Asap', sans-serif; + font-weight: 400; + color: rgba(0, 0, 0, 0.7); +} +.notification-modal { + position: fixed; + bottom: 24px; + right: 24px; + z-index: 9999; + min-width: 300px; + max-width: 400px; + background: #fff; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); + border-radius: 8px; + display: none; + animation: fadeInUp 0.3s; +} +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(40px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +.notification-content { + padding: 20px 28px; + border-radius: 8px; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15); + display: flex; + align-items: center; + justify-content: space-between; +} +.notification-content.info { + background: #fff; + border: 1px solid #e0e0e0; +} +.notification-content.error { + background: #ffeaea; + border: 1px solid #ff4d4f; + color: #b71c1c; +} +.close-btn { + background: none; + border: none; + font-size: 1.5em; + cursor: pointer; + color: #888; +} +@property --tw-translate-x { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-translate-y { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-translate-z { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-rotate-x { + syntax: "*"; + inherits: false; +} +@property --tw-rotate-y { + syntax: "*"; + inherits: false; +} +@property --tw-rotate-z { + syntax: "*"; + inherits: false; +} +@property --tw-skew-x { + syntax: "*"; + inherits: false; +} +@property --tw-skew-y { + syntax: "*"; + inherits: false; +} +@property --tw-space-y-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-border-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-font-weight { + syntax: "*"; + inherits: false; +} +@property --tw-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-inset-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-inset-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-inset-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-ring-color { + syntax: "*"; + inherits: false; +} +@property --tw-ring-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-inset-ring-color { + syntax: "*"; + inherits: false; +} +@property --tw-inset-ring-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-ring-inset { + syntax: "*"; + inherits: false; +} +@property --tw-ring-offset-width { + syntax: ""; + inherits: false; + initial-value: 0px; +} +@property --tw-ring-offset-color { + syntax: "*"; + inherits: false; + initial-value: #fff; +} +@property --tw-ring-offset-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-duration { + syntax: "*"; + inherits: false; +} +@property --tw-content { + syntax: "*"; + initial-value: ""; + inherits: false; +} +@layer properties { + @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { + *, ::before, ::after, ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-translate-z: 0; + --tw-rotate-x: initial; + --tw-rotate-y: initial; + --tw-rotate-z: initial; + --tw-skew-x: initial; + --tw-skew-y: initial; + --tw-space-y-reverse: 0; + --tw-border-style: solid; + --tw-font-weight: initial; + --tw-shadow: 0 0 #0000; + --tw-shadow-color: initial; + --tw-shadow-alpha: 100%; + --tw-inset-shadow: 0 0 #0000; + --tw-inset-shadow-color: initial; + --tw-inset-shadow-alpha: 100%; + --tw-ring-color: initial; + --tw-ring-shadow: 0 0 #0000; + --tw-inset-ring-color: initial; + --tw-inset-ring-shadow: 0 0 #0000; + --tw-ring-inset: initial; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-duration: initial; + --tw-content: ""; + } + } +} diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/3rdparty/gstwebrtc-api-2.0.0.min.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/3rdparty/gstwebrtc-api-2.0.0.min.js new file mode 100644 index 0000000000000000000000000000000000000000..a8e1dfe53db7cc7d533e524db69fe0ba7a3cccec --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/3rdparty/gstwebrtc-api-2.0.0.min.js @@ -0,0 +1,5 @@ +/*! gstwebrtc-api (https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/tree/main/net/webrtc/gstwebrtc-api), MPL-2.0 License, Copyright (C) 2022 Igalia S.L. , Author: Loïc Le Page */ +/*! Contains embedded adapter from webrtc-adapter (https://github.com/webrtcHacks/adapter), BSD 3-Clause License, Copyright (c) 2014, The WebRTC project authors. All rights reserved. Copyright (c) 2018, The adapter.js project authors. All rights reserved. */ + +(()=>{"use strict";var e={539:e=>{const t={generateIdentifier:function(){return Math.random().toString(36).substring(2,12)}};t.localCName=t.generateIdentifier(),t.splitLines=function(e){return e.trim().split("\n").map((e=>e.trim()))},t.splitSections=function(e){return e.split("\nm=").map(((e,t)=>(t>0?"m="+e:e).trim()+"\r\n"))},t.getDescription=function(e){const n=t.splitSections(e);return n&&n[0]},t.getMediaSections=function(e){const n=t.splitSections(e);return n.shift(),n},t.matchPrefix=function(e,n){return t.splitLines(e).filter((e=>0===e.indexOf(n)))},t.parseCandidate=function(e){let t;t=0===e.indexOf("a=candidate:")?e.substring(12).split(" "):e.substring(10).split(" ");const n={foundation:t[0],component:{1:"rtp",2:"rtcp"}[t[1]]||t[1],protocol:t[2].toLowerCase(),priority:parseInt(t[3],10),ip:t[4],address:t[4],port:parseInt(t[5],10),type:t[7]};for(let e=8;e0?t[0].split("/")[1]:"sendrecv",uri:t[1],attributes:t.slice(2).join(" ")}},t.writeExtmap=function(e){return"a=extmap:"+(e.id||e.preferredId)+(e.direction&&"sendrecv"!==e.direction?"/"+e.direction:"")+" "+e.uri+(e.attributes?" "+e.attributes:"")+"\r\n"},t.parseFmtp=function(e){const t={};let n;const r=e.substring(e.indexOf(" ")+1).split(";");for(let e=0;e{void 0!==e.parameters[t]?r.push(t+"="+e.parameters[t]):r.push(t)})),t+="a=fmtp:"+n+" "+r.join(";")+"\r\n"}return t},t.parseRtcpFb=function(e){const t=e.substring(e.indexOf(" ")+1).split(" ");return{type:t.shift(),parameter:t.join(" ")}},t.writeRtcpFb=function(e){let t="",n=e.payloadType;return void 0!==e.preferredPayloadType&&(n=e.preferredPayloadType),e.rtcpFeedback&&e.rtcpFeedback.length&&e.rtcpFeedback.forEach((e=>{t+="a=rtcp-fb:"+n+" "+e.type+(e.parameter&&e.parameter.length?" "+e.parameter:"")+"\r\n"})),t},t.parseSsrcMedia=function(e){const t=e.indexOf(" "),n={ssrc:parseInt(e.substring(7,t),10)},r=e.indexOf(":",t);return r>-1?(n.attribute=e.substring(t+1,r),n.value=e.substring(r+1)):n.attribute=e.substring(t+1),n},t.parseSsrcGroup=function(e){const t=e.substring(13).split(" ");return{semantics:t.shift(),ssrcs:t.map((e=>parseInt(e,10)))}},t.getMid=function(e){const n=t.matchPrefix(e,"a=mid:")[0];if(n)return n.substring(6)},t.parseFingerprint=function(e){const t=e.substring(14).split(" ");return{algorithm:t[0].toLowerCase(),value:t[1].toUpperCase()}},t.getDtlsParameters=function(e,n){return{role:"auto",fingerprints:t.matchPrefix(e+n,"a=fingerprint:").map(t.parseFingerprint)}},t.writeDtlsParameters=function(e,t){let n="a=setup:"+t+"\r\n";return e.fingerprints.forEach((e=>{n+="a=fingerprint:"+e.algorithm+" "+e.value+"\r\n"})),n},t.parseCryptoLine=function(e){const t=e.substring(9).split(" ");return{tag:parseInt(t[0],10),cryptoSuite:t[1],keyParams:t[2],sessionParams:t.slice(3)}},t.writeCryptoLine=function(e){return"a=crypto:"+e.tag+" "+e.cryptoSuite+" "+("object"==typeof e.keyParams?t.writeCryptoKeyParams(e.keyParams):e.keyParams)+(e.sessionParams?" "+e.sessionParams.join(" "):"")+"\r\n"},t.parseCryptoKeyParams=function(e){if(0!==e.indexOf("inline:"))return null;const t=e.substring(7).split("|");return{keyMethod:"inline",keySalt:t[0],lifeTime:t[1],mkiValue:t[2]?t[2].split(":")[0]:void 0,mkiLength:t[2]?t[2].split(":")[1]:void 0}},t.writeCryptoKeyParams=function(e){return e.keyMethod+":"+e.keySalt+(e.lifeTime?"|"+e.lifeTime:"")+(e.mkiValue&&e.mkiLength?"|"+e.mkiValue+":"+e.mkiLength:"")},t.getCryptoParameters=function(e,n){return t.matchPrefix(e+n,"a=crypto:").map(t.parseCryptoLine)},t.getIceParameters=function(e,n){const r=t.matchPrefix(e+n,"a=ice-ufrag:")[0],i=t.matchPrefix(e+n,"a=ice-pwd:")[0];return r&&i?{usernameFragment:r.substring(12),password:i.substring(10)}:null},t.writeIceParameters=function(e){let t="a=ice-ufrag:"+e.usernameFragment+"\r\na=ice-pwd:"+e.password+"\r\n";return e.iceLite&&(t+="a=ice-lite\r\n"),t},t.parseRtpParameters=function(e){const n={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},r=t.splitLines(e)[0].split(" ");n.profile=r[2];for(let i=3;i{n.headerExtensions.push(t.parseExtmap(e))}));const i=t.matchPrefix(e,"a=rtcp-fb:* ").map(t.parseRtcpFb);return n.codecs.forEach((e=>{i.forEach((t=>{e.rtcpFeedback.find((e=>e.type===t.type&&e.parameter===t.parameter))||e.rtcpFeedback.push(t)}))})),n},t.writeRtpDescription=function(e,n){let r="";r+="m="+e+" ",r+=n.codecs.length>0?"9":"0",r+=" "+(n.profile||"UDP/TLS/RTP/SAVPF")+" ",r+=n.codecs.map((e=>void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType)).join(" ")+"\r\n",r+="c=IN IP4 0.0.0.0\r\n",r+="a=rtcp:9 IN IP4 0.0.0.0\r\n",n.codecs.forEach((e=>{r+=t.writeRtpMap(e),r+=t.writeFmtp(e),r+=t.writeRtcpFb(e)}));let i=0;return n.codecs.forEach((e=>{e.maxptime>i&&(i=e.maxptime)})),i>0&&(r+="a=maxptime:"+i+"\r\n"),n.headerExtensions&&n.headerExtensions.forEach((e=>{r+=t.writeExtmap(e)})),r},t.parseRtpEncodingParameters=function(e){const n=[],r=t.parseRtpParameters(e),i=-1!==r.fecMechanisms.indexOf("RED"),o=-1!==r.fecMechanisms.indexOf("ULPFEC"),s=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute)),a=s.length>0&&s[0].ssrc;let c;const d=t.matchPrefix(e,"a=ssrc-group:FID").map((e=>e.substring(17).split(" ").map((e=>parseInt(e,10)))));d.length>0&&d[0].length>1&&d[0][0]===a&&(c=d[0][1]),r.codecs.forEach((e=>{if("RTX"===e.name.toUpperCase()&&e.parameters.apt){let t={ssrc:a,codecPayloadType:parseInt(e.parameters.apt,10)};a&&c&&(t.rtx={ssrc:c}),n.push(t),i&&(t=JSON.parse(JSON.stringify(t)),t.fec={ssrc:a,mechanism:o?"red+ulpfec":"red"},n.push(t))}})),0===n.length&&a&&n.push({ssrc:a});let l=t.matchPrefix(e,"b=");return l.length&&(l=0===l[0].indexOf("b=TIAS:")?parseInt(l[0].substring(7),10):0===l[0].indexOf("b=AS:")?1e3*parseInt(l[0].substring(5),10)*.95-16e3:void 0,n.forEach((e=>{e.maxBitrate=l}))),n},t.parseRtcpParameters=function(e){const n={},r=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute))[0];r&&(n.cname=r.value,n.ssrc=r.ssrc);const i=t.matchPrefix(e,"a=rtcp-rsize");n.reducedSize=i.length>0,n.compound=0===i.length;const o=t.matchPrefix(e,"a=rtcp-mux");return n.mux=o.length>0,n},t.writeRtcpParameters=function(e){let t="";return e.reducedSize&&(t+="a=rtcp-rsize\r\n"),e.mux&&(t+="a=rtcp-mux\r\n"),void 0!==e.ssrc&&e.cname&&(t+="a=ssrc:"+e.ssrc+" cname:"+e.cname+"\r\n"),t},t.parseMsid=function(e){let n;const r=t.matchPrefix(e,"a=msid:");if(1===r.length)return n=r[0].substring(7).split(" "),{stream:n[0],track:n[1]};const i=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"msid"===e.attribute));return i.length>0?(n=i[0].value.split(" "),{stream:n[0],track:n[1]}):void 0},t.parseSctpDescription=function(e){const n=t.parseMLine(e),r=t.matchPrefix(e,"a=max-message-size:");let i;r.length>0&&(i=parseInt(r[0].substring(19),10)),isNaN(i)&&(i=65536);const o=t.matchPrefix(e,"a=sctp-port:");if(o.length>0)return{port:parseInt(o[0].substring(12),10),protocol:n.fmt,maxMessageSize:i};const s=t.matchPrefix(e,"a=sctpmap:");if(s.length>0){const e=s[0].substring(10).split(" ");return{port:parseInt(e[0],10),protocol:e[1],maxMessageSize:i}}},t.writeSctpDescription=function(e,t){let n=[];return n="DTLS/SCTP"!==e.protocol?["m="+e.kind+" 9 "+e.protocol+" "+t.protocol+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctp-port:"+t.port+"\r\n"]:["m="+e.kind+" 9 "+e.protocol+" "+t.port+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctpmap:"+t.port+" "+t.protocol+" 65535\r\n"],void 0!==t.maxMessageSize&&n.push("a=max-message-size:"+t.maxMessageSize+"\r\n"),n.join("")},t.generateSessionId=function(){return Math.random().toString().substr(2,22)},t.writeSessionBoilerplate=function(e,n,r){let i;const o=void 0!==n?n:2;i=e||t.generateSessionId();return"v=0\r\no="+(r||"thisisadapterortc")+" "+i+" "+o+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},t.getDirection=function(e,n){const r=t.splitLines(e);for(let e=0;e{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e={};n.r(e),n.d(e,{fixNegotiationNeeded:()=>w,shimAddTrackRemoveTrack:()=>P,shimAddTrackRemoveTrackWithNative:()=>E,shimGetDisplayMedia:()=>y,shimGetSendersWithDtmf:()=>S,shimGetStats:()=>k,shimGetUserMedia:()=>C,shimMediaStream:()=>v,shimOnTrack:()=>b,shimPeerConnection:()=>R,shimSenderReceiverGetStats:()=>T});var t={};n.r(t),n.d(t,{shimAddTransceiver:()=>G,shimCreateAnswer:()=>U,shimCreateOffer:()=>N,shimGetDisplayMedia:()=>x,shimGetParameters:()=>j,shimGetUserMedia:()=>A,shimOnTrack:()=>I,shimPeerConnection:()=>O,shimRTCDataChannel:()=>H,shimReceiverGetStats:()=>M,shimRemoveStream:()=>L,shimSenderGetStats:()=>D});var r={};n.r(r),n.d(r,{shimAudioContext:()=>B,shimCallbacksAPI:()=>J,shimConstraints:()=>q,shimCreateOfferLegacy:()=>V,shimGetUserMedia:()=>K,shimLocalStreamsAPI:()=>F,shimRTCIceServerUrls:()=>W,shimRemoteStreamsAPI:()=>z,shimTrackEventTransceiver:()=>Y});var i={};n.r(i),n.d(i,{removeExtmapAllowMixed:()=>re,shimAddIceCandidateNullOrEmpty:()=>ie,shimConnectionState:()=>ne,shimMaxMessageSize:()=>ee,shimParameterlessSetLocalDescription:()=>oe,shimRTCIceCandidate:()=>$,shimRTCIceCandidateRelayProtocol:()=>Q,shimSendThrowTypeError:()=>te});let o=!0,s=!0;function a(e,t,n){const r=e.match(t);return r&&r.length>=n&&parseInt(r[n],10)}function c(e,t,n){if(!e.RTCPeerConnection)return;const r=e.RTCPeerConnection.prototype,i=r.addEventListener;r.addEventListener=function(e,r){if(e!==t)return i.apply(this,arguments);const o=e=>{const t=n(e);t&&(r.handleEvent?r.handleEvent(t):r(t))};return this._eventMap=this._eventMap||{},this._eventMap[t]||(this._eventMap[t]=new Map),this._eventMap[t].set(r,o),i.apply(this,[e,o])};const o=r.removeEventListener;r.removeEventListener=function(e,n){if(e!==t||!this._eventMap||!this._eventMap[t])return o.apply(this,arguments);if(!this._eventMap[t].has(n))return o.apply(this,arguments);const r=this._eventMap[t].get(n);return this._eventMap[t].delete(n),0===this._eventMap[t].size&&delete this._eventMap[t],0===Object.keys(this._eventMap).length&&delete this._eventMap,o.apply(this,[e,r])},Object.defineProperty(r,"on"+t,{get(){return this["_on"+t]},set(e){this["_on"+t]&&(this.removeEventListener(t,this["_on"+t]),delete this["_on"+t]),e&&this.addEventListener(t,this["_on"+t]=e)},enumerable:!0,configurable:!0})}function d(e){return"boolean"!=typeof e?new Error("Argument type: "+typeof e+". Please use a boolean."):(o=e,e?"adapter.js logging disabled":"adapter.js logging enabled")}function l(e){return"boolean"!=typeof e?new Error("Argument type: "+typeof e+". Please use a boolean."):(s=!e,"adapter.js deprecation warnings "+(e?"disabled":"enabled"))}function h(){if("object"==typeof window){if(o)return;"undefined"!=typeof console&&"function"==typeof console.log&&console.log.apply(console,arguments)}}function p(e,t){s&&console.warn(e+" is deprecated, please use "+t+" instead.")}function u(e){return"[object Object]"===Object.prototype.toString.call(e)}function m(e){return u(e)?Object.keys(e).reduce((function(t,n){const r=u(e[n]),i=r?m(e[n]):e[n],o=r&&!Object.keys(i).length;return void 0===i||o?t:Object.assign(t,{[n]:i})}),{}):e}function _(e,t,n){t&&!n.has(t.id)&&(n.set(t.id,t),Object.keys(t).forEach((r=>{r.endsWith("Id")?_(e,e.get(t[r]),n):r.endsWith("Ids")&&t[r].forEach((t=>{_(e,e.get(t),n)}))})))}function f(e,t,n){const r=n?"outbound-rtp":"inbound-rtp",i=new Map;if(null===t)return i;const o=[];return e.forEach((e=>{"track"===e.type&&e.trackIdentifier===t.id&&o.push(e)})),o.forEach((t=>{e.forEach((n=>{n.type===r&&n.trackId===t.id&&_(e,n,i)}))})),i}const g=h;function C(e,t){const n=e&&e.navigator;if(!n.mediaDevices)return;const r=function(e){if("object"!=typeof e||e.mandatory||e.optional)return e;const t={};return Object.keys(e).forEach((n=>{if("require"===n||"advanced"===n||"mediaSource"===n)return;const r="object"==typeof e[n]?e[n]:{ideal:e[n]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);const i=function(e,t){return e?e+t.charAt(0).toUpperCase()+t.slice(1):"deviceId"===t?"sourceId":t};if(void 0!==r.ideal){t.optional=t.optional||[];let e={};"number"==typeof r.ideal?(e[i("min",n)]=r.ideal,t.optional.push(e),e={},e[i("max",n)]=r.ideal,t.optional.push(e)):(e[i("",n)]=r.ideal,t.optional.push(e))}void 0!==r.exact&&"number"!=typeof r.exact?(t.mandatory=t.mandatory||{},t.mandatory[i("",n)]=r.exact):["min","max"].forEach((e=>{void 0!==r[e]&&(t.mandatory=t.mandatory||{},t.mandatory[i(e,n)]=r[e])}))})),e.advanced&&(t.optional=(t.optional||[]).concat(e.advanced)),t},i=function(e,i){if(t.version>=61)return i(e);if((e=JSON.parse(JSON.stringify(e)))&&"object"==typeof e.audio){const t=function(e,t,n){t in e&&!(n in e)&&(e[n]=e[t],delete e[t])};t((e=JSON.parse(JSON.stringify(e))).audio,"autoGainControl","googAutoGainControl"),t(e.audio,"noiseSuppression","googNoiseSuppression"),e.audio=r(e.audio)}if(e&&"object"==typeof e.video){let o=e.video.facingMode;o=o&&("object"==typeof o?o:{ideal:o});const s=t.version<66;if(o&&("user"===o.exact||"environment"===o.exact||"user"===o.ideal||"environment"===o.ideal)&&(!n.mediaDevices.getSupportedConstraints||!n.mediaDevices.getSupportedConstraints().facingMode||s)){let t;if(delete e.video.facingMode,"environment"===o.exact||"environment"===o.ideal?t=["back","rear"]:"user"!==o.exact&&"user"!==o.ideal||(t=["front"]),t)return n.mediaDevices.enumerateDevices().then((n=>{let s=(n=n.filter((e=>"videoinput"===e.kind))).find((e=>t.some((t=>e.label.toLowerCase().includes(t)))));return!s&&n.length&&t.includes("back")&&(s=n[n.length-1]),s&&(e.video.deviceId=o.exact?{exact:s.deviceId}:{ideal:s.deviceId}),e.video=r(e.video),g("chrome: "+JSON.stringify(e)),i(e)}))}e.video=r(e.video)}return g("chrome: "+JSON.stringify(e)),i(e)},o=function(e){return t.version>=64?e:{name:{PermissionDeniedError:"NotAllowedError",PermissionDismissedError:"NotAllowedError",InvalidStateError:"NotAllowedError",DevicesNotFoundError:"NotFoundError",ConstraintNotSatisfiedError:"OverconstrainedError",TrackStartError:"NotReadableError",MediaDeviceFailedDueToShutdown:"NotAllowedError",MediaDeviceKillSwitchOn:"NotAllowedError",TabCaptureError:"AbortError",ScreenCaptureError:"AbortError",DeviceCaptureError:"AbortError"}[e.name]||e.name,message:e.message,constraint:e.constraint||e.constraintName,toString(){return this.name+(this.message&&": ")+this.message}}};if(n.getUserMedia=function(e,t,r){i(e,(e=>{n.webkitGetUserMedia(e,t,(e=>{r&&r(o(e))}))}))}.bind(n),n.mediaDevices.getUserMedia){const e=n.mediaDevices.getUserMedia.bind(n.mediaDevices);n.mediaDevices.getUserMedia=function(t){return i(t,(t=>e(t).then((e=>{if(t.audio&&!e.getAudioTracks().length||t.video&&!e.getVideoTracks().length)throw e.getTracks().forEach((e=>{e.stop()})),new DOMException("","NotFoundError");return e}),(e=>Promise.reject(o(e))))))}}}function y(e,t){e.navigator.mediaDevices&&"getDisplayMedia"in e.navigator.mediaDevices||e.navigator.mediaDevices&&("function"==typeof t?e.navigator.mediaDevices.getDisplayMedia=function(n){return t(n).then((t=>{const r=n.video&&n.video.width,i=n.video&&n.video.height,o=n.video&&n.video.frameRate;return n.video={mandatory:{chromeMediaSource:"desktop",chromeMediaSourceId:t,maxFrameRate:o||3}},r&&(n.video.mandatory.maxWidth=r),i&&(n.video.mandatory.maxHeight=i),e.navigator.mediaDevices.getUserMedia(n)}))}:console.error("shimGetDisplayMedia: getSourceId argument is not a function"))}function v(e){e.MediaStream=e.MediaStream||e.webkitMediaStream}function b(e){if("object"==typeof e&&e.RTCPeerConnection&&!("ontrack"in e.RTCPeerConnection.prototype)){Object.defineProperty(e.RTCPeerConnection.prototype,"ontrack",{get(){return this._ontrack},set(e){this._ontrack&&this.removeEventListener("track",this._ontrack),this.addEventListener("track",this._ontrack=e)},enumerable:!0,configurable:!0});const t=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(){return this._ontrackpoly||(this._ontrackpoly=t=>{t.stream.addEventListener("addtrack",(n=>{let r;r=e.RTCPeerConnection.prototype.getReceivers?this.getReceivers().find((e=>e.track&&e.track.id===n.track.id)):{track:n.track};const i=new Event("track");i.track=n.track,i.receiver=r,i.transceiver={receiver:r},i.streams=[t.stream],this.dispatchEvent(i)})),t.stream.getTracks().forEach((n=>{let r;r=e.RTCPeerConnection.prototype.getReceivers?this.getReceivers().find((e=>e.track&&e.track.id===n.id)):{track:n};const i=new Event("track");i.track=n,i.receiver=r,i.transceiver={receiver:r},i.streams=[t.stream],this.dispatchEvent(i)}))},this.addEventListener("addstream",this._ontrackpoly)),t.apply(this,arguments)}}else c(e,"track",(e=>(e.transceiver||Object.defineProperty(e,"transceiver",{value:{receiver:e.receiver}}),e)))}function S(e){if("object"==typeof e&&e.RTCPeerConnection&&!("getSenders"in e.RTCPeerConnection.prototype)&&"createDTMFSender"in e.RTCPeerConnection.prototype){const t=function(e,t){return{track:t,get dtmf(){return void 0===this._dtmf&&("audio"===t.kind?this._dtmf=e.createDTMFSender(t):this._dtmf=null),this._dtmf},_pc:e}};if(!e.RTCPeerConnection.prototype.getSenders){e.RTCPeerConnection.prototype.getSenders=function(){return this._senders=this._senders||[],this._senders.slice()};const n=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addTrack=function(e,r){let i=n.apply(this,arguments);return i||(i=t(this,e),this._senders.push(i)),i};const r=e.RTCPeerConnection.prototype.removeTrack;e.RTCPeerConnection.prototype.removeTrack=function(e){r.apply(this,arguments);const t=this._senders.indexOf(e);-1!==t&&this._senders.splice(t,1)}}const n=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(e){this._senders=this._senders||[],n.apply(this,[e]),e.getTracks().forEach((e=>{this._senders.push(t(this,e))}))};const r=e.RTCPeerConnection.prototype.removeStream;e.RTCPeerConnection.prototype.removeStream=function(e){this._senders=this._senders||[],r.apply(this,[e]),e.getTracks().forEach((e=>{const t=this._senders.find((t=>t.track===e));t&&this._senders.splice(this._senders.indexOf(t),1)}))}}else if("object"==typeof e&&e.RTCPeerConnection&&"getSenders"in e.RTCPeerConnection.prototype&&"createDTMFSender"in e.RTCPeerConnection.prototype&&e.RTCRtpSender&&!("dtmf"in e.RTCRtpSender.prototype)){const t=e.RTCPeerConnection.prototype.getSenders;e.RTCPeerConnection.prototype.getSenders=function(){const e=t.apply(this,[]);return e.forEach((e=>e._pc=this)),e},Object.defineProperty(e.RTCRtpSender.prototype,"dtmf",{get(){return void 0===this._dtmf&&("audio"===this.track.kind?this._dtmf=this._pc.createDTMFSender(this.track):this._dtmf=null),this._dtmf}})}}function k(e){if(!e.RTCPeerConnection)return;const t=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){const[e,n,r]=arguments;if(arguments.length>0&&"function"==typeof e)return t.apply(this,arguments);if(0===t.length&&(0===arguments.length||"function"!=typeof e))return t.apply(this,[]);const i=function(e){const t={};return e.result().forEach((e=>{const n={id:e.id,timestamp:e.timestamp,type:{localcandidate:"local-candidate",remotecandidate:"remote-candidate"}[e.type]||e.type};e.names().forEach((t=>{n[t]=e.stat(t)})),t[n.id]=n})),t},o=function(e){return new Map(Object.keys(e).map((t=>[t,e[t]])))};if(arguments.length>=2){const r=function(e){n(o(i(e)))};return t.apply(this,[r,e])}return new Promise(((e,n)=>{t.apply(this,[function(t){e(o(i(t)))},n])})).then(n,r)}}function T(e){if(!("object"==typeof e&&e.RTCPeerConnection&&e.RTCRtpSender&&e.RTCRtpReceiver))return;if(!("getStats"in e.RTCRtpSender.prototype)){const t=e.RTCPeerConnection.prototype.getSenders;t&&(e.RTCPeerConnection.prototype.getSenders=function(){const e=t.apply(this,[]);return e.forEach((e=>e._pc=this)),e});const n=e.RTCPeerConnection.prototype.addTrack;n&&(e.RTCPeerConnection.prototype.addTrack=function(){const e=n.apply(this,arguments);return e._pc=this,e}),e.RTCRtpSender.prototype.getStats=function(){const e=this;return this._pc.getStats().then((t=>f(t,e.track,!0)))}}if(!("getStats"in e.RTCRtpReceiver.prototype)){const t=e.RTCPeerConnection.prototype.getReceivers;t&&(e.RTCPeerConnection.prototype.getReceivers=function(){const e=t.apply(this,[]);return e.forEach((e=>e._pc=this)),e}),c(e,"track",(e=>(e.receiver._pc=e.srcElement,e))),e.RTCRtpReceiver.prototype.getStats=function(){const e=this;return this._pc.getStats().then((t=>f(t,e.track,!1)))}}if(!("getStats"in e.RTCRtpSender.prototype)||!("getStats"in e.RTCRtpReceiver.prototype))return;const t=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){if(arguments.length>0&&arguments[0]instanceof e.MediaStreamTrack){const e=arguments[0];let t,n,r;return this.getSenders().forEach((n=>{n.track===e&&(t?r=!0:t=n)})),this.getReceivers().forEach((t=>(t.track===e&&(n?r=!0:n=t),t.track===e))),r||t&&n?Promise.reject(new DOMException("There are more than one sender or receiver for the track.","InvalidAccessError")):t?t.getStats():n?n.getStats():Promise.reject(new DOMException("There is no sender or receiver for the track.","InvalidAccessError"))}return t.apply(this,arguments)}}function E(e){e.RTCPeerConnection.prototype.getLocalStreams=function(){return this._shimmedLocalStreams=this._shimmedLocalStreams||{},Object.keys(this._shimmedLocalStreams).map((e=>this._shimmedLocalStreams[e][0]))};const t=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addTrack=function(e,n){if(!n)return t.apply(this,arguments);this._shimmedLocalStreams=this._shimmedLocalStreams||{};const r=t.apply(this,arguments);return this._shimmedLocalStreams[n.id]?-1===this._shimmedLocalStreams[n.id].indexOf(r)&&this._shimmedLocalStreams[n.id].push(r):this._shimmedLocalStreams[n.id]=[n,r],r};const n=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(e){this._shimmedLocalStreams=this._shimmedLocalStreams||{},e.getTracks().forEach((e=>{if(this.getSenders().find((t=>t.track===e)))throw new DOMException("Track already exists.","InvalidAccessError")}));const t=this.getSenders();n.apply(this,arguments);const r=this.getSenders().filter((e=>-1===t.indexOf(e)));this._shimmedLocalStreams[e.id]=[e].concat(r)};const r=e.RTCPeerConnection.prototype.removeStream;e.RTCPeerConnection.prototype.removeStream=function(e){return this._shimmedLocalStreams=this._shimmedLocalStreams||{},delete this._shimmedLocalStreams[e.id],r.apply(this,arguments)};const i=e.RTCPeerConnection.prototype.removeTrack;e.RTCPeerConnection.prototype.removeTrack=function(e){return this._shimmedLocalStreams=this._shimmedLocalStreams||{},e&&Object.keys(this._shimmedLocalStreams).forEach((t=>{const n=this._shimmedLocalStreams[t].indexOf(e);-1!==n&&this._shimmedLocalStreams[t].splice(n,1),1===this._shimmedLocalStreams[t].length&&delete this._shimmedLocalStreams[t]})),i.apply(this,arguments)}}function P(e,t){if(!e.RTCPeerConnection)return;if(e.RTCPeerConnection.prototype.addTrack&&t.version>=65)return E(e);const n=e.RTCPeerConnection.prototype.getLocalStreams;e.RTCPeerConnection.prototype.getLocalStreams=function(){const e=n.apply(this);return this._reverseStreams=this._reverseStreams||{},e.map((e=>this._reverseStreams[e.id]))};const r=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(t){if(this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{},t.getTracks().forEach((e=>{if(this.getSenders().find((t=>t.track===e)))throw new DOMException("Track already exists.","InvalidAccessError")})),!this._reverseStreams[t.id]){const n=new e.MediaStream(t.getTracks());this._streams[t.id]=n,this._reverseStreams[n.id]=t,t=n}r.apply(this,[t])};const i=e.RTCPeerConnection.prototype.removeStream;function o(e,t){let n=t.sdp;return Object.keys(e._reverseStreams||[]).forEach((t=>{const r=e._reverseStreams[t],i=e._streams[r.id];n=n.replace(new RegExp(i.id,"g"),r.id)})),new RTCSessionDescription({type:t.type,sdp:n})}e.RTCPeerConnection.prototype.removeStream=function(e){this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{},i.apply(this,[this._streams[e.id]||e]),delete this._reverseStreams[this._streams[e.id]?this._streams[e.id].id:e.id],delete this._streams[e.id]},e.RTCPeerConnection.prototype.addTrack=function(t,n){if("closed"===this.signalingState)throw new DOMException("The RTCPeerConnection's signalingState is 'closed'.","InvalidStateError");const r=[].slice.call(arguments,1);if(1!==r.length||!r[0].getTracks().find((e=>e===t)))throw new DOMException("The adapter.js addTrack polyfill only supports a single stream which is associated with the specified track.","NotSupportedError");if(this.getSenders().find((e=>e.track===t)))throw new DOMException("Track already exists.","InvalidAccessError");this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{};const i=this._streams[n.id];if(i)i.addTrack(t),Promise.resolve().then((()=>{this.dispatchEvent(new Event("negotiationneeded"))}));else{const r=new e.MediaStream([t]);this._streams[n.id]=r,this._reverseStreams[r.id]=n,this.addStream(r)}return this.getSenders().find((e=>e.track===t))},["createOffer","createAnswer"].forEach((function(t){const n=e.RTCPeerConnection.prototype[t],r={[t](){const e=arguments;return arguments.length&&"function"==typeof arguments[0]?n.apply(this,[t=>{const n=o(this,t);e[0].apply(null,[n])},t=>{e[1]&&e[1].apply(null,t)},arguments[2]]):n.apply(this,arguments).then((e=>o(this,e)))}};e.RTCPeerConnection.prototype[t]=r[t]}));const s=e.RTCPeerConnection.prototype.setLocalDescription;e.RTCPeerConnection.prototype.setLocalDescription=function(){return arguments.length&&arguments[0].type?(arguments[0]=function(e,t){let n=t.sdp;return Object.keys(e._reverseStreams||[]).forEach((t=>{const r=e._reverseStreams[t],i=e._streams[r.id];n=n.replace(new RegExp(r.id,"g"),i.id)})),new RTCSessionDescription({type:t.type,sdp:n})}(this,arguments[0]),s.apply(this,arguments)):s.apply(this,arguments)};const a=Object.getOwnPropertyDescriptor(e.RTCPeerConnection.prototype,"localDescription");Object.defineProperty(e.RTCPeerConnection.prototype,"localDescription",{get(){const e=a.get.apply(this);return""===e.type?e:o(this,e)}}),e.RTCPeerConnection.prototype.removeTrack=function(e){if("closed"===this.signalingState)throw new DOMException("The RTCPeerConnection's signalingState is 'closed'.","InvalidStateError");if(!e._pc)throw new DOMException("Argument 1 of RTCPeerConnection.removeTrack does not implement interface RTCRtpSender.","TypeError");if(!(e._pc===this))throw new DOMException("Sender was not created by this connection.","InvalidAccessError");let t;this._streams=this._streams||{},Object.keys(this._streams).forEach((n=>{this._streams[n].getTracks().find((t=>e.track===t))&&(t=this._streams[n])})),t&&(1===t.getTracks().length?this.removeStream(this._reverseStreams[t.id]):t.removeTrack(e.track),this.dispatchEvent(new Event("negotiationneeded")))}}function R(e,t){!e.RTCPeerConnection&&e.webkitRTCPeerConnection&&(e.RTCPeerConnection=e.webkitRTCPeerConnection),e.RTCPeerConnection&&t.version<53&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(t){const n=e.RTCPeerConnection.prototype[t],r={[t](){return arguments[0]=new("addIceCandidate"===t?e.RTCIceCandidate:e.RTCSessionDescription)(arguments[0]),n.apply(this,arguments)}};e.RTCPeerConnection.prototype[t]=r[t]}))}function w(e,t){c(e,"negotiationneeded",(e=>{const n=e.target;if(!(t.version<72||n.getConfiguration&&"plan-b"===n.getConfiguration().sdpSemantics)||"stable"===n.signalingState)return e}))}function A(e,t){const n=e&&e.navigator,r=e&&e.MediaStreamTrack;if(n.getUserMedia=function(e,t,r){p("navigator.getUserMedia","navigator.mediaDevices.getUserMedia"),n.mediaDevices.getUserMedia(e).then(t,r)},!(t.version>55&&"autoGainControl"in n.mediaDevices.getSupportedConstraints())){const e=function(e,t,n){t in e&&!(n in e)&&(e[n]=e[t],delete e[t])},t=n.mediaDevices.getUserMedia.bind(n.mediaDevices);if(n.mediaDevices.getUserMedia=function(n){return"object"==typeof n&&"object"==typeof n.audio&&(n=JSON.parse(JSON.stringify(n)),e(n.audio,"autoGainControl","mozAutoGainControl"),e(n.audio,"noiseSuppression","mozNoiseSuppression")),t(n)},r&&r.prototype.getSettings){const t=r.prototype.getSettings;r.prototype.getSettings=function(){const n=t.apply(this,arguments);return e(n,"mozAutoGainControl","autoGainControl"),e(n,"mozNoiseSuppression","noiseSuppression"),n}}if(r&&r.prototype.applyConstraints){const t=r.prototype.applyConstraints;r.prototype.applyConstraints=function(n){return"audio"===this.kind&&"object"==typeof n&&(n=JSON.parse(JSON.stringify(n)),e(n,"autoGainControl","mozAutoGainControl"),e(n,"noiseSuppression","mozNoiseSuppression")),t.apply(this,[n])}}}}function x(e,t){e.navigator.mediaDevices&&"getDisplayMedia"in e.navigator.mediaDevices||e.navigator.mediaDevices&&(e.navigator.mediaDevices.getDisplayMedia=function(n){if(!n||!n.video){const e=new DOMException("getDisplayMedia without video constraints is undefined");return e.name="NotFoundError",e.code=8,Promise.reject(e)}return!0===n.video?n.video={mediaSource:t}:n.video.mediaSource=t,e.navigator.mediaDevices.getUserMedia(n)})}function I(e){"object"==typeof e&&e.RTCTrackEvent&&"receiver"in e.RTCTrackEvent.prototype&&!("transceiver"in e.RTCTrackEvent.prototype)&&Object.defineProperty(e.RTCTrackEvent.prototype,"transceiver",{get(){return{receiver:this.receiver}}})}function O(e,t){if("object"!=typeof e||!e.RTCPeerConnection&&!e.mozRTCPeerConnection)return;!e.RTCPeerConnection&&e.mozRTCPeerConnection&&(e.RTCPeerConnection=e.mozRTCPeerConnection),t.version<53&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(t){const n=e.RTCPeerConnection.prototype[t],r={[t](){return arguments[0]=new("addIceCandidate"===t?e.RTCIceCandidate:e.RTCSessionDescription)(arguments[0]),n.apply(this,arguments)}};e.RTCPeerConnection.prototype[t]=r[t]}));const n={inboundrtp:"inbound-rtp",outboundrtp:"outbound-rtp",candidatepair:"candidate-pair",localcandidate:"local-candidate",remotecandidate:"remote-candidate"},r=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){const[e,i,o]=arguments;return r.apply(this,[e||null]).then((e=>{if(t.version<53&&!i)try{e.forEach((e=>{e.type=n[e.type]||e.type}))}catch(t){if("TypeError"!==t.name)throw t;e.forEach(((t,r)=>{e.set(r,Object.assign({},t,{type:n[t.type]||t.type}))}))}return e})).then(i,o)}}function D(e){if("object"!=typeof e||!e.RTCPeerConnection||!e.RTCRtpSender)return;if(e.RTCRtpSender&&"getStats"in e.RTCRtpSender.prototype)return;const t=e.RTCPeerConnection.prototype.getSenders;t&&(e.RTCPeerConnection.prototype.getSenders=function(){const e=t.apply(this,[]);return e.forEach((e=>e._pc=this)),e});const n=e.RTCPeerConnection.prototype.addTrack;n&&(e.RTCPeerConnection.prototype.addTrack=function(){const e=n.apply(this,arguments);return e._pc=this,e}),e.RTCRtpSender.prototype.getStats=function(){return this.track?this._pc.getStats(this.track):Promise.resolve(new Map)}}function M(e){if("object"!=typeof e||!e.RTCPeerConnection||!e.RTCRtpSender)return;if(e.RTCRtpSender&&"getStats"in e.RTCRtpReceiver.prototype)return;const t=e.RTCPeerConnection.prototype.getReceivers;t&&(e.RTCPeerConnection.prototype.getReceivers=function(){const e=t.apply(this,[]);return e.forEach((e=>e._pc=this)),e}),c(e,"track",(e=>(e.receiver._pc=e.srcElement,e))),e.RTCRtpReceiver.prototype.getStats=function(){return this._pc.getStats(this.track)}}function L(e){e.RTCPeerConnection&&!("removeStream"in e.RTCPeerConnection.prototype)&&(e.RTCPeerConnection.prototype.removeStream=function(e){p("removeStream","removeTrack"),this.getSenders().forEach((t=>{t.track&&e.getTracks().includes(t.track)&&this.removeTrack(t)}))})}function H(e){e.DataChannel&&!e.RTCDataChannel&&(e.RTCDataChannel=e.DataChannel)}function G(e){if("object"!=typeof e||!e.RTCPeerConnection)return;const t=e.RTCPeerConnection.prototype.addTransceiver;t&&(e.RTCPeerConnection.prototype.addTransceiver=function(){this.setParametersPromises=[];let e=arguments[1]&&arguments[1].sendEncodings;void 0===e&&(e=[]),e=[...e];const n=e.length>0;n&&e.forEach((e=>{if("rid"in e){if(!/^[a-z0-9]{0,16}$/i.test(e.rid))throw new TypeError("Invalid RID value provided.")}if("scaleResolutionDownBy"in e&&!(parseFloat(e.scaleResolutionDownBy)>=1))throw new RangeError("scale_resolution_down_by must be >= 1.0");if("maxFramerate"in e&&!(parseFloat(e.maxFramerate)>=0))throw new RangeError("max_framerate must be >= 0.0")}));const r=t.apply(this,arguments);if(n){const{sender:t}=r,n=t.getParameters();(!("encodings"in n)||1===n.encodings.length&&0===Object.keys(n.encodings[0]).length)&&(n.encodings=e,t.sendEncodings=e,this.setParametersPromises.push(t.setParameters(n).then((()=>{delete t.sendEncodings})).catch((()=>{delete t.sendEncodings}))))}return r})}function j(e){if("object"!=typeof e||!e.RTCRtpSender)return;const t=e.RTCRtpSender.prototype.getParameters;t&&(e.RTCRtpSender.prototype.getParameters=function(){const e=t.apply(this,arguments);return"encodings"in e||(e.encodings=[].concat(this.sendEncodings||[{}])),e})}function N(e){if("object"!=typeof e||!e.RTCPeerConnection)return;const t=e.RTCPeerConnection.prototype.createOffer;e.RTCPeerConnection.prototype.createOffer=function(){return this.setParametersPromises&&this.setParametersPromises.length?Promise.all(this.setParametersPromises).then((()=>t.apply(this,arguments))).finally((()=>{this.setParametersPromises=[]})):t.apply(this,arguments)}}function U(e){if("object"!=typeof e||!e.RTCPeerConnection)return;const t=e.RTCPeerConnection.prototype.createAnswer;e.RTCPeerConnection.prototype.createAnswer=function(){return this.setParametersPromises&&this.setParametersPromises.length?Promise.all(this.setParametersPromises).then((()=>t.apply(this,arguments))).finally((()=>{this.setParametersPromises=[]})):t.apply(this,arguments)}}function F(e){if("object"==typeof e&&e.RTCPeerConnection){if("getLocalStreams"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.getLocalStreams=function(){return this._localStreams||(this._localStreams=[]),this._localStreams}),!("addStream"in e.RTCPeerConnection.prototype)){const t=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addStream=function(e){this._localStreams||(this._localStreams=[]),this._localStreams.includes(e)||this._localStreams.push(e),e.getAudioTracks().forEach((n=>t.call(this,n,e))),e.getVideoTracks().forEach((n=>t.call(this,n,e)))},e.RTCPeerConnection.prototype.addTrack=function(e,...n){return n&&n.forEach((e=>{this._localStreams?this._localStreams.includes(e)||this._localStreams.push(e):this._localStreams=[e]})),t.apply(this,arguments)}}"removeStream"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.removeStream=function(e){this._localStreams||(this._localStreams=[]);const t=this._localStreams.indexOf(e);if(-1===t)return;this._localStreams.splice(t,1);const n=e.getTracks();this.getSenders().forEach((e=>{n.includes(e.track)&&this.removeTrack(e)}))})}}function z(e){if("object"==typeof e&&e.RTCPeerConnection&&("getRemoteStreams"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.getRemoteStreams=function(){return this._remoteStreams?this._remoteStreams:[]}),!("onaddstream"in e.RTCPeerConnection.prototype))){Object.defineProperty(e.RTCPeerConnection.prototype,"onaddstream",{get(){return this._onaddstream},set(e){this._onaddstream&&(this.removeEventListener("addstream",this._onaddstream),this.removeEventListener("track",this._onaddstreampoly)),this.addEventListener("addstream",this._onaddstream=e),this.addEventListener("track",this._onaddstreampoly=e=>{e.streams.forEach((e=>{if(this._remoteStreams||(this._remoteStreams=[]),this._remoteStreams.includes(e))return;this._remoteStreams.push(e);const t=new Event("addstream");t.stream=e,this.dispatchEvent(t)}))})}});const t=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(){const e=this;return this._onaddstreampoly||this.addEventListener("track",this._onaddstreampoly=function(t){t.streams.forEach((t=>{if(e._remoteStreams||(e._remoteStreams=[]),e._remoteStreams.indexOf(t)>=0)return;e._remoteStreams.push(t);const n=new Event("addstream");n.stream=t,e.dispatchEvent(n)}))}),t.apply(e,arguments)}}}function J(e){if("object"!=typeof e||!e.RTCPeerConnection)return;const t=e.RTCPeerConnection.prototype,n=t.createOffer,r=t.createAnswer,i=t.setLocalDescription,o=t.setRemoteDescription,s=t.addIceCandidate;t.createOffer=function(e,t){const r=arguments.length>=2?arguments[2]:arguments[0],i=n.apply(this,[r]);return t?(i.then(e,t),Promise.resolve()):i},t.createAnswer=function(e,t){const n=arguments.length>=2?arguments[2]:arguments[0],i=r.apply(this,[n]);return t?(i.then(e,t),Promise.resolve()):i};let a=function(e,t,n){const r=i.apply(this,[e]);return n?(r.then(t,n),Promise.resolve()):r};t.setLocalDescription=a,a=function(e,t,n){const r=o.apply(this,[e]);return n?(r.then(t,n),Promise.resolve()):r},t.setRemoteDescription=a,a=function(e,t,n){const r=s.apply(this,[e]);return n?(r.then(t,n),Promise.resolve()):r},t.addIceCandidate=a}function K(e){const t=e&&e.navigator;if(t.mediaDevices&&t.mediaDevices.getUserMedia){const e=t.mediaDevices,n=e.getUserMedia.bind(e);t.mediaDevices.getUserMedia=e=>n(q(e))}!t.getUserMedia&&t.mediaDevices&&t.mediaDevices.getUserMedia&&(t.getUserMedia=function(e,n,r){t.mediaDevices.getUserMedia(e).then(n,r)}.bind(t))}function q(e){return e&&void 0!==e.video?Object.assign({},e,{video:m(e.video)}):e}function W(e){if(!e.RTCPeerConnection)return;const t=e.RTCPeerConnection;e.RTCPeerConnection=function(e,n){if(e&&e.iceServers){const t=[];for(let n=0;nt.generateCertificate})}function Y(e){"object"==typeof e&&e.RTCTrackEvent&&"receiver"in e.RTCTrackEvent.prototype&&!("transceiver"in e.RTCTrackEvent.prototype)&&Object.defineProperty(e.RTCTrackEvent.prototype,"transceiver",{get(){return{receiver:this.receiver}}})}function V(e){const t=e.RTCPeerConnection.prototype.createOffer;e.RTCPeerConnection.prototype.createOffer=function(e){if(e){void 0!==e.offerToReceiveAudio&&(e.offerToReceiveAudio=!!e.offerToReceiveAudio);const t=this.getTransceivers().find((e=>"audio"===e.receiver.track.kind));!1===e.offerToReceiveAudio&&t?"sendrecv"===t.direction?t.setDirection?t.setDirection("sendonly"):t.direction="sendonly":"recvonly"===t.direction&&(t.setDirection?t.setDirection("inactive"):t.direction="inactive"):!0!==e.offerToReceiveAudio||t||this.addTransceiver("audio",{direction:"recvonly"}),void 0!==e.offerToReceiveVideo&&(e.offerToReceiveVideo=!!e.offerToReceiveVideo);const n=this.getTransceivers().find((e=>"video"===e.receiver.track.kind));!1===e.offerToReceiveVideo&&n?"sendrecv"===n.direction?n.setDirection?n.setDirection("sendonly"):n.direction="sendonly":"recvonly"===n.direction&&(n.setDirection?n.setDirection("inactive"):n.direction="inactive"):!0!==e.offerToReceiveVideo||n||this.addTransceiver("video",{direction:"recvonly"})}return t.apply(this,arguments)}}function B(e){"object"!=typeof e||e.AudioContext||(e.AudioContext=e.webkitAudioContext)}var Z=n(539),X=n.n(Z);function $(e){if(!e.RTCIceCandidate||e.RTCIceCandidate&&"foundation"in e.RTCIceCandidate.prototype)return;const t=e.RTCIceCandidate;e.RTCIceCandidate=function(e){if("object"==typeof e&&e.candidate&&0===e.candidate.indexOf("a=")&&((e=JSON.parse(JSON.stringify(e))).candidate=e.candidate.substring(2)),e.candidate&&e.candidate.length){const n=new t(e),r=X().parseCandidate(e.candidate);for(const e in r)e in n||Object.defineProperty(n,e,{value:r[e]});return n.toJSON=function(){return{candidate:n.candidate,sdpMid:n.sdpMid,sdpMLineIndex:n.sdpMLineIndex,usernameFragment:n.usernameFragment}},n}return new t(e)},e.RTCIceCandidate.prototype=t.prototype,c(e,"icecandidate",(t=>(t.candidate&&Object.defineProperty(t,"candidate",{value:new e.RTCIceCandidate(t.candidate),writable:"false"}),t)))}function Q(e){!e.RTCIceCandidate||e.RTCIceCandidate&&"relayProtocol"in e.RTCIceCandidate.prototype||c(e,"icecandidate",(e=>{if(e.candidate){const t=X().parseCandidate(e.candidate.candidate);"relay"===t.type&&(e.candidate.relayProtocol={0:"tls",1:"tcp",2:"udp"}[t.priority>>24])}return e}))}function ee(e,t){if(!e.RTCPeerConnection)return;"sctp"in e.RTCPeerConnection.prototype||Object.defineProperty(e.RTCPeerConnection.prototype,"sctp",{get(){return void 0===this._sctp?null:this._sctp}});const n=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(){if(this._sctp=null,"chrome"===t.browser&&t.version>=76){const{sdpSemantics:e}=this.getConfiguration();"plan-b"===e&&Object.defineProperty(this,"sctp",{get(){return void 0===this._sctp?null:this._sctp},enumerable:!0,configurable:!0})}if(function(e){if(!e||!e.sdp)return!1;const t=X().splitSections(e.sdp);return t.shift(),t.some((e=>{const t=X().parseMLine(e);return t&&"application"===t.kind&&-1!==t.protocol.indexOf("SCTP")}))}(arguments[0])){const e=function(e){const t=e.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);if(null===t||t.length<2)return-1;const n=parseInt(t[1],10);return n!=n?-1:n}(arguments[0]),n=function(e){let n=65536;return"firefox"===t.browser&&(n=t.version<57?-1===e?16384:2147483637:t.version<60?57===t.version?65535:65536:2147483637),n}(e),r=function(e,n){let r=65536;"firefox"===t.browser&&57===t.version&&(r=65535);const i=X().matchPrefix(e.sdp,"a=max-message-size:");return i.length>0?r=parseInt(i[0].substring(19),10):"firefox"===t.browser&&-1!==n&&(r=2147483637),r}(arguments[0],e);let i;i=0===n&&0===r?Number.POSITIVE_INFINITY:0===n||0===r?Math.max(n,r):Math.min(n,r);const o={};Object.defineProperty(o,"maxMessageSize",{get:()=>i}),this._sctp=o}return n.apply(this,arguments)}}function te(e){if(!e.RTCPeerConnection||!("createDataChannel"in e.RTCPeerConnection.prototype))return;function t(e,t){const n=e.send;e.send=function(){const r=arguments[0],i=r.length||r.size||r.byteLength;if("open"===e.readyState&&t.sctp&&i>t.sctp.maxMessageSize)throw new TypeError("Message too large (can send a maximum of "+t.sctp.maxMessageSize+" bytes)");return n.apply(e,arguments)}}const n=e.RTCPeerConnection.prototype.createDataChannel;e.RTCPeerConnection.prototype.createDataChannel=function(){const e=n.apply(this,arguments);return t(e,this),e},c(e,"datachannel",(e=>(t(e.channel,e.target),e)))}function ne(e){if(!e.RTCPeerConnection||"connectionState"in e.RTCPeerConnection.prototype)return;const t=e.RTCPeerConnection.prototype;Object.defineProperty(t,"connectionState",{get(){return{completed:"connected",checking:"connecting"}[this.iceConnectionState]||this.iceConnectionState},enumerable:!0,configurable:!0}),Object.defineProperty(t,"onconnectionstatechange",{get(){return this._onconnectionstatechange||null},set(e){this._onconnectionstatechange&&(this.removeEventListener("connectionstatechange",this._onconnectionstatechange),delete this._onconnectionstatechange),e&&this.addEventListener("connectionstatechange",this._onconnectionstatechange=e)},enumerable:!0,configurable:!0}),["setLocalDescription","setRemoteDescription"].forEach((e=>{const n=t[e];t[e]=function(){return this._connectionstatechangepoly||(this._connectionstatechangepoly=e=>{const t=e.target;if(t._lastConnectionState!==t.connectionState){t._lastConnectionState=t.connectionState;const n=new Event("connectionstatechange",e);t.dispatchEvent(n)}return e},this.addEventListener("iceconnectionstatechange",this._connectionstatechangepoly)),n.apply(this,arguments)}}))}function re(e,t){if(!e.RTCPeerConnection)return;if("chrome"===t.browser&&t.version>=71)return;if("safari"===t.browser&&t.version>=605)return;const n=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(t){if(t&&t.sdp&&-1!==t.sdp.indexOf("\na=extmap-allow-mixed")){const n=t.sdp.split("\n").filter((e=>"a=extmap-allow-mixed"!==e.trim())).join("\n");e.RTCSessionDescription&&t instanceof e.RTCSessionDescription?arguments[0]=new e.RTCSessionDescription({type:t.type,sdp:n}):t.sdp=n}return n.apply(this,arguments)}}function ie(e,t){if(!e.RTCPeerConnection||!e.RTCPeerConnection.prototype)return;const n=e.RTCPeerConnection.prototype.addIceCandidate;n&&0!==n.length&&(e.RTCPeerConnection.prototype.addIceCandidate=function(){return arguments[0]?("chrome"===t.browser&&t.version<78||"firefox"===t.browser&&t.version<68||"safari"===t.browser)&&arguments[0]&&""===arguments[0].candidate?Promise.resolve():n.apply(this,arguments):(arguments[1]&&arguments[1].apply(null),Promise.resolve())})}function oe(e,t){if(!e.RTCPeerConnection||!e.RTCPeerConnection.prototype)return;const n=e.RTCPeerConnection.prototype.setLocalDescription;n&&0!==n.length&&(e.RTCPeerConnection.prototype.setLocalDescription=function(){let e=arguments[0]||{};if("object"!=typeof e||e.type&&e.sdp)return n.apply(this,arguments);if(e={type:e.type,sdp:e.sdp},!e.type)switch(this.signalingState){case"stable":case"have-local-offer":case"have-remote-pranswer":e.type="offer";break;default:e.type="answer"}if(e.sdp||"offer"!==e.type&&"answer"!==e.type)return n.apply(this,[e]);return("offer"===e.type?this.createOffer:this.createAnswer).apply(this).then((e=>n.apply(this,[e])))})}!function({window:n}={},o={shimChrome:!0,shimFirefox:!0,shimSafari:!0}){const s=h,c=function(e){const t={browser:null,version:null};if(void 0===e||!e.navigator)return t.browser="Not a browser.",t;const{navigator:n}=e;if(n.mozGetUserMedia)t.browser="firefox",t.version=a(n.userAgent,/Firefox\/(\d+)\./,1);else if(n.webkitGetUserMedia||!1===e.isSecureContext&&e.webkitRTCPeerConnection)t.browser="chrome",t.version=a(n.userAgent,/Chrom(e|ium)\/(\d+)\./,2);else{if(!e.RTCPeerConnection||!n.userAgent.match(/AppleWebKit\/(\d+)\./))return t.browser="Not a supported browser.",t;t.browser="safari",t.version=a(n.userAgent,/AppleWebKit\/(\d+)\./,1),t.supportsUnifiedPlan=e.RTCRtpTransceiver&&"currentDirection"in e.RTCRtpTransceiver.prototype}return t}(n),p={browserDetails:c,commonShim:i,extractVersion:a,disableLog:d,disableWarnings:l,sdp:Z};switch(c.browser){case"chrome":if(!e||!R||!o.shimChrome)return s("Chrome shim is not included in this adapter release."),p;if(null===c.version)return s("Chrome shim can not determine version, not shimming."),p;s("adapter.js shimming chrome."),p.browserShim=e,ie(n,c),oe(n),C(n,c),v(n),R(n,c),b(n),P(n,c),S(n),k(n),T(n),w(n,c),$(n),Q(n),ne(n),ee(n,c),te(n),re(n,c);break;case"firefox":if(!t||!O||!o.shimFirefox)return s("Firefox shim is not included in this adapter release."),p;s("adapter.js shimming firefox."),p.browserShim=t,ie(n,c),oe(n),A(n,c),O(n,c),I(n),L(n),D(n),M(n),H(n),G(n),j(n),N(n),U(n),$(n),ne(n),ee(n,c),te(n);break;case"safari":if(!r||!o.shimSafari)return s("Safari shim is not included in this adapter release."),p;s("adapter.js shimming safari."),p.browserShim=r,ie(n,c),oe(n),W(n),V(n),J(n),F(n),z(n),Y(n),K(n),B(n),$(n),Q(n),ee(n,c),te(n),re(n,c);break;default:s("Unsupported browser!")}}({window:"undefined"==typeof window?void 0:window});const se=Object.freeze({meta:null,signalingServerUrl:"ws://127.0.0.1:8443",reconnectionTimeout:2500,webrtcConfig:{iceServers:[{urls:["stun:stun.l.google.com:19302","stun:stun1.l.google.com:19302"]}]}}),ae={idle:0,connecting:1,streaming:2,closed:3};Object.freeze(ae);const ce=ae;class de extends EventTarget{constructor(e,t){super(),this._peerId=e,this._sessionId="",this._comChannel=t,this._state=ce.idle,this._rtcPeerConnection=null}get peerId(){return this._peerId}get sessionId(){return this._sessionId}get state(){return this._state}get rtcPeerConnection(){return this._rtcPeerConnection}close(){this._state!==ce.closed&&(this._state!==ce.idle&&this._comChannel&&this._sessionId&&this._comChannel.send({type:"endSession",sessionId:this._sessionId}),this._state=ce.closed,this.dispatchEvent(new Event("stateChanged")),this._comChannel=null,this._rtcPeerConnection&&(this._rtcPeerConnection.close(),this._rtcPeerConnection=null,this.dispatchEvent(new Event("rtcPeerConnectionChanged"))),this.dispatchEvent(new Event("closed")))}}const le=de,he=Object.freeze({32:"space",33:"exclam",34:"quotedbl",35:"numbersign",36:"dollar",37:"percent",38:"ampersand",39:"apostrophe",40:"parenleft",41:"parenright",42:"asterisk",43:"plus",44:"comma",45:"minus",46:"period",47:"slash",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",58:"colon",59:"semicolon",60:"less",61:"equal",62:"greater",63:"question",64:"at",65:"A",66:"B",67:"C",68:"D",69:"E",70:"F",71:"G",72:"H",73:"I",74:"J",75:"K",76:"L",77:"M",78:"N",79:"O",80:"P",81:"Q",82:"R",83:"S",84:"T",85:"U",86:"V",87:"W",88:"X",89:"Y",90:"Z",91:"bracketleft",92:"backslash",93:"bracketright",94:"asciicircum",95:"underscore",96:"grave",97:"a",98:"b",99:"c",100:"d",101:"e",102:"f",103:"g",104:"h",105:"i",106:"j",107:"k",108:"l",109:"m",110:"n",111:"o",112:"p",113:"q",114:"r",115:"s",116:"t",117:"u",118:"v",119:"w",120:"x",121:"y",122:"z",123:"braceleft",124:"bar",125:"braceright",126:"asciitilde",160:"nobreakspace",161:"exclamdown",162:"cent",163:"sterling",164:"currency",165:"yen",166:"brokenbar",167:"section",168:"diaeresis",169:"copyright",170:"ordfeminine",171:"guillemotleft",172:"notsign",173:"hyphen",174:"registered",175:"macron",176:"degree",177:"plusminus",178:"twosuperior",179:"threesuperior",180:"acute",181:"mu",182:"paragraph",183:"periodcentered",184:"cedilla",185:"onesuperior",186:"masculine",187:"guillemotright",188:"onequarter",189:"onehalf",190:"threequarters",191:"questiondown",192:"Agrave",193:"Aacute",194:"Acircumflex",195:"Atilde",196:"Adiaeresis",197:"Aring",198:"AE",199:"Ccedilla",200:"Egrave",201:"Eacute",202:"Ecircumflex",203:"Ediaeresis",204:"Igrave",205:"Iacute",206:"Icircumflex",207:"Idiaeresis",208:"ETH",209:"Ntilde",210:"Ograve",211:"Oacute",212:"Ocircumflex",213:"Otilde",214:"Odiaeresis",215:"multiply",216:"Ooblique",217:"Ugrave",218:"Uacute",219:"Ucircumflex",220:"Udiaeresis",221:"Yacute",222:"THORN",223:"ssharp",224:"agrave",225:"aacute",226:"acircumflex",227:"atilde",228:"adiaeresis",229:"aring",230:"ae",231:"ccedilla",232:"egrave",233:"eacute",234:"ecircumflex",235:"ediaeresis",236:"igrave",237:"iacute",238:"icircumflex",239:"idiaeresis",240:"eth",241:"ntilde",242:"ograve",243:"oacute",244:"ocircumflex",245:"otilde",246:"odiaeresis",247:"division",248:"oslash",249:"ugrave",250:"uacute",251:"ucircumflex",252:"udiaeresis",253:"yacute",254:"thorn",255:"ydiaeresis",260:"Aogonek",728:"breve",321:"Lstroke",317:"Lcaron",346:"Sacute",352:"Scaron",350:"Scedilla",356:"Tcaron",377:"Zacute",381:"Zcaron",379:"Zabovedot",261:"aogonek",731:"ogonek",322:"lstroke",318:"lcaron",347:"sacute",711:"caron",353:"scaron",351:"scedilla",357:"tcaron",378:"zacute",733:"doubleacute",382:"zcaron",380:"zabovedot",340:"Racute",258:"Abreve",313:"Lacute",262:"Cacute",268:"Ccaron",280:"Eogonek",282:"Ecaron",270:"Dcaron",272:"Dstroke",323:"Nacute",327:"Ncaron",336:"Odoubleacute",344:"Rcaron",366:"Uring",368:"Udoubleacute",354:"Tcedilla",341:"racute",259:"abreve",314:"lacute",263:"cacute",269:"ccaron",281:"eogonek",283:"ecaron",271:"dcaron",273:"dstroke",324:"nacute",328:"ncaron",337:"odoubleacute",345:"rcaron",367:"uring",369:"udoubleacute",355:"tcedilla",729:"abovedot",294:"Hstroke",292:"Hcircumflex",304:"Iabovedot",286:"Gbreve",308:"Jcircumflex",295:"hstroke",293:"hcircumflex",305:"idotless",287:"gbreve",309:"jcircumflex",266:"Cabovedot",264:"Ccircumflex",288:"Gabovedot",284:"Gcircumflex",364:"Ubreve",348:"Scircumflex",267:"cabovedot",265:"ccircumflex",289:"gabovedot",285:"gcircumflex",365:"ubreve",349:"scircumflex",312:"kra",342:"Rcedilla",296:"Itilde",315:"Lcedilla",274:"Emacron",290:"Gcedilla",358:"Tslash",343:"rcedilla",297:"itilde",316:"lcedilla",275:"emacron",291:"gcedilla",359:"tslash",330:"ENG",331:"eng",256:"Amacron",302:"Iogonek",278:"Eabovedot",298:"Imacron",325:"Ncedilla",332:"Omacron",310:"Kcedilla",370:"Uogonek",360:"Utilde",362:"Umacron",257:"amacron",303:"iogonek",279:"eabovedot",299:"imacron",326:"ncedilla",333:"omacron",311:"kcedilla",371:"uogonek",361:"utilde",363:"umacron",8254:"overline",12290:"kana_fullstop",12300:"kana_openingbracket",12301:"kana_closingbracket",12289:"kana_comma",12539:"kana_conjunctive",12530:"kana_WO",12449:"kana_a",12451:"kana_i",12453:"kana_u",12455:"kana_e",12457:"kana_o",12515:"kana_ya",12517:"kana_yu",12519:"kana_yo",12483:"kana_tsu",12540:"prolongedsound",12450:"kana_A",12452:"kana_I",12454:"kana_U",12456:"kana_E",12458:"kana_O",12459:"kana_KA",12461:"kana_KI",12463:"kana_KU",12465:"kana_KE",12467:"kana_KO",12469:"kana_SA",12471:"kana_SHI",12473:"kana_SU",12475:"kana_SE",12477:"kana_SO",12479:"kana_TA",12481:"kana_CHI",12484:"kana_TSU",12486:"kana_TE",12488:"kana_TO",12490:"kana_NA",12491:"kana_NI",12492:"kana_NU",12493:"kana_NE",12494:"kana_NO",12495:"kana_HA",12498:"kana_HI",12501:"kana_FU",12504:"kana_HE",12507:"kana_HO",12510:"kana_MA",12511:"kana_MI",12512:"kana_MU",12513:"kana_ME",12514:"kana_MO",12516:"kana_YA",12518:"kana_YU",12520:"kana_YO",12521:"kana_RA",12522:"kana_RI",12523:"kana_RU",12524:"kana_RE",12525:"kana_RO",12527:"kana_WA",12531:"kana_N",12443:"voicedsound",12444:"semivoicedsound",1548:"Arabic_comma",1563:"Arabic_semicolon",1567:"Arabic_question_mark",1569:"Arabic_hamza",1570:"Arabic_maddaonalef",1571:"Arabic_hamzaonalef",1572:"Arabic_hamzaonwaw",1573:"Arabic_hamzaunderalef",1574:"Arabic_hamzaonyeh",1575:"Arabic_alef",1576:"Arabic_beh",1577:"Arabic_tehmarbuta",1578:"Arabic_teh",1579:"Arabic_theh",1580:"Arabic_jeem",1581:"Arabic_hah",1582:"Arabic_khah",1583:"Arabic_dal",1584:"Arabic_thal",1585:"Arabic_ra",1586:"Arabic_zain",1587:"Arabic_seen",1588:"Arabic_sheen",1589:"Arabic_sad",1590:"Arabic_dad",1591:"Arabic_tah",1592:"Arabic_zah",1593:"Arabic_ain",1594:"Arabic_ghain",1600:"Arabic_tatweel",1601:"Arabic_feh",1602:"Arabic_qaf",1603:"Arabic_kaf",1604:"Arabic_lam",1605:"Arabic_meem",1606:"Arabic_noon",1607:"Arabic_ha",1608:"Arabic_waw",1609:"Arabic_alefmaksura",1610:"Arabic_yeh",1611:"Arabic_fathatan",1612:"Arabic_dammatan",1613:"Arabic_kasratan",1614:"Arabic_fatha",1615:"Arabic_damma",1616:"Arabic_kasra",1617:"Arabic_shadda",1618:"Arabic_sukun",1106:"Serbian_dje",1107:"Macedonia_gje",1105:"Cyrillic_io",1108:"Ukrainian_ie",1109:"Macedonia_dse",1110:"Ukrainian_i",1111:"Ukrainian_yi",1112:"Cyrillic_je",1113:"Cyrillic_lje",1114:"Cyrillic_nje",1115:"Serbian_tshe",1116:"Macedonia_kje",1118:"Byelorussian_shortu",1119:"Cyrillic_dzhe",8470:"numerosign",1026:"Serbian_DJE",1027:"Macedonia_GJE",1025:"Cyrillic_IO",1028:"Ukrainian_IE",1029:"Macedonia_DSE",1030:"Ukrainian_I",1031:"Ukrainian_YI",1032:"Cyrillic_JE",1033:"Cyrillic_LJE",1034:"Cyrillic_NJE",1035:"Serbian_TSHE",1036:"Macedonia_KJE",1038:"Byelorussian_SHORTU",1039:"Cyrillic_DZHE",1102:"Cyrillic_yu",1072:"Cyrillic_a",1073:"Cyrillic_be",1094:"Cyrillic_tse",1076:"Cyrillic_de",1077:"Cyrillic_ie",1092:"Cyrillic_ef",1075:"Cyrillic_ghe",1093:"Cyrillic_ha",1080:"Cyrillic_i",1081:"Cyrillic_shorti",1082:"Cyrillic_ka",1083:"Cyrillic_el",1084:"Cyrillic_em",1085:"Cyrillic_en",1086:"Cyrillic_o",1087:"Cyrillic_pe",1103:"Cyrillic_ya",1088:"Cyrillic_er",1089:"Cyrillic_es",1090:"Cyrillic_te",1091:"Cyrillic_u",1078:"Cyrillic_zhe",1074:"Cyrillic_ve",1100:"Cyrillic_softsign",1099:"Cyrillic_yeru",1079:"Cyrillic_ze",1096:"Cyrillic_sha",1101:"Cyrillic_e",1097:"Cyrillic_shcha",1095:"Cyrillic_che",1098:"Cyrillic_hardsign",1070:"Cyrillic_YU",1040:"Cyrillic_A",1041:"Cyrillic_BE",1062:"Cyrillic_TSE",1044:"Cyrillic_DE",1045:"Cyrillic_IE",1060:"Cyrillic_EF",1043:"Cyrillic_GHE",1061:"Cyrillic_HA",1048:"Cyrillic_I",1049:"Cyrillic_SHORTI",1050:"Cyrillic_KA",1051:"Cyrillic_EL",1052:"Cyrillic_EM",1053:"Cyrillic_EN",1054:"Cyrillic_O",1055:"Cyrillic_PE",1071:"Cyrillic_YA",1056:"Cyrillic_ER",1057:"Cyrillic_ES",1058:"Cyrillic_TE",1059:"Cyrillic_U",1046:"Cyrillic_ZHE",1042:"Cyrillic_VE",1068:"Cyrillic_SOFTSIGN",1067:"Cyrillic_YERU",1047:"Cyrillic_ZE",1064:"Cyrillic_SHA",1069:"Cyrillic_E",1065:"Cyrillic_SHCHA",1063:"Cyrillic_CHE",1066:"Cyrillic_HARDSIGN",902:"Greek_ALPHAaccent",904:"Greek_EPSILONaccent",905:"Greek_ETAaccent",906:"Greek_IOTAaccent",938:"Greek_IOTAdiaeresis",908:"Greek_OMICRONaccent",910:"Greek_UPSILONaccent",939:"Greek_UPSILONdieresis",911:"Greek_OMEGAaccent",901:"Greek_accentdieresis",8213:"Greek_horizbar",940:"Greek_alphaaccent",941:"Greek_epsilonaccent",942:"Greek_etaaccent",943:"Greek_iotaaccent",970:"Greek_iotadieresis",912:"Greek_iotaaccentdieresis",972:"Greek_omicronaccent",973:"Greek_upsilonaccent",971:"Greek_upsilondieresis",944:"Greek_upsilonaccentdieresis",974:"Greek_omegaaccent",913:"Greek_ALPHA",914:"Greek_BETA",915:"Greek_GAMMA",916:"Greek_DELTA",917:"Greek_EPSILON",918:"Greek_ZETA",919:"Greek_ETA",920:"Greek_THETA",921:"Greek_IOTA",922:"Greek_KAPPA",923:"Greek_LAMBDA",924:"Greek_MU",925:"Greek_NU",926:"Greek_XI",927:"Greek_OMICRON",928:"Greek_PI",929:"Greek_RHO",931:"Greek_SIGMA",932:"Greek_TAU",933:"Greek_UPSILON",934:"Greek_PHI",935:"Greek_CHI",936:"Greek_PSI",937:"Greek_OMEGA",945:"Greek_alpha",946:"Greek_beta",947:"Greek_gamma",948:"Greek_delta",949:"Greek_epsilon",950:"Greek_zeta",951:"Greek_eta",952:"Greek_theta",953:"Greek_iota",954:"Greek_kappa",955:"Greek_lambda",956:"Greek_mu",957:"Greek_nu",958:"Greek_xi",959:"Greek_omicron",960:"Greek_pi",961:"Greek_rho",963:"Greek_sigma",962:"Greek_finalsmallsigma",964:"Greek_tau",965:"Greek_upsilon",966:"Greek_phi",967:"Greek_chi",968:"Greek_psi",969:"Greek_omega",9143:"leftradical",8992:"topintegral",8993:"botintegral",9121:"topleftsqbracket",9123:"botleftsqbracket",9124:"toprightsqbracket",9126:"botrightsqbracket",9115:"topleftparens",9117:"botleftparens",9118:"toprightparens",9120:"botrightparens",9128:"leftmiddlecurlybrace",9132:"rightmiddlecurlybrace",8804:"lessthanequal",8800:"notequal",8805:"greaterthanequal",8747:"integral",8756:"therefore",8733:"variation",8734:"infinity",8711:"nabla",8764:"approximate",8771:"similarequal",8660:"ifonlyif",8658:"implies",8801:"identical",8730:"radical",8834:"includedin",8835:"includes",8745:"intersection",8746:"union",8743:"logicaland",8744:"logicalor",8706:"partialderivative",402:"function",8592:"leftarrow",8593:"uparrow",8594:"rightarrow",8595:"downarrow",9670:"soliddiamond",9618:"checkerboard",9225:"ht",9228:"ff",9229:"cr",9226:"lf",9252:"nl",9227:"vt",9496:"lowrightcorner",9488:"uprightcorner",9484:"upleftcorner",9492:"lowleftcorner",9532:"crossinglines",9146:"horizlinescan1",9147:"horizlinescan3",9472:"horizlinescan5",9148:"horizlinescan7",9149:"horizlinescan9",9500:"leftt",9508:"rightt",9524:"bott",9516:"topt",9474:"vertbar",8195:"emspace",8194:"enspace",8196:"em3space",8197:"em4space",8199:"digitspace",8200:"punctspace",8201:"thinspace",8202:"hairspace",8212:"emdash",8211:"endash",9251:"signifblank",8230:"ellipsis",8229:"doubbaselinedot",8531:"onethird",8532:"twothirds",8533:"onefifth",8534:"twofifths",8535:"threefifths",8536:"fourfifths",8537:"onesixth",8538:"fivesixths",8453:"careof",8210:"figdash",10216:"leftanglebracket",10217:"rightanglebracket",8539:"oneeighth",8540:"threeeighths",8541:"fiveeighths",8542:"seveneighths",8482:"trademark",9747:"signaturemark",9665:"leftopentriangle",9655:"rightopentriangle",9647:"emopenrectangle",8216:"leftsinglequotemark",8217:"rightsinglequotemark",8220:"leftdoublequotemark",8221:"rightdoublequotemark",8478:"prescription",8242:"minutes",8243:"seconds",10013:"latincross",9644:"filledrectbullet",9664:"filledlefttribullet",9654:"filledrighttribullet",9679:"emfilledcircle",9646:"emfilledrect",9702:"enopencircbullet",9643:"enopensquarebullet",9645:"openrectbullet",9651:"opentribulletup",9661:"opentribulletdown",9734:"openstar",8226:"enfilledcircbullet",9642:"enfilledsqbullet",9650:"filledtribulletup",9660:"filledtribulletdown",9756:"leftpointer",9758:"rightpointer",9827:"club",9830:"diamond",9829:"heart",10016:"maltesecross",8224:"dagger",8225:"doubledagger",10003:"checkmark",10007:"ballotcross",9839:"musicalsharp",9837:"musicalflat",9794:"malesymbol",9792:"femalesymbol",9742:"telephone",8981:"telephonerecorder",8471:"phonographcopyright",8248:"caret",8218:"singlelowquotemark",8222:"doublelowquotemark",8869:"downtack",8970:"downstile",8728:"jot",9109:"quad",8868:"uptack",9675:"circle",8968:"upstile",8866:"lefttack",8867:"righttack",8215:"hebrew_doublelowline",1488:"hebrew_aleph",1489:"hebrew_beth",1490:"hebrew_gimmel",1491:"hebrew_daleth",1492:"hebrew_he",1493:"hebrew_waw",1494:"hebrew_zayin",1495:"hebrew_het",1496:"hebrew_teth",1497:"hebrew_yod",1498:"hebrew_finalkaph",1499:"hebrew_kaph",1500:"hebrew_lamed",1501:"hebrew_finalmem",1502:"hebrew_mem",1503:"hebrew_finalnun",1504:"hebrew_nun",1505:"hebrew_samekh",1506:"hebrew_ayin",1507:"hebrew_finalpe",1508:"hebrew_pe",1509:"hebrew_finalzadi",1510:"hebrew_zadi",1511:"hebrew_qoph",1512:"hebrew_resh",1513:"hebrew_shin",1514:"hebrew_taw",3585:"Thai_kokai",3586:"Thai_khokhai",3587:"Thai_khokhuat",3588:"Thai_khokhwai",3589:"Thai_khokhon",3590:"Thai_khorakhang",3591:"Thai_ngongu",3592:"Thai_chochan",3593:"Thai_choching",3594:"Thai_chochang",3595:"Thai_soso",3596:"Thai_chochoe",3597:"Thai_yoying",3598:"Thai_dochada",3599:"Thai_topatak",3600:"Thai_thothan",3601:"Thai_thonangmontho",3602:"Thai_thophuthao",3603:"Thai_nonen",3604:"Thai_dodek",3605:"Thai_totao",3606:"Thai_thothung",3607:"Thai_thothahan",3608:"Thai_thothong",3609:"Thai_nonu",3610:"Thai_bobaimai",3611:"Thai_popla",3612:"Thai_phophung",3613:"Thai_fofa",3614:"Thai_phophan",3615:"Thai_fofan",3616:"Thai_phosamphao",3617:"Thai_moma",3618:"Thai_yoyak",3619:"Thai_rorua",3620:"Thai_ru",3621:"Thai_loling",3622:"Thai_lu",3623:"Thai_wowaen",3624:"Thai_sosala",3625:"Thai_sorusi",3626:"Thai_sosua",3627:"Thai_hohip",3628:"Thai_lochula",3629:"Thai_oang",3630:"Thai_honokhuk",3631:"Thai_paiyannoi",3632:"Thai_saraa",3633:"Thai_maihanakat",3634:"Thai_saraaa",3635:"Thai_saraam",3636:"Thai_sarai",3637:"Thai_saraii",3638:"Thai_saraue",3639:"Thai_sarauee",3640:"Thai_sarau",3641:"Thai_sarauu",3642:"Thai_phinthu",3647:"Thai_baht",3648:"Thai_sarae",3649:"Thai_saraae",3650:"Thai_sarao",3651:"Thai_saraaimaimuan",3652:"Thai_saraaimaimalai",3653:"Thai_lakkhangyao",3654:"Thai_maiyamok",3655:"Thai_maitaikhu",3656:"Thai_maiek",3657:"Thai_maitho",3658:"Thai_maitri",3659:"Thai_maichattawa",3660:"Thai_thanthakhat",3661:"Thai_nikhahit",3664:"Thai_leksun",3665:"Thai_leknung",3666:"Thai_leksong",3667:"Thai_leksam",3668:"Thai_leksi",3669:"Thai_lekha",3670:"Thai_lekhok",3671:"Thai_lekchet",3672:"Thai_lekpaet",3673:"Thai_lekkao",12593:"Hangul_Kiyeog",12594:"Hangul_SsangKiyeog",12595:"Hangul_KiyeogSios",12596:"Hangul_Nieun",12597:"Hangul_NieunJieuj",12598:"Hangul_NieunHieuh",12599:"Hangul_Dikeud",12600:"Hangul_SsangDikeud",12601:"Hangul_Rieul",12602:"Hangul_RieulKiyeog",12603:"Hangul_RieulMieum",12604:"Hangul_RieulPieub",12605:"Hangul_RieulSios",12606:"Hangul_RieulTieut",12607:"Hangul_RieulPhieuf",12608:"Hangul_RieulHieuh",12609:"Hangul_Mieum",12610:"Hangul_Pieub",12611:"Hangul_SsangPieub",12612:"Hangul_PieubSios",12613:"Hangul_Sios",12614:"Hangul_SsangSios",12615:"Hangul_Ieung",12616:"Hangul_Jieuj",12617:"Hangul_SsangJieuj",12618:"Hangul_Cieuc",12619:"Hangul_Khieuq",12620:"Hangul_Tieut",12621:"Hangul_Phieuf",12622:"Hangul_Hieuh",12623:"Hangul_A",12624:"Hangul_AE",12625:"Hangul_YA",12626:"Hangul_YAE",12627:"Hangul_EO",12628:"Hangul_E",12629:"Hangul_YEO",12630:"Hangul_YE",12631:"Hangul_O",12632:"Hangul_WA",12633:"Hangul_WAE",12634:"Hangul_OE",12635:"Hangul_YO",12636:"Hangul_U",12637:"Hangul_WEO",12638:"Hangul_WE",12639:"Hangul_WI",12640:"Hangul_YU",12641:"Hangul_EU",12642:"Hangul_YI",12643:"Hangul_I",4520:"Hangul_J_Kiyeog",4521:"Hangul_J_SsangKiyeog",4522:"Hangul_J_KiyeogSios",4523:"Hangul_J_Nieun",4524:"Hangul_J_NieunJieuj",4525:"Hangul_J_NieunHieuh",4526:"Hangul_J_Dikeud",4527:"Hangul_J_Rieul",4528:"Hangul_J_RieulKiyeog",4529:"Hangul_J_RieulMieum",4530:"Hangul_J_RieulPieub",4531:"Hangul_J_RieulSios",4532:"Hangul_J_RieulTieut",4533:"Hangul_J_RieulPhieuf",4534:"Hangul_J_RieulHieuh",4535:"Hangul_J_Mieum",4536:"Hangul_J_Pieub",4537:"Hangul_J_PieubSios",4538:"Hangul_J_Sios",4539:"Hangul_J_SsangSios",4540:"Hangul_J_Ieung",4541:"Hangul_J_Jieuj",4542:"Hangul_J_Cieuc",4543:"Hangul_J_Khieuq",4544:"Hangul_J_Tieut",4545:"Hangul_J_Phieuf",4546:"Hangul_J_Hieuh",12653:"Hangul_RieulYeorinHieuh",12657:"Hangul_SunkyeongeumMieum",12664:"Hangul_SunkyeongeumPieub",12671:"Hangul_PanSios",12673:"Hangul_KkogjiDalrinIeung",12676:"Hangul_SunkyeongeumPhieuf",12678:"Hangul_YeorinHieuh",12685:"Hangul_AraeA",12686:"Hangul_AraeAE",4587:"Hangul_J_PanSios",4592:"Hangul_J_KkogjiDalrinIeung",4601:"Hangul_J_YeorinHieuh",338:"OE",339:"oe",376:"Ydiaeresis",8352:"EcuSign",8353:"ColonSign",8354:"CruzeiroSign",8355:"FFrancSign",8356:"LiraSign",8357:"MillSign",8358:"NairaSign",8359:"PesetaSign",8360:"RupeeSign",8361:"WonSign",8362:"NewSheqelSign",8363:"DongSign",8364:"EuroSign",768:"dead_grave",769:"dead_acute",770:"dead_circumflex",771:"dead_tilde",772:"dead_macron",774:"dead_breve",775:"dead_abovedot",776:"dead_diaeresis",778:"dead_abovering",779:"dead_doubleacute",780:"dead_caron",807:"dead_cedilla",808:"dead_ogonek",837:"dead_iota",12441:"dead_voiced_sound",12442:"dead_semivoiced_sound",8:"BackSpace",9:"Tab",10:"Linefeed",11:"Clear",13:"Return",19:"Pause",20:"Scroll_Lock",21:"Sys_Req",27:"Escape",1169:"Ukrainian_ghe_with_upturn",1168:"Ukrainian_GHE_WITH_UPTURN",1415:"Armenian_ligature_ew",1417:"Armenian_verjaket",1373:"Armenian_but",1418:"Armenian_yentamna",1372:"Armenian_amanak",1371:"Armenian_shesht",1374:"Armenian_paruyk",1329:"Armenian_AYB",1377:"Armenian_ayb",1330:"Armenian_BEN",1378:"Armenian_ben",1331:"Armenian_GIM",1379:"Armenian_gim",1332:"Armenian_DA",1380:"Armenian_da",1333:"Armenian_YECH",1381:"Armenian_yech",1334:"Armenian_ZA",1382:"Armenian_za",1335:"Armenian_E",1383:"Armenian_e",1336:"Armenian_AT",1384:"Armenian_at",1337:"Armenian_TO",1385:"Armenian_to",1338:"Armenian_ZHE",1386:"Armenian_zhe",1339:"Armenian_INI",1387:"Armenian_ini",1340:"Armenian_LYUN",1388:"Armenian_lyun",1341:"Armenian_KHE",1389:"Armenian_khe",1342:"Armenian_TSA",1390:"Armenian_tsa",1343:"Armenian_KEN",1391:"Armenian_ken",1344:"Armenian_HO",1392:"Armenian_ho",1345:"Armenian_DZA",1393:"Armenian_dza",1346:"Armenian_GHAT",1394:"Armenian_ghat",1347:"Armenian_TCHE",1395:"Armenian_tche",1348:"Armenian_MEN",1396:"Armenian_men",1349:"Armenian_HI",1397:"Armenian_hi",1350:"Armenian_NU",1398:"Armenian_nu",1351:"Armenian_SHA",1399:"Armenian_sha",1352:"Armenian_VO",1400:"Armenian_vo",1353:"Armenian_CHA",1401:"Armenian_cha",1354:"Armenian_PE",1402:"Armenian_pe",1355:"Armenian_JE",1403:"Armenian_je",1356:"Armenian_RA",1404:"Armenian_ra",1357:"Armenian_SE",1405:"Armenian_se",1358:"Armenian_VEV",1406:"Armenian_vev",1359:"Armenian_TYUN",1407:"Armenian_tyun",1360:"Armenian_RE",1408:"Armenian_re",1361:"Armenian_TSO",1409:"Armenian_tso",1362:"Armenian_VYUN",1410:"Armenian_vyun",1363:"Armenian_PYUR",1411:"Armenian_pyur",1364:"Armenian_KE",1412:"Armenian_ke",1365:"Armenian_O",1413:"Armenian_o",1366:"Armenian_FE",1414:"Armenian_fe",1370:"Armenian_apostrophe",4304:"Georgian_an",4305:"Georgian_ban",4306:"Georgian_gan",4307:"Georgian_don",4308:"Georgian_en",4309:"Georgian_vin",4310:"Georgian_zen",4311:"Georgian_tan",4312:"Georgian_in",4313:"Georgian_kan",4314:"Georgian_las",4315:"Georgian_man",4316:"Georgian_nar",4317:"Georgian_on",4318:"Georgian_par",4319:"Georgian_zhar",4320:"Georgian_rae",4321:"Georgian_san",4322:"Georgian_tar",4323:"Georgian_un",4324:"Georgian_phar",4325:"Georgian_khar",4326:"Georgian_ghan",4327:"Georgian_qar",4328:"Georgian_shin",4329:"Georgian_chin",4330:"Georgian_can",4331:"Georgian_jil",4332:"Georgian_cil",4333:"Georgian_char",4334:"Georgian_xan",4335:"Georgian_jhan",4336:"Georgian_hae",4337:"Georgian_he",4338:"Georgian_hie",4339:"Georgian_we",4340:"Georgian_har",4341:"Georgian_hoe",4342:"Georgian_fi",7682:"Babovedot",7683:"babovedot",7690:"Dabovedot",7808:"Wgrave",7810:"Wacute",7691:"dabovedot",7922:"Ygrave",7710:"Fabovedot",7711:"fabovedot",7744:"Mabovedot",7745:"mabovedot",7766:"Pabovedot",7809:"wgrave",7767:"pabovedot",7811:"wacute",7776:"Sabovedot",7923:"ygrave",7812:"Wdiaeresis",7813:"wdiaeresis",7777:"sabovedot",372:"Wcircumflex",7786:"Tabovedot",374:"Ycircumflex",373:"wcircumflex",7787:"tabovedot",375:"ycircumflex",1776:"Farsi_0",1777:"Farsi_1",1778:"Farsi_2",1779:"Farsi_3",1780:"Farsi_4",1781:"Farsi_5",1782:"Farsi_6",1783:"Farsi_7",1784:"Farsi_8",1785:"Farsi_9",1642:"Arabic_percent",1648:"Arabic_superscript_alef",1657:"Arabic_tteh",1662:"Arabic_peh",1670:"Arabic_tcheh",1672:"Arabic_ddal",1681:"Arabic_rreh",1748:"Arabic_fullstop",1632:"Arabic_0",1633:"Arabic_1",1634:"Arabic_2",1635:"Arabic_3",1636:"Arabic_4",1637:"Arabic_5",1638:"Arabic_6",1639:"Arabic_7",1640:"Arabic_8",1641:"Arabic_9",1619:"Arabic_madda_above",1620:"Arabic_hamza_above",1621:"Arabic_hamza_below",1688:"Arabic_jeh",1700:"Arabic_veh",1705:"Arabic_keheh",1711:"Arabic_gaf",1722:"Arabic_noon_ghunna",1726:"Arabic_heh_doachashmee",1740:"Farsi_yeh",1746:"Arabic_yeh_baree",1729:"Arabic_heh_goal",1170:"Cyrillic_GHE_bar",1174:"Cyrillic_ZHE_descender",1178:"Cyrillic_KA_descender",1180:"Cyrillic_KA_vertstroke",1186:"Cyrillic_EN_descender",1198:"Cyrillic_U_straight",1200:"Cyrillic_U_straight_bar",1202:"Cyrillic_HA_descender",1206:"Cyrillic_CHE_descender",1208:"Cyrillic_CHE_vertstroke",1210:"Cyrillic_SHHA",1240:"Cyrillic_SCHWA",1250:"Cyrillic_I_macron",1256:"Cyrillic_O_bar",1262:"Cyrillic_U_macron",1171:"Cyrillic_ghe_bar",1175:"Cyrillic_zhe_descender",1179:"Cyrillic_ka_descender",1181:"Cyrillic_ka_vertstroke",1187:"Cyrillic_en_descender",1199:"Cyrillic_u_straight",1201:"Cyrillic_u_straight_bar",1203:"Cyrillic_ha_descender",1207:"Cyrillic_che_descender",1209:"Cyrillic_che_vertstroke",1211:"Cyrillic_shha",1241:"Cyrillic_schwa",1251:"Cyrillic_i_macron",1257:"Cyrillic_o_bar",1263:"Cyrillic_u_macron",7818:"Xabovedot",300:"Ibreve",437:"Zstroke",486:"Gcaron",415:"Obarred",7819:"xabovedot",301:"ibreve",438:"zstroke",487:"gcaron",466:"ocaron",629:"obarred",399:"SCHWA",601:"schwa",7734:"Lbelowdot",7735:"lbelowdot",7840:"Abelowdot",7841:"abelowdot",7842:"Ahook",7843:"ahook",7844:"Acircumflexacute",7845:"acircumflexacute",7846:"Acircumflexgrave",7847:"acircumflexgrave",7848:"Acircumflexhook",7849:"acircumflexhook",7850:"Acircumflextilde",7851:"acircumflextilde",7852:"Acircumflexbelowdot",7853:"acircumflexbelowdot",7854:"Abreveacute",7855:"abreveacute",7856:"Abrevegrave",7857:"abrevegrave",7858:"Abrevehook",7859:"abrevehook",7860:"Abrevetilde",7861:"abrevetilde",7862:"Abrevebelowdot",7863:"abrevebelowdot",7864:"Ebelowdot",7865:"ebelowdot",7866:"Ehook",7867:"ehook",7868:"Etilde",7869:"etilde",7870:"Ecircumflexacute",7871:"ecircumflexacute",7872:"Ecircumflexgrave",7873:"ecircumflexgrave",7874:"Ecircumflexhook",7875:"ecircumflexhook",7876:"Ecircumflextilde",7877:"ecircumflextilde",7878:"Ecircumflexbelowdot",7879:"ecircumflexbelowdot",7880:"Ihook",7881:"ihook",7882:"Ibelowdot",7883:"ibelowdot",7884:"Obelowdot",7885:"obelowdot",7886:"Ohook",7887:"ohook",7888:"Ocircumflexacute",7889:"ocircumflexacute",7890:"Ocircumflexgrave",7891:"ocircumflexgrave",7892:"Ocircumflexhook",7893:"ocircumflexhook",7894:"Ocircumflextilde",7895:"ocircumflextilde",7896:"Ocircumflexbelowdot",7897:"ocircumflexbelowdot",7898:"Ohornacute",7899:"ohornacute",7900:"Ohorngrave",7901:"ohorngrave",7902:"Ohornhook",7903:"ohornhook",7904:"Ohorntilde",7905:"ohorntilde",7906:"Ohornbelowdot",7907:"ohornbelowdot",7908:"Ubelowdot",7909:"ubelowdot",7910:"Uhook",7911:"uhook",7912:"Uhornacute",7913:"uhornacute",7914:"Uhorngrave",7915:"uhorngrave",7916:"Uhornhook",7917:"uhornhook",7918:"Uhorntilde",7919:"uhorntilde",7920:"Uhornbelowdot",7921:"uhornbelowdot",7924:"Ybelowdot",7925:"ybelowdot",7926:"Yhook",7927:"yhook",7928:"Ytilde",7929:"ytilde",416:"Ohorn",417:"ohorn",431:"Uhorn",432:"uhorn",803:"dead_belowdot",777:"dead_hook",795:"dead_horn"}),pe=Object.freeze({AltLeft:"Alt_L",AltRight:"Alt_R",ArrowDown:"Down",ArrowLeft:"Left",ArrowRight:"Right",ArrowUp:"Up",Backspace:"BackSpace",CapsLock:"Caps_Lock",ControlLeft:"Control_L",ControlRight:"Control_R",Enter:"Return",HyperLeft:"Hyper_L",HyperRight:"Hyper_R",NumLock:"Num_Lock",NumpadEnter:"Return",MetaLeft:"Meta_L",MetaRight:"Meta_R",PageDown:"Page_Down",PageUp:"Page_Up",ScrollLock:"Scroll_Lock",ShiftLeft:"Shift_L",ShiftRight:"Shift_R",SuperLeft:"Super_L",SuperRight:"Super_R"}),ue=new Set(["Clear","Copy","Cut","Delete","End","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","Home","Insert","Paste","Redo","Tab","Undo"]);function me(e,t){var n="Unidentified";if(1===e.length){const t=e.charCodeAt(0);t in he&&(n=he[t])}else t in pe?n=pe[t]:ue.has(t)&&(n=t);return n}const _e=Object.freeze(["wheel","contextmenu","mousemove","mousedown","mouseup","touchstart","touchend","touchmove","touchcancel","keyup","keydown"]),fe=Object.freeze({mousemove:"MouseMove",mousedown:"MouseButtonPress",mouseup:"MouseButtonRelease"}),ge=Object.freeze({touchstart:"TouchDown",touchend:"TouchUp",touchmove:"TouchMotion",touchcancel:"TouchUp"}),Ce=Object.freeze({keydown:"KeyPress",keyup:"KeyRelease"});function ye(e){const t=[];return e.altKey&&t.push("mod1-mask"),e.ctrlKey&&t.push("control-mask"),e.metaKey&&t.push("meta-mask"),e.shiftKey&&t.push("shift-mask"),t.join("+")}class ve extends EventTarget{constructor(e,t){super(),this._rtcDataChannel=e,this._consumerSession=t,this._videoElement=null,this._videoElementComputedStyle=null,this._videoElementKeyboard=null,this._lastTouchEventTimestamp=0,this._requestCounter=0,e.addEventListener("close",(()=>{this._rtcDataChannel===e&&this.close()})),e.addEventListener("error",(t=>{if(this._rtcDataChannel===e){const e=t.error;this.dispatchEvent(new ErrorEvent("error",{message:e&&e.message||"Remote controller error",error:e||new Error("unknown error on the remote controller data channel")}))}})),e.addEventListener("message",(e=>{try{const t=JSON.parse(e.data);"ControlResponseMessage"===t.type?this.dispatchEvent(new CustomEvent("controlResponse",{detail:t})):"InfoMessage"===t.type&&this.dispatchEvent(new CustomEvent("info",{detail:t}))}catch(e){this.dispatchEvent(new ErrorEvent("error",{message:"cannot parse control message from signaling server",error:e}))}}))}get rtcDataChannel(){return this._rtcDataChannel}get consumerSession(){return this._consumerSession}get videoElement(){return this._videoElement}attachVideoElement(e){if(e instanceof HTMLVideoElement&&e!==this._videoElement){this._videoElement&&this.attachVideoElement(null),this._videoElement=e,this._videoElementComputedStyle=window.getComputedStyle(e);for(const t of _e)e.addEventListener(t,this);e.setAttribute("tabindex","0")}else if(null===e&&this._videoElement){const e=this._videoElement;e.removeAttribute("tabindex"),this._videoElement=null,this._videoElementComputedStyle=null,this._lastTouchEventTimestamp=0;for(const t of _e)e.removeEventListener(t,this)}}sendControlRequest(e){try{if(!e||"object"!=typeof e&&"string"!=typeof e)throw new Error("invalid request");if(!this._rtcDataChannel)throw new Error("remote controller data channel is closed");let t={id:this._requestCounter++,request:e};return this._rtcDataChannel.send(JSON.stringify(t)),t.id}catch(e){return this.dispatchEvent(new ErrorEvent("error",{message:`cannot send control message over session ${this._consumerSession.sessionId} remote controller`,error:e})),-1}}close(){this.attachVideoElement(null);const e=this._rtcDataChannel;this._rtcDataChannel=null,e&&(e.close(),this.dispatchEvent(new Event("closed")))}_sendGstNavigationEvent(e){let t={type:"navigationEvent",event:e};this.sendControlRequest(t)}_computeVideoMousePosition(e){const t={x:0,y:0};if(!this._videoElement||this._videoElement.videoWidth<=0||this._videoElement.videoHeight<=0)return t;const n=parseFloat(this._videoElementComputedStyle.paddingLeft),r=parseFloat(this._videoElementComputedStyle.paddingRight),i=parseFloat(this._videoElementComputedStyle.paddingTop),o=parseFloat(this._videoElementComputedStyle.paddingBottom);if("offsetX"in e&&"offsetY"in e)t.x=e.offsetX-n,t.y=e.offsetY-i;else{const r=this._videoElement.getBoundingClientRect(),o={left:parseFloat(this._videoElementComputedStyle.borderLeftWidth),top:parseFloat(this._videoElementComputedStyle.borderTopWidth)};t.x=e.clientX-r.left-o.left-n,t.y=e.clientY-r.top-o.top-i}const s={x:this._videoElement.clientWidth-(n+r),y:this._videoElement.clientHeight-(i+o)},a=Math.min(s.x/this._videoElement.videoWidth,s.y/this._videoElement.videoHeight);s.x=Math.max(.5*(s.x-this._videoElement.videoWidth*a),0),s.y=Math.max(.5*(s.y-this._videoElement.videoHeight*a),0);const c=0!==a?1/a:0;return t.x=(t.x-s.x)*c,t.y=(t.y-s.y)*c,t.x=Math.min(Math.max(t.x,0),this._videoElement.videoWidth),t.y=Math.min(Math.max(t.y,0),this._videoElement.videoHeight),t}handleEvent(e){if(this._videoElement)switch(e.type){case"wheel":e.preventDefault();{const t=this._computeVideoMousePosition(e);this._sendGstNavigationEvent({event:"MouseScroll",x:t.x,y:t.y,delta_x:-e.deltaX,delta_y:-e.deltaY,modifier_state:ye(e)})}break;case"contextmenu":e.preventDefault();break;case"mousemove":case"mousedown":case"mouseup":e.preventDefault();{const t=this._computeVideoMousePosition(e),n={event:fe[e.type],x:t.x,y:t.y,modifier_state:ye(e)};"mousemove"!==e.type&&(n.button=e.button+1,"mousedown"===e.type&&0===e.button&&this._videoElement.focus()),this._sendGstNavigationEvent(n)}break;case"touchstart":case"touchend":case"touchmove":case"touchcancel":for(const t of e.changedTouches){const n=this._computeVideoMousePosition(t),r={event:ge[e.type],identifier:t.identifier,x:n.x,y:n.y,modifier_state:ye(e)};!("force"in t)||"touchstart"!==e.type&&"touchmove"!==e.type||(r.pressure=t.force),this._sendGstNavigationEvent(r)}e.timeStamp>this._lastTouchEventTimestamp&&(this._lastTouchEventTimestamp=e.timeStamp,this._sendGstNavigationEvent({event:"TouchFrame",modifier_state:ye(e)}));break;case"keyup":case"keydown":e.preventDefault();{const t={event:Ce[e.type],key:me(e.key,e.code),modifier_state:ye(e)};this._sendGstNavigationEvent(t)}}}}const be=ve;const Se=class extends le{constructor(e,t,n){super(e,t),this._streams=[],this._remoteController=null,this._pendingCandidates=[],this._mungeStereoHack=!1,this._offerOptions=n,this.addEventListener("closed",(()=>{this._streams=[],this._pendingCandidates=[],this._remoteController&&this._remoteController.close()}))}set mungeStereoHack(e){"boolean"==typeof e&&(this._mungeStereoHack=e)}get streams(){return this._streams}get remoteController(){return this._remoteController}connect(){if(!this._comChannel||this._state===ce.closed)return!1;if(this._state!==ce.idle)return!0;if(this._offerOptions)this.ensurePeerConnection(),this._rtcPeerConnection.createDataChannel("control"),this._rtcPeerConnection.createOffer(this._offerOptions).then((e=>{if(this._rtcPeerConnection&&e)return this._rtcPeerConnection.setLocalDescription(e);throw new Error("cannot send local offer to WebRTC peer")})).then((()=>{if(this._rtcPeerConnection&&this._comChannel){const e={type:"startSession",peerId:this._peerId,offer:this._rtcPeerConnection.localDescription.toJSON().sdp};if(!this._comChannel.send(e))throw new Error("cannot send startSession message to signaling server");this._state=ce.connecting,this.dispatchEvent(new Event("stateChanged"))}})).catch((e=>{this._state!==ce.closed&&(this.dispatchEvent(new ErrorEvent("error",{message:"an unrecoverable error occurred during SDP handshake",error:e})),this.close())}));else{const e={type:"startSession",peerId:this._peerId};if(!this._comChannel.send(e))return this.dispatchEvent(new ErrorEvent("error",{message:"cannot connect consumer session",error:new Error("cannot send startSession message to signaling server")})),this.close(),!1;this._state=ce.connecting,this.dispatchEvent(new Event("stateChanged"))}return!0}onSessionStarted(e,t){if(this._peerId===e&&this._state===ce.connecting&&!this._sessionId){console.log("Session started",this._sessionId),this._sessionId=t;for(const e of this._pendingCandidates)console.log("Sending delayed ICE with session id",this._sessionId),this._comChannel.send({type:"peer",sessionId:this._sessionId,ice:e.toJSON()});this._pendingCandidates=[]}}ensurePeerConnection(){if(!this._rtcPeerConnection){const e=new RTCPeerConnection(this._comChannel.webrtcConfig);this._rtcPeerConnection=e,e.ontrack=t=>{if(this._rtcPeerConnection===e&&t.streams&&t.streams.length>0){this._state===ce.connecting&&(this._state=ce.streaming,this.dispatchEvent(new Event("stateChanged")));let e=!1;for(const n of t.streams)this._streams.includes(n)||(this._streams.push(n),e=!0);e&&this.dispatchEvent(new Event("streamsChanged"))}},e.ondatachannel=e=>{const t=e.channel;if(t&&"control"===t.label){if(this._remoteController){const e=this._remoteController;this._remoteController=null,e.close()}const e=new be(t,this);this._remoteController=e,this.dispatchEvent(new Event("remoteControllerChanged")),e.addEventListener("closed",(()=>{this._remoteController===e&&(this._remoteController=null,this.dispatchEvent(new Event("remoteControllerChanged")))}))}},e.onicecandidate=t=>{this._rtcPeerConnection===e&&t.candidate&&this._comChannel&&(this._sessionId?(console.log("Sending ICE with session id",this._sessionId),this._comChannel.send({type:"peer",sessionId:this._sessionId,ice:t.candidate.toJSON()})):this._pendingCandidates.push(t.candidate))},this.dispatchEvent(new Event("rtcPeerConnectionChanged"))}}mungeStereo(e,t){const n=/a=fmtp:.* sprop-stereo/g;let r=new Set;for(const t of e.matchAll(n)){const e=t[0].match(/a=fmtp:(\d+) .*/);e&&r.add(e[1])}for(const e of r){const n=new RegExp("a=fmtp:"+e+".*stereo");t.match(n)||(t=t.replaceAll("a=fmtp:"+e,"a=fmtp:"+e+" stereo=1;"))}return t}onSessionPeerMessage(e){if(this._state!==ce.closed&&this._comChannel&&this._sessionId)if(this.ensurePeerConnection(),e.sdp)this._offerOptions?this._rtcPeerConnection.setRemoteDescription(e.sdp).then((()=>{console.log("done")})).catch((e=>{this._state!==ce.closed&&(this.dispatchEvent(new ErrorEvent("error",{message:"an unrecoverable error occurred during SDP handshake",error:e})),this.close())})):this._rtcPeerConnection.setRemoteDescription(e.sdp).then((()=>this._rtcPeerConnection?this._rtcPeerConnection.createAnswer():null)).then((t=>this._rtcPeerConnection&&t?(this._mungeStereoHack&&(t.sdp=this.mungeStereo(e.sdp.sdp,t.sdp)),this._rtcPeerConnection.setLocalDescription(t)):null)).then((()=>{if(this._rtcPeerConnection&&this._comChannel){console.log("Sending SDP with session id",this._sessionId);const e={type:"peer",sessionId:this._sessionId,sdp:this._rtcPeerConnection.localDescription.toJSON()};if(!this._comChannel.send(e))throw new Error("cannot send local SDP configuration to WebRTC peer")}})).catch((e=>{this._state!==ce.closed&&(this.dispatchEvent(new ErrorEvent("error",{message:"an unrecoverable error occurred during SDP handshake",error:e})),this.close())}));else{if(!e.ice)throw new Error(`invalid empty peer message received from consumer session ${this._sessionId}`);{const t=new RTCIceCandidate(e.ice);this._rtcPeerConnection.addIceCandidate(t).catch((e=>{this._state!==ce.closed&&(this.dispatchEvent(new ErrorEvent("error",{message:"an unrecoverable error occurred during ICE handshake",error:e})),this.close())}))}}}};class ke extends le{constructor(e,t,n,r){super(e,n),this._sessionId=t,this._state=ce.streaming;const i=new RTCPeerConnection(this._comChannel.webrtcConfig);this._rtcPeerConnection=i;for(const e of r.getTracks())i.addTrack(e,r);i.onicecandidate=e=>{this._rtcPeerConnection===i&&e.candidate&&this._comChannel&&this._comChannel.send({type:"peer",sessionId:this._sessionId,ice:e.candidate.toJSON()})},this.dispatchEvent(new Event("rtcPeerConnectionChanged")),i.setLocalDescription().then((()=>{if(this._rtcPeerConnection===i&&this._comChannel){const e={type:"peer",sessionId:this._sessionId,sdp:this._rtcPeerConnection.localDescription.toJSON()};if(!this._comChannel.send(e))throw new Error("cannot send local SDP configuration to WebRTC peer")}})).catch((e=>{this._state!==ce.closed&&(this.dispatchEvent(new ErrorEvent("error",{message:"an unrecoverable error occurred during SDP handshake",error:e})),this.close())}))}onSessionPeerMessage(e){if(this._state!==ce.closed&&this._rtcPeerConnection)if(e.sdp)this._rtcPeerConnection.setRemoteDescription(e.sdp).catch((e=>{this._state!==ce.closed&&(this.dispatchEvent(new ErrorEvent("error",{message:"an unrecoverable error occurred during SDP handshake",error:e})),this.close())}));else{if(!e.ice)throw new Error(`invalid empty peer message received from producer's client session ${this._peerId}`);{const t=new RTCIceCandidate(e.ice);this._rtcPeerConnection.addIceCandidate(t).catch((e=>{this._state!==ce.closed&&(this.dispatchEvent(new ErrorEvent("error",{message:"an unrecoverable error occurred during ICE handshake",error:e})),this.close())}))}}}}class Te extends EventTarget{constructor(e,t){super(),this._comChannel=e,this._stream=t,this._state=ce.idle,this._clientSessions={}}get stream(){return this._stream}get state(){return this._state}start(){if(!this._comChannel||this._state===ce.closed)return!1;if(this._state!==ce.idle)return!0;const e={type:"setPeerStatus",roles:["listener","producer"],meta:this._comChannel.meta};return this._comChannel.send(e)?(this._state=ce.connecting,this.dispatchEvent(new Event("stateChanged")),!0):(this.dispatchEvent(new ErrorEvent("error",{message:"cannot start producer session",error:new Error("cannot register producer to signaling server")})),this.close(),!1)}close(){if(this._state!==ce.closed){for(const e of this._stream.getTracks())e.stop();this._state!==ce.idle&&this._comChannel&&this._comChannel.send({type:"setPeerStatus",roles:["listener"],meta:this._comChannel.meta}),this._state=ce.closed,this.dispatchEvent(new Event("stateChanged")),this._comChannel=null,this._stream=null;for(const e of Object.values(this._clientSessions))e.close();this._clientSessions={},this.dispatchEvent(new Event("closed"))}}onProducerRegistered(){this._state===ce.connecting&&(this._state=ce.streaming,this.dispatchEvent(new Event("stateChanged")))}onStartSessionMessage(e){if(this._comChannel&&this._stream&&!(e.sessionId in this._clientSessions)){const t=new ke(e.peerId,e.sessionId,this._comChannel,this._stream);this._clientSessions[e.sessionId]=t,t.addEventListener("closed",(e=>{const n=e.target.sessionId;n in this._clientSessions&&this._clientSessions[n]===t&&(delete this._clientSessions[n],this.dispatchEvent(new CustomEvent("clientConsumerRemoved",{detail:t})))})),t.addEventListener("error",(e=>{this.dispatchEvent(new ErrorEvent("error",{message:`error from client consumer ${e.target.peerId}: ${e.message}`,error:e.error}))})),this.dispatchEvent(new CustomEvent("clientConsumerAdded",{detail:t}))}}onEndSessionMessage(e){e.sessionId in this._clientSessions&&this._clientSessions[e.sessionId].close()}onSessionPeerMessage(e){e.sessionId in this._clientSessions&&this._clientSessions[e.sessionId].onSessionPeerMessage(e)}}const Ee=Te,Pe=Object.freeze({welcome:"welcome",peerStatusChanged:"peerStatusChanged",list:"list",sessionStarted:"sessionStarted",peer:"peer",startSession:"startSession",endSession:"endSession",error:"error"});function Re(e,t){if(!e||"object"!=typeof e)return null;const n={id:"",meta:{}};if(e.id&&"string"==typeof e.id)n.id=e.id;else{if(!e.peerId||"string"!=typeof e.peerId)return null;n.id=e.peerId}return n.id===t?null:(e.meta&&"object"==typeof e.meta&&(n.meta=e.meta),Object.freeze(n.meta),Object.freeze(n))}class we extends EventTarget{constructor(e,t,n){super(),this._meta=t,this._webrtcConfig=n,this._ws=new WebSocket(e),this._ready=!1,this._channelId="",this._producerSession=null,this._consumerSessions={},this._ws.onerror=e=>{this.dispatchEvent(new ErrorEvent("error",{message:e.message||"WebSocket error",error:e.error||new Error(this._ready?"transportation error":"cannot connect to signaling server")})),this.close()},this._ws.onclose=()=>{this._ready=!1,this._channelId="",this._ws=null,this.closeAllConsumerSessions(),this._producerSession&&(this._producerSession.close(),this._producerSession=null),this.dispatchEvent(new Event("closed"))},this._ws.onmessage=e=>{try{const n=JSON.parse(e.data);if(n&&"object"==typeof n)switch(n.type){case Pe.welcome:this._channelId=n.peerId;try{this._ws.send(JSON.stringify({type:"setPeerStatus",roles:["listener"],meta:t}))}catch(e){this.dispatchEvent(new ErrorEvent("error",{message:"cannot initialize connection to signaling server",error:e})),this.close()}break;case Pe.peerStatusChanged:if(n.peerId===this._channelId)!this._ready&&n.roles.includes("listener")&&(this._ready=!0,this.dispatchEvent(new Event("ready")),this.send({type:"list"})),this._producerSession&&n.roles.includes("producer")&&this._producerSession.onProducerRegistered();else{const e=Re(n,this._channelId);e&&(n.roles.includes("producer")?this.dispatchEvent(new CustomEvent("producerAdded",{detail:e})):this.dispatchEvent(new CustomEvent("producerRemoved",{detail:e})))}break;case Pe.list:for(const e of n.producers){const t=Re(e,this._channelId);t&&this.dispatchEvent(new CustomEvent("producerAdded",{detail:t}))}break;case Pe.sessionStarted:{const e=this.getConsumerSession(n.peerId);e&&(delete this._consumerSessions[n.peerId],e.onSessionStarted(n.peerId,n.sessionId),e.sessionId&&!(e.sessionId in this._consumerSessions)?this._consumerSessions[e.sessionId]=e:e.close())}break;case Pe.peer:{const e=this.getConsumerSession(n.sessionId);e?e.onSessionPeerMessage(n):this._producerSession&&this._producerSession.onSessionPeerMessage(n)}break;case Pe.startSession:this._producerSession&&this._producerSession.onStartSessionMessage(n);break;case Pe.endSession:{const e=this.getConsumerSession(n.sessionId);e?e.close():this._producerSession&&this._producerSession.onEndSessionMessage(n)}break;case Pe.error:this.dispatchEvent(new ErrorEvent("error",{message:"error received from signaling server",error:new Error(n.details)}));break;default:throw new Error(`unknown message type: "${n.type}"`)}}catch(e){this.dispatchEvent(new ErrorEvent("error",{message:"cannot parse incoming message from signaling server",error:e}))}}}get meta(){return this._meta}get webrtcConfig(){return this._webrtcConfig}get ready(){return this._ready}get channelId(){return this._channelId}get producerSession(){return this._producerSession}createProducerSession(e){if(!(this._ready&&e instanceof MediaStream))return null;if(this._producerSession)return this._producerSession.stream===e?this._producerSession:null;const t=new Ee(this,e);return this._producerSession=t,t.addEventListener("closed",(()=>{this._producerSession===t&&(this._producerSession=null)})),t}createConsumerSession(e,t){if(!this._ready||!e||"string"!=typeof e)return null;if(t&&"object"!=typeof t&&(t=void 0),e in this._consumerSessions)return this._consumerSessions[e];for(const t of Object.values(this._consumerSessions))if(t.peerId===e)return t;const n=new Se(e,this,t);return this._consumerSessions[e]=n,n.addEventListener("closed",(e=>{let t=e.target.sessionId;t||(t=e.target.peerId),t in this._consumerSessions&&this._consumerSessions[t]===n&&delete this._consumerSessions[t]})),n}getConsumerSession(e){return e in this._consumerSessions?this._consumerSessions[e]:null}closeAllConsumerSessions(){for(const e of Object.values(this._consumerSessions))e.close();this._consumerSessions={}}send(e){if(this._ready&&e&&"object"==typeof e)try{return this._ws.send(JSON.stringify(e)),!0}catch(e){this.dispatchEvent(new ErrorEvent("error",{message:"cannot send message to signaling server",error:e}))}return!1}close(){this._ws&&(this._ready=!1,this._channelId="",this._ws.close(),this.closeAllConsumerSessions(),this._producerSession&&(this._producerSession.close(),this._producerSession=null))}}const Ae=we;class xe{constructor(e){this._channel=null,this._producers={},this._connectionListeners=[],this._producersListeners=[];const t=Object.assign({},se);e&&"object"==typeof e&&Object.assign(t,e),"object"!=typeof t.meta&&(t.meta=null),this._config=t,this.connectChannel()}registerConnectionListener(e){return!(!e||"object"!=typeof e||"function"!=typeof e.connected||"function"!=typeof e.disconnected)&&(this._connectionListeners.includes(e)||this._connectionListeners.push(e),!0)}unregisterConnectionListener(e){const t=this._connectionListeners.indexOf(e);return t>=0&&(this._connectionListeners.splice(t,1),!0)}unregisterAllConnectionListeners(){this._connectionListeners=[]}createProducerSession(e){return this._channel?this._channel.createProducerSession(e):null}getAvailableProducers(){return Object.values(this._producers)}registerProducersListener(e){return!(!e||"object"!=typeof e||"function"!=typeof e.producerAdded||"function"!=typeof e.producerRemoved)&&(this._producersListeners.includes(e)||this._producersListeners.push(e),!0)}unregisterProducersListener(e){const t=this._producersListeners.indexOf(e);return t>=0&&(this._producersListeners.splice(t,1),!0)}unregisterAllProducersListeners(){this._producersListeners=[]}createConsumerSession(e){return this._channel?this._channel.createConsumerSession(e):null}createConsumerSessionWithOfferOptions(e,t){return this._channel?this._channel.createConsumerSession(e,t):null}connectChannel(){if(this._channel){const e=this._channel;this._channel=null,e.close();for(const e in this._producers)this.triggerProducerRemoved(e);this._producers={},this.triggerDisconnected()}this._channel=new Ae(this._config.signalingServerUrl,this._config.meta,this._config.webrtcConfig),this._channel.addEventListener("error",(e=>{e.target===this._channel&&console.error(e.message,e.error)})),this._channel.addEventListener("closed",(e=>{if(e.target===this._channel){this._channel=null;for(const e in this._producers)this.triggerProducerRemoved(e);this._producers={},this.triggerDisconnected(),this._config.reconnectionTimeout>0&&window.setTimeout((()=>{this.connectChannel()}),this._config.reconnectionTimeout)}})),this._channel.addEventListener("ready",(e=>{e.target===this._channel&&this.triggerConnected(this._channel.channelId)})),this._channel.addEventListener("producerAdded",(e=>{e.target===this._channel&&this.triggerProducerAdded(e.detail)})),this._channel.addEventListener("producerRemoved",(e=>{e.target===this._channel&&this.triggerProducerRemoved(e.detail.id)}))}triggerConnected(e){for(const t of this._connectionListeners)try{t.connected(e)}catch(e){console.error("a listener callback should not throw any exception",e)}}triggerDisconnected(){for(const e of this._connectionListeners)try{e.disconnected()}catch(e){console.error("a listener callback should not throw any exception",e)}}triggerProducerAdded(e){if(!(e.id in this._producers)){this._producers[e.id]=e;for(const t of this._producersListeners)try{t.producerAdded(e)}catch(e){console.error("a listener callback should not throw any exception",e)}}}triggerProducerRemoved(e){if(e in this._producers){const t=this._producers[e];delete this._producers[e];for(const e of this._producersListeners)try{e.producerRemoved(t)}catch(e){console.error("a listener callback should not throw any exception",e)}}}}xe.SessionState=ce;const Ie=xe;window.GstWebRTCAPI||(window.GstWebRTCAPI=Ie)})()})(); +//# sourceMappingURL=gstwebrtc-api-2.0.0.min.js.map \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/apps.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/apps.js new file mode 100644 index 0000000000000000000000000000000000000000..cd60df2852df2fca161c2c7a047e130df7810059 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/apps.js @@ -0,0 +1,319 @@ +const installedApps = { + refreshAppList: async () => { + const appsData = await installedApps.fetchInstalledApps(); + await installedApps.displayInstalledApps(appsData); + }, + + currentlyRunningApp: null, + busy: false, + toggles: {}, + + startApp: async (appName) => { + if (installedApps.busy) { + console.log(`Another app is currently being started or stopped.`); + return; + } + installedApps.setBusy(true); + + console.log(`Current running app: ${installedApps.currentlyRunningApp}`); + + if (installedApps.currentlyRunningApp) { + console.log(`Stopping currently running app: ${installedApps.currentlyRunningApp}...`); + await installedApps.stopApp(installedApps.currentlyRunningApp, true); + } + + console.log(`Starting app: ${appName}...`); + const endpoint = `/api/apps/start-app/${appName}`; + const resp = await fetch(endpoint, { method: 'POST' }); + if (!resp.ok) { + console.error(`Failed to staret app ${appName}: ${resp.statusText}`); + installedApps.toggles[appName].setChecked(false); + installedApps.setBusy(false); + return; + } else { + console.log(`App ${appName} started successfully.`); + } + + installedApps.currentlyRunningApp = appName; + installedApps.setBusy(false); + }, + + stopApp: async (appName, force = false) => { + if (installedApps.busy && !force) { + console.log(`Another app is currently being started or stopped.`); + return; + } + installedApps.setBusy(true); + + console.log(`Stopping app: ${appName}...`); + + if (force) { + console.log(`Force stopping app: ${appName}...`); + installedApps.toggles[appName].setChecked(false); + } + + const endpoint = `/api/apps/stop-current-app`; + const resp = await fetch(endpoint, { method: 'POST' }); + if (!resp.ok) { + console.error(`Failed to stop app ${appName}: ${resp.statusText}`); + installedApps.setBusy(false); + return; + } else { + console.log(`App ${appName} stopped successfully.`); + installedApps.toggles[appName].setChecked(false); + } + + if (installedApps.currentlyRunningApp === appName) { + installedApps.currentlyRunningApp = null; + } + installedApps.setBusy(false); + }, + + setBusy: (isBusy) => { + installedApps.busy = isBusy; + for (const toggle of Object.values(installedApps.toggles)) { + if (isBusy) { + toggle.disable(); + } else { + toggle.enable(); + } + } + }, + + fetchInstalledApps: async () => { + const resp = await fetch('/api/apps/list-available/installed'); + const appsData = await resp.json(); + return appsData; + }, + + displayInstalledApps: async (appsData) => { + const appsListElement = document.getElementById('installed-apps'); + appsListElement.innerHTML = ''; + + if (!appsData || appsData.length === 0) { + appsListElement.innerHTML = '
  • No installed apps found.
  • '; + return; + } + + const runningApp = await installedApps.getRunningApp(); + + installedApps.toggles = {}; + appsData.forEach(app => { + const li = document.createElement('li'); + li.className = 'app-list-item'; + const isRunning = (app.name === runningApp); + li.appendChild(installedApps.createAppElement(app, isRunning)); + appsListElement.appendChild(li); + }); + }, + + createAppElement: (app, isRunning) => { + const container = document.createElement('div'); + container.className = 'grid grid-cols-[auto_6rem_2rem] justify-stretch gap-x-2'; + + const title = document.createElement('div'); + const titleSpan = document.createElement('span'); + titleSpan.className = 'installed-app-title top-1/2 '; + titleSpan.innerHTML = app.name; + title.appendChild(titleSpan); + if (app.extra && app.extra.custom_app_url) { + const settingsLink = document.createElement('a'); + settingsLink.className = 'installed-app-settings ml-2 text-gray-500 cursor-pointer'; + settingsLink.innerHTML = '⚙️'; + settingsLink.href = app.extra.custom_app_url; + settingsLink.target = '_blank'; + settingsLink.rel = 'noopener noreferrer'; + title.appendChild(settingsLink); + } + container.appendChild(title); + const slider = document.createElement('div'); + const toggle = new ToggleSlider({ + checked: isRunning, + onChange: (checked) => { + if (installedApps.busy) { + toggle.setChecked(!checked); + return; + } + if (checked) { + installedApps.startApp(app.name); + } else { + installedApps.stopApp(app.name); + } + } + }); + installedApps.toggles[app.name] = toggle; + slider.appendChild(toggle.element); + container.appendChild(slider); + + const remove = document.createElement('button'); + remove.innerHTML = '🗑️'; + remove.className = '-translate-y-1 text-xl'; + container.appendChild(remove); + remove.onclick = async () => { + console.log(`Removing ${app.name}...`); + const resp = await fetch(`/api/apps/remove/${app.name}`, { method: 'POST' }); + const data = await resp.json(); + const jobId = data.job_id; + + installedApps.appUninstallLogHandler(app.name, jobId); + }; + + return container; + }, + + getRunningApp: async () => { + const resp = await fetch('/api/apps/current-app-status'); + const data = await resp.json(); + if (!data) { + return null; + } + installedApps.currentlyRunningApp = data.info.name; + return data.info.name; + }, + + appUninstallLogHandler: async (appName, jobId) => { + const installModal = document.getElementById('install-modal'); + const modalTitle = installModal.querySelector('#modal-title'); + modalTitle.textContent = `Uninstalling ${appName}...`; + installModal.classList.remove('hidden'); + + const logsDiv = document.getElementById('install-logs'); + logsDiv.textContent = ''; + + const closeButton = document.getElementById('modal-close-button'); + closeButton.onclick = () => { + installModal.classList.add('hidden'); + }; + closeButton.classList = "hidden"; + closeButton.textContent = ''; + + const ws = new WebSocket(`ws://${location.host}/api/apps/ws/apps-manager/${jobId}`); + ws.onmessage = (event) => { + try { + if (event.data.startsWith('{') && event.data.endsWith('}')) { + + const data = JSON.parse(event.data); + + if (data.status === "failed") { + closeButton.classList = "text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800"; + closeButton.textContent = 'Close'; + console.error(`Uninstallation of ${appName} failed.`); + } else if (data.status === "done") { + closeButton.classList = "text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"; + closeButton.textContent = 'Uninstall done'; + console.log(`Uninstallation of ${appName} completed.`); + + } + } else { + logsDiv.innerHTML += event.data + '\n'; + logsDiv.scrollTop = logsDiv.scrollHeight; + } + } catch { + logsDiv.innerHTML += event.data + '\n'; + logsDiv.scrollTop = logsDiv.scrollHeight; + } + }; + ws.onclose = async () => { + hfAppsStore.refreshAppList(); + installedApps.refreshAppList(); + }; + }, +}; + +class ToggleSlider { + constructor({ checked = false, onChange = null } = {}) { + this.label = document.createElement('label'); + this.label.className = 'relative inline-block w-28 h-8 cursor-pointer'; + + this.input = document.createElement('input'); + this.input.type = 'checkbox'; + this.input.className = 'sr-only peer'; + this.input.checked = checked; + this.label.appendChild(this.input); + + // Off label + this.offLabel = document.createElement('span'); + this.offLabel.textContent = 'Off'; + this.offLabel.className = 'absolute left-0 top-1/2 -translate-x-8 -translate-y-1/2 text-base select-none transition-colors duration-200 text-gray-900 peer-checked:text-gray-400'; + this.label.appendChild(this.offLabel); + + this.track = document.createElement('div'); + this.track.className = 'absolute top-0 left-0 w-16 h-8 bg-gray-200 rounded-full transition-colors duration-200 peer-checked:bg-blue-800 dark:bg-gray-400 dark:peer-checked:bg-blue-800'; + this.label.appendChild(this.track); + + this.thumb = document.createElement('div'); + this.thumb.className = 'absolute top-0.5 left-0.5 w-7 h-7 bg-white border border-gray-300 rounded-full transition-all duration-200'; + this.track.appendChild(this.thumb); + + // On label + this.onLabel = document.createElement('span'); + this.onLabel.textContent = 'On'; + this.onLabel.className = 'absolute right-0 top-1/2 -translate-y-1/2 -translate-x-4 text-base select-none transition-colors duration-200 text-gray-400 peer-checked:text-gray-900'; + this.label.appendChild(this.onLabel); + + + this.input.addEventListener('change', () => { + if (this.input.checked) { + this.thumb.style.transform = 'translateX(31px)'; + this.onLabel.classList.remove('text-gray-400'); + this.onLabel.classList.add('text-gray-900'); + this.offLabel.classList.remove('text-gray-900'); + this.offLabel.classList.add('text-gray-400'); + } else { + this.thumb.style.transform = 'translateX(0)'; + this.onLabel.classList.remove('text-gray-900'); + this.onLabel.classList.add('text-gray-400'); + this.offLabel.classList.remove('text-gray-400'); + this.offLabel.classList.add('text-gray-900'); + } + if (onChange) onChange(this.input.checked); + }); + + // Set initial thumb and label color + if (checked) { + this.thumb.style.transform = 'translateX(31px)'; + this.onLabel.classList.remove('text-gray-400'); + this.onLabel.classList.add('text-gray-900'); + } else { + this.onLabel.classList.remove('text-gray-900'); + this.onLabel.classList.add('text-gray-400'); + } + + this.element = this.label; + } + + setChecked(val) { + this.input.checked = val; + if (this.input.checked) { + this.thumb.style.transform = 'translateX(48px)'; + this.onLabel.classList.remove('text-gray-400'); + this.onLabel.classList.add('text-gray-900'); + this.offLabel.classList.remove('text-gray-900'); + this.offLabel.classList.add('text-gray-400'); + } else { + this.thumb.style.transform = 'translateX(0)'; + this.onLabel.classList.remove('text-gray-900'); + this.onLabel.classList.add('text-gray-400'); + this.offLabel.classList.remove('text-gray-400'); + this.offLabel.classList.add('text-gray-900'); + } + } + + getChecked() { + return this.input.checked; + } + + disable() { + this.input.disabled = true; + this.label.classList.add('opacity-50', 'pointer-events-none'); + } + + enable() { + this.input.disabled = false; + this.label.classList.remove('opacity-50', 'pointer-events-none'); + } +}; + +window.addEventListener('load', async () => { + await installedApps.refreshAppList(); +}); \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/appstore.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/appstore.js new file mode 100644 index 0000000000000000000000000000000000000000..e570fd73f7f8bb6962fcae989983eadf0225bad3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/appstore.js @@ -0,0 +1,157 @@ + +const hfAppsStore = { + refreshAppList: async () => { + const appsData = await hfAppsStore.fetchAvailableApps(); + await hfAppsStore.displayAvailableApps(appsData); + }, + fetchAvailableApps: async () => { + const resAvailable = await fetch('/api/apps/list-available/dashboard_selection'); + const appsData = await resAvailable.json(); + return appsData; + }, + + isInstalling: false, + + installApp: async (app) => { + if (hfAppsStore.isInstalling) { + console.warn('An installation is already in progress.'); + return; + } + hfAppsStore.isInstalling = true; + + const appName = app.extra.cardData.title || app.name; + console.log(`Installing ${app.name}...`); + + const resp = await fetch('/api/apps/install', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(app) + }); + const data = await resp.json(); + const jobId = data.job_id; + + hfAppsStore.appInstallLogHandler(appName, jobId); + }, + + displayAvailableApps: async (appsData) => { + const appsListElement = document.getElementById('hf-available-apps'); + appsListElement.innerHTML = ''; + + if (!appsData || appsData.length === 0) { + appsListElement.innerHTML = '
  • No available apps found.
  • '; + return; + } + + const hfApps = appsData.filter(app => app.source_kind === 'hf_space'); + const installedApps = await fetch('/api/apps/list-available/installed').then(res => res.json()); + + hfApps.forEach(app => { + const li = document.createElement('li'); + li.className = 'app-list-item'; + const isInstalled = installedApps.some(installedApp => installedApp.name === app.name); + li.appendChild(hfAppsStore.createAppElement(app, isInstalled)); + appsListElement.appendChild(li); + }); + }, + + createAppElement: (app, isInstalled) => { + const container = document.createElement('div'); + container.className = 'grid grid-cols-[2rem_auto_8rem] justify-stretch gap-x-6'; + + const iconDiv = document.createElement('div'); + iconDiv.className = 'hf-app-icon row-span-2 my-1'; + iconDiv.textContent = app.extra.cardData.emoji || '📦'; + container.appendChild(iconDiv); + + const nameDiv = document.createElement('div'); + nameDiv.className = 'flex flex-col'; + + const titleDiv = document.createElement('a'); + titleDiv.href = app.url; + titleDiv.target = '_blank'; + titleDiv.rel = 'noopener noreferrer'; + titleDiv.className = 'hf-app-title'; + titleDiv.textContent = app.extra.cardData.title || app.name; + nameDiv.appendChild(titleDiv); + const descriptionDiv = document.createElement('span'); + descriptionDiv.className = 'hf-app-description'; + descriptionDiv.textContent = app.description || 'No description available.'; + nameDiv.appendChild(descriptionDiv); + container.appendChild(nameDiv); + + const installButtonDiv = document.createElement('button'); + installButtonDiv.className = 'row-span-2 my-2 hf-app-install-button'; + + if (isInstalled) { + installButtonDiv.classList.add('bg-gray-400', 'cursor-not-allowed'); + installButtonDiv.textContent = 'Installed'; + installButtonDiv.disabled = true; + } else { + installButtonDiv.classList.add('border', 'border-red-600'); + installButtonDiv.textContent = 'Install'; + installButtonDiv.onclick = async () => { + hfAppsStore.installApp(app); + }; + } + + container.appendChild(installButtonDiv); + + return container; + }, + + appInstallLogHandler: async (appName, jobId) => { + const installModal = document.getElementById('install-modal'); + const modalTitle = installModal.querySelector('#modal-title'); + modalTitle.textContent = `Installing ${appName}...`; + installModal.classList.remove('hidden'); + + const logsDiv = document.getElementById('install-logs'); + logsDiv.textContent = ''; + + const closeButton = document.getElementById('modal-close-button'); + closeButton.onclick = () => { + installModal.classList.add('hidden'); + }; + closeButton.classList = "hidden"; + closeButton.textContent = ''; + + const ws = new WebSocket(`ws://${location.host}/api/apps/ws/apps-manager/${jobId}`); + ws.onmessage = (event) => { + try { + if (event.data.startsWith('{') && event.data.endsWith('}')) { + const data = JSON.parse(event.data); + + if (data.status === "failed") { + closeButton.classList = "text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800"; + closeButton.textContent = 'Close'; + console.error(`Installation of ${appName} failed.`); + } else if (data.status === "done") { + closeButton.classList = "text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"; + closeButton.textContent = 'Install done'; + console.log(`Installation of ${appName} completed.`); + + } + } + else { + logsDiv.innerHTML += event.data + '\n'; + logsDiv.scrollTop = logsDiv.scrollHeight; + } + + + } catch { + logsDiv.innerHTML += event.data + '\n'; + logsDiv.scrollTop = logsDiv.scrollHeight; + } + }; + ws.onclose = async () => { + hfAppsStore.isInstalling = false; + hfAppsStore.refreshAppList(); + installedApps.refreshAppList(); + }; + }, +}; + + +window.addEventListener('load', async () => { + await hfAppsStore.refreshAppList(); +}); \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/daemon.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/daemon.js new file mode 100644 index 0000000000000000000000000000000000000000..4bcb67c725d9dfb99e17d34d15a73b281c1baebc --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/daemon.js @@ -0,0 +1,169 @@ + + + +const daemon = { + currentStatus: { + state: null, + }, + + start: async (wakeUp) => { + await fetch(`/api/daemon/start?wake_up=${wakeUp}`, { + method: 'POST', + }) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .then(async (data) => { + await daemon.checkStatusUpdate(); + }) + .catch((error) => { + console.error('Error starting daemon:', error); + }); + }, + + stop: async (gotoSleep) => { + await fetch(`/api/daemon/stop?goto_sleep=${gotoSleep}`, { + method: 'POST', + }) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .then(async (data) => { + await daemon.checkStatusUpdate(); + }) + .catch((error) => { + console.error('Error stopping daemon:', error); + }); + }, + + getStatus: async () => { + await fetch('/api/daemon/status') + .then((response) => response.json()) + .then(async (data) => { + let currentState = daemon.currentStatus.state; + let newState = data.state || null; + + daemon.currentStatus = data; + + if (currentState === null || currentState !== newState) { + await daemon.updateUI(); + } + + }) + .catch((error) => { + console.error('Error fetching daemon status:', error); + }); + }, + + checkStatusUpdate: async (initialState) => { + await daemon.getStatus(); + + if (!initialState) { + initialState = daemon.currentStatus.state; + } + + let currentState = daemon.currentStatus.state; + + if (currentState !== "error" && (currentState === initialState || currentState === "starting" || currentState === "stopping")) { + setTimeout(() => { + daemon.checkStatusUpdate(initialState); + }, 500); + } + }, + + toggleSwitch: async () => { + const toggleDaemonSwitch = document.getElementById('daemon-toggle'); + + if (toggleDaemonSwitch.checked) { + console.log('Toggle switched ON. Starting daemon...'); + await daemon.start(true); + } else { + console.log('Toggle switched OFF. Stopping daemon...'); + await daemon.stop(true); + } + + await daemon.updateToggle(); + }, + + updateUI: async () => { + const daemonStatusAnim = document.getElementById('daemon-status-anim'); + const toggleDaemonSwitch = document.getElementById('daemon-toggle'); + const backendStatusIcon = document.getElementById('backend-status-icon'); + const backendStatusText = document.getElementById('backend-status-text'); + + let daemonState = daemon.currentStatus.state; + + toggleDaemonSwitch.disabled = false; + backendStatusIcon.classList.remove('bg-green-500', 'bg-yellow-500', 'bg-red-500'); + + if (daemonState === 'starting') { + // daemonStatusAnim.setAttribute('data', '/static/assets/reachy-mini-wake-up-animation.svg'); + daemonStatusAnim.setAttribute('data', '/static/assets/awake-cartoon.svg'); + toggleDaemonSwitch.disabled = true; + toggleDaemonSwitch.checked = true; + backendStatusIcon.classList.add('bg-yellow-500'); + backendStatusText.textContent = 'Waking up...'; + } + else if (daemonState === 'running') { + // daemonStatusAnim.setAttribute('data', '/static/assets/reachy-mini-awake.svg'); + daemonStatusAnim.setAttribute('data', '/static/assets/awake-cartoon-static.svg'); + toggleDaemonSwitch.checked = true; + backendStatusIcon.classList.add('bg-green-500'); + backendStatusText.textContent = 'Up and ready'; + } + else if (daemonState === 'stopping') { + // daemonStatusAnim.setAttribute('data', '/static/assets/reachy-mini-go-to-sleep-animation.svg'); + daemonStatusAnim.setAttribute('data', '/static/assets/go-to-sleep-cartoon.svg'); + toggleDaemonSwitch.disabled = true; + toggleDaemonSwitch.checked = false; + backendStatusIcon.classList.add('bg-yellow-500'); + backendStatusText.textContent = 'Going to sleep...'; + } + else if (daemonState === 'stopped' || daemonState === 'not_initialized') { + // daemonStatusAnim.setAttribute('data', '/static/assets/reachy-mini-sleeping.svg'); + daemonStatusAnim.setAttribute('data', '/static/assets/reachy-mini-sleeping-static.svg'); + toggleDaemonSwitch.checked = false; + backendStatusIcon.classList.add('bg-yellow-500'); + backendStatusText.textContent = 'Stopped'; + } + else if (daemonState === 'error') { + daemonStatusAnim.setAttribute('data', '/static/assets/no-wifi-cartoon.svg'); + toggleDaemonSwitch.checked = false; + backendStatusIcon.classList.add('bg-red-500'); + backendStatusText.textContent = 'Error occurred'; + + notificationCenter.showError(daemon.currentStatus.error); + } + + await daemon.updateToggle(); + }, + + updateToggle: async () => { + const toggle = document.getElementById('daemon-toggle'); + const toggleSlider = document.getElementById('daemon-toggle-slider'); + const toggleOnLabel = document.getElementById('daemon-toggle-on'); + const toggleOffLabel = document.getElementById('daemon-toggle-off'); + + toggleSlider.classList.remove('hidden'); + + if (toggle.checked) { + toggleOnLabel.classList.remove('hidden'); + toggleOffLabel.classList.add('hidden'); + } else { + toggleOnLabel.classList.add('hidden'); + toggleOffLabel.classList.remove('hidden'); + } + }, +}; + + +window.addEventListener('load', async () => { + document.getElementById('daemon-toggle').onchange = daemon.toggleSwitch; + await daemon.getStatus(); +}); \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/health_check.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/health_check.js new file mode 100644 index 0000000000000000000000000000000000000000..e0514b2765eddf49ee35c3e990a89a5a34717891 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/health_check.js @@ -0,0 +1,9 @@ +window.addEventListener("load", () => { + const healthCheckInterval = setInterval(async () => { + const response = await fetch("/health-check", { method: "POST" }); + if (!response.ok) { + console.error("Health check failed"); + clearInterval(healthCheckInterval); + } + }, 2500); +}); diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/move_player.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/move_player.js new file mode 100644 index 0000000000000000000000000000000000000000..322a94e7e199936d9ce696362bb54a5fa44cad2f --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/move_player.js @@ -0,0 +1,132 @@ +const updateMoveItems = async (dataset) => { + fetch(`/api/move/recorded-move-datasets/list/${dataset}`) + .then(response => response.json()) + .then(data => { + // Update the UI with the list of recorded moves + const moveSelectToggle = document.getElementById('move-select-toggle'); + moveSelectToggle.innerHTML = ''; + + data.forEach(moveName => { + const option = document.createElement('option'); + option.value = moveName; + option.textContent = moveName; + moveSelectToggle.appendChild(option); + }); + + }) + .catch(error => { + console.error(`Error fetching recorded moves for dataset '${dataset}':`, error); + }); +}; + +const movePlayer = { + playing: false, + currentMove: null, + + playRecordedMove: async (dataset, move) => { + console.log(`Requesting play move '${move}' from dataset '${dataset}'`); + + // movePlayer.playing = true; + // movePlayer.updateUI(); + + await fetch(`/api/move/play/recorded-move-dataset/${dataset}/${move}`, { + method: 'POST' + }).then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + } + ).then(data => { + movePlayer.currentMove = data.uuid; + }).catch(error => { + console.error(`Error playing move '${move}' from dataset '${dataset}':`, error); + // movePlayer.playing = false; + // movePlayer.currentMove = null; + // movePlayer.updateUI(); + }); + }, + + stopMove: async () => { + console.log(`Requesting stop of current move`); + + await fetch(`/api/move/stop`, { + method: 'POST', + body: JSON.stringify({ uuid: movePlayer.currentMove }), + headers: { + 'Content-Type': 'application/json' + } + }); + }, + + updateUI: () => { + const movePlayBtn = document.getElementById('move-play-btn'); + const moveStopBtn = document.getElementById('move-stop-btn'); + + if (movePlayer.playing) { + movePlayBtn.disabled = true; + moveStopBtn.disabled = false; + } else { + movePlayBtn.disabled = false; + moveStopBtn.disabled = true; + } + }, + + checkMoveStatus: async () => { + let ws = new WebSocket(`ws://${window.location.host}/api/move/ws/updates`); + + ws.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data.type === 'move_started') { + movePlayer.playing = true; + movePlayer.currentMove = data.move_id; + } + else if (data.type === 'move_completed') { + movePlayer.playing = false; + movePlayer.currentMove = null; + } + else if (data.type === 'move_failed' || data.type === 'move_cancelled') { + movePlayer.playing = false; + movePlayer.currentMove = null; + } + + movePlayer.updateUI(); + }; + + ws.onclose = () => { + console.log('Move status WebSocket closed, reconnecting in 1 second...'); + setTimeout(() => { + movePlayer.checkMoveStatus(); + }, 1000); + }; + } +}; + +window.addEventListener('DOMContentLoaded', (event) => { + const moveDatasetToggle = document.getElementById('move-dataset-toggle'); + + moveDatasetToggle.addEventListener('change', (_) => { + const selectedDataset = moveDatasetToggle.value; + updateMoveItems(selectedDataset); + }); + + const movePlayBtn = document.getElementById('move-play-btn'); + movePlayBtn.addEventListener('click', async () => { + const selectedDataset = moveDatasetToggle.value; + const moveSelectToggle = document.getElementById('move-select-toggle'); + const selectedMove = moveSelectToggle.value; + + await movePlayer.playRecordedMove(selectedDataset, selectedMove); + }); + + const moveStopBtn = document.getElementById('move-stop-btn'); + moveStopBtn.addEventListener('click', async () => { + await movePlayer.stopMove(); + }); + + // Initialize move items on page load + updateMoveItems(moveDatasetToggle.value); + + movePlayer.checkMoveStatus(); + movePlayer.updateUI(); +}); \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/notification.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/notification.js new file mode 100644 index 0000000000000000000000000000000000000000..69e119956273544332422e0ad25e397bcb44ead3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/notification.js @@ -0,0 +1,41 @@ +const notificationCenter = { + + showInfo: (message, duration = 5000, autoclose = true) => { + notificationCenter.showNotification(message, false, duration, autoclose); + }, + showError: (message, duration = 5000, autoclose = false) => { + message = notificationCenter.errorTranslation(message); + notificationCenter.showNotification(message, true, duration, autoclose); + }, + + showNotification: (message, error, duration = 5000, autoclose = true) => { + document.getElementById('notification-message').textContent = message; + document.getElementById('notification-modal').style.display = 'block'; + + if (error) { + document.getElementById('notification-content').classList.add('error'); + document.getElementById('notification-content').classList.remove('info'); + } else { + document.getElementById('notification-content').classList.remove('error'); + document.getElementById('notification-content').classList.add('info'); + } + + if (autoclose) { + setTimeout(notificationCenter.closeNotification, duration); + } + }, + + closeNotification: () => { + document.getElementById('notification-modal').style.display = 'none'; + }, + + errorTranslation: (errorMessage) => { + if (errorMessage.includes('No Reachy Mini serial port found.')) { + return 'Reachy Mini not detected on USB. Please check that the USB cable is properly connected.'; + } + + console.log('No translation found for error message:', errorMessage); + return errorMessage; + }, + +}; \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/update.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/update.js new file mode 100644 index 0000000000000000000000000000000000000000..a1e6812812dcb99af3c2e74ffc80f9244efdf2fc --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/update.js @@ -0,0 +1,132 @@ +const updateManager = { + busy: false, + preRelease: false, + + checkForUpdate: async () => { + await updateManager.updateUI(); // Clear previous state + + await fetch('/update/available?pre_release=' + updateManager.preRelease) + .then(async response => { + if (!response.ok) { + return false; + } + const data = await response.json(); + await updateManager.updateUI(data); + }).catch(error => { + console.error('Error checking for updates:', error); + }); + }, + + startUpdate: async () => { + if (updateManager.busy) { + console.warn('An update is already in progress.'); + return; + } + updateManager.busy = true; + + fetch('/update/start?pre_release=' + updateManager.preRelease, { method: 'POST' }) + .then(response => { + if (response.ok) { + return response.json(); + } else { + return response.json().then(data => { + throw new Error(data.detail || 'Error starting update'); + }); + } + }) + .then(data => { + const jobId = data.job_id; + updateManager.connectLogsWebSocket(jobId); + }) + .catch(error => { + console.error('Error triggering update:', error); + updateManager.busy = false; + }); + }, + + connectLogsWebSocket: (jobId) => { + const updateModal = document.getElementById('update-modal'); + const updateModalTitle = document.getElementById('update-modal-title'); + const logsDiv = document.getElementById('update-logs'); + const closeButton = document.getElementById('update-modal-close-button'); + + updateModalTitle.textContent = 'Updating...'; + + closeButton.onclick = () => { + updateModal.classList.add('hidden'); + }; + + updateModal.classList.remove('hidden'); + + const ws = new WebSocket(`ws://${location.host}/update/ws/logs?job_id=${jobId}`); + + ws.onmessage = (event) => { + // console.log('Update log:', event); + logsDiv.innerHTML += event.data + '
    '; + logsDiv.scrollTop = logsDiv.scrollHeight; + }; + ws.onclose = async () => { + console.log('Update logs WebSocket closed'); + closeButton.classList.remove('hidden'); + closeButton.textContent = 'Close'; + updateModalTitle.textContent = 'Update Completed ✅'; + + updateManager.busy = false; + await updateManager.checkForUpdate(); + }; + }, + + updateUI: async (update) => { + // updateManager.updateMainPage(isUpdateAvailable); + updateManager.updateUpdatePage(update); + }, + + // updateMainPage: async (update) => { + // const daemonUpdateBtn = document.getElementById('daemon-update-btn'); + // if (!daemonUpdateBtn) return; + + // if (isUpdateAvailable) { + // daemonUpdateBtn.innerHTML = 'Update 1'; + // } else { + // daemonUpdateBtn.innerHTML = 'Update'; + // } + // }, + updateUpdatePage: async (data) => { + const statusElem = document.getElementById('update-status'); + if (!statusElem) return; + + const currentVersionElem = document.getElementById('current-version'); + const availableVersionElem = document.getElementById('available-version'); + const availableVersionContainer = document.getElementById('available-version-container'); + const startUpdateBtn = document.getElementById('start-update-btn'); + + if (!data || !data.update || !data.update.reachy_mini) { + statusElem.innerHTML = 'Checking for updates...'; + if (currentVersionElem) currentVersionElem.textContent = ''; + if (availableVersionElem) availableVersionElem.textContent = ''; + return; + } + + const updateInfo = data.update.reachy_mini; + const isUpdateAvailable = updateInfo.is_available; + const currentVersion = updateInfo.current_version || '-'; + const availableVersion = updateInfo.available_version || '-'; + + if (currentVersionElem) currentVersionElem.textContent = `Current version: ${currentVersion}`; + if (availableVersionElem) availableVersionElem.textContent = `Available version: ${availableVersion}`; + + if (isUpdateAvailable) { + statusElem.innerHTML = 'An update is available!'; + if (availableVersionContainer) availableVersionContainer.classList.remove('hidden'); + startUpdateBtn.classList.remove('hidden'); + } else { + statusElem.innerHTML = 'Your system is up to date.'; + if (availableVersionContainer) availableVersionContainer.classList.add('hidden'); + startUpdateBtn.classList.add('hidden'); + } + } +}; + +window.addEventListener('load', async () => { + await updateManager.checkForUpdate(); +}); \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/volume_control.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/volume_control.js new file mode 100644 index 0000000000000000000000000000000000000000..0b6fdbd05a9bfff354480385d304210794235488 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/volume_control.js @@ -0,0 +1,252 @@ +const volumeControl = { + currentVolume: 50, + device: 'unknown', + platform: 'unknown', + isUpdating: false, + + init: async () => { + const slider = document.getElementById('volume-slider'); + const valueLabel = document.getElementById('volume-value'); + const deviceInfo = document.getElementById('volume-device-info'); + + if (!slider || !valueLabel || !deviceInfo) { + console.warn('Volume control elements not found in DOM'); + return; + } + + try { + await volumeControl.loadCurrentVolume(); + } catch (error) { + console.error('Error loading current volume:', error); + deviceInfo.textContent = 'Error loading volume'; + } + + slider.addEventListener('input', (e) => { + const v = Number(e.target.value); + valueLabel.textContent = String(v); + }); + + slider.addEventListener('change', async (e) => { + const newVolume = Number(e.target.value); + if (!Number.isFinite(newVolume)) return; + await volumeControl.setVolume(newVolume); + }); + }, + + loadCurrentVolume: async () => { + try { + const response = await fetch('/api/volume/current'); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + + const volume = Number(data.volume); + if (!Number.isFinite(volume)) { + throw new Error('Invalid volume in response'); + } + + volumeControl.currentVolume = volume; + volumeControl.device = data.device ?? 'unknown'; + volumeControl.platform = data.platform ?? 'unknown'; + + const slider = document.getElementById('volume-slider'); + const valueLabel = document.getElementById('volume-value'); + const deviceInfo = document.getElementById('volume-device-info'); + + if (slider) slider.value = String(volume); + if (valueLabel) valueLabel.textContent = String(volume); + if (deviceInfo) { + deviceInfo.textContent = `${volumeControl.platform} - ${volumeControl.device}`; + } + + console.log('Loaded volume:', data); + } catch (error) { + console.error('Error loading current volume:', error); + throw error; + } + }, + + setVolume: async (volume) => { + if (!Number.isFinite(volume)) { + console.warn('Ignoring invalid volume:', volume); + return; + } + + const safeVolume = Math.max(0, Math.min(100, volume)); + if (volumeControl.isUpdating) { + console.log('Volume update already in progress, skipping...'); + return; + } + + volumeControl.isUpdating = true; + const slider = document.getElementById('volume-slider'); + + if (slider) slider.disabled = true; + + try { + const response = await fetch('/api/volume/set', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ volume: safeVolume }), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + const serverVolume = Number(data.volume); + + if (Number.isFinite(serverVolume)) { + volumeControl.currentVolume = serverVolume; + const s = document.getElementById('volume-slider'); + const valueLabel = document.getElementById('volume-value'); + if (s) s.value = String(serverVolume); + if (valueLabel) valueLabel.textContent = String(serverVolume); + } + + console.log('Volume set to:', serverVolume); + } catch (error) { + console.error('Error setting volume:', error); + try { + await volumeControl.loadCurrentVolume(); + } catch (loadError) { + console.error('Also failed to reload volume:', loadError); + } + } finally { + volumeControl.isUpdating = false; + const s = document.getElementById('volume-slider'); + if (s) s.disabled = false; + } + }, +}; + +const microphoneControl = { + currentVolume: 50, + device: 'unknown', + platform: 'unknown', + isUpdating: false, + + init: async () => { + const slider = document.getElementById('microphone-slider'); + const valueLabel = document.getElementById('microphone-value'); + const deviceInfo = document.getElementById('microphone-device-info'); + + if (!slider || !valueLabel || !deviceInfo) { + console.warn('Microphone control elements not found in DOM'); + return; + } + + try { + await microphoneControl.loadCurrentVolume(); + } catch (error) { + console.error('Error loading current microphone volume:', error); + deviceInfo.textContent = 'Error loading microphone'; + } + + slider.addEventListener('input', (e) => { + const v = Number(e.target.value); + valueLabel.textContent = String(v); + }); + + slider.addEventListener('change', async (e) => { + const newVolume = Number(e.target.value); + if (!Number.isFinite(newVolume)) return; + await microphoneControl.setVolume(newVolume); + }); + }, + + loadCurrentVolume: async () => { + try { + const response = await fetch('/api/volume/microphone/current'); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + + const volume = Number(data.volume); + if (!Number.isFinite(volume)) { + throw new Error('Invalid microphone volume in response'); + } + + microphoneControl.currentVolume = volume; + microphoneControl.device = data.device ?? 'unknown'; + microphoneControl.platform = data.platform ?? 'unknown'; + + const slider = document.getElementById('microphone-slider'); + const valueLabel = document.getElementById('microphone-value'); + const deviceInfo = document.getElementById('microphone-device-info'); + + if (slider) slider.value = String(volume); + if (valueLabel) valueLabel.textContent = String(volume); + if (deviceInfo) { + deviceInfo.textContent = `${microphoneControl.platform} - ${microphoneControl.device}`; + } + + console.log('Loaded microphone volume:', data); + } catch (error) { + console.error('Error loading current microphone volume:', error); + throw error; + } + }, + + setVolume: async (volume) => { + if (!Number.isFinite(volume)) { + console.warn('Ignoring invalid microphone volume:', volume); + return; + } + + const safeVolume = Math.max(0, Math.min(100, volume)); + if (microphoneControl.isUpdating) { + console.log('Microphone volume update already in progress, skipping...'); + return; + } + + microphoneControl.isUpdating = true; + const slider = document.getElementById('microphone-slider'); + + if (slider) slider.disabled = true; + + try { + const response = await fetch('/api/volume/microphone/set', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ volume: safeVolume }), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + const serverVolume = Number(data.volume); + + if (Number.isFinite(serverVolume)) { + microphoneControl.currentVolume = serverVolume; + const s = document.getElementById('microphone-slider'); + const valueLabel = document.getElementById('microphone-value'); + if (s) s.value = String(serverVolume); + if (valueLabel) valueLabel.textContent = String(serverVolume); + } + + console.log('Microphone volume set to:', serverVolume); + } catch (error) { + console.error('Error setting microphone volume:', error); + try { + await microphoneControl.loadCurrentVolume(); + } catch (loadError) { + console.error('Also failed to reload microphone volume:', loadError); + } + } finally { + microphoneControl.isUpdating = false; + const s = document.getElementById('microphone-slider'); + if (s) s.disabled = false; + } + }, +}; + +window.addEventListener('DOMContentLoaded', () => { + volumeControl.init(); + microphoneControl.init(); +}); diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/wifi.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/wifi.js new file mode 100644 index 0000000000000000000000000000000000000000..3a620a408228bb0ef19790612912e7a97eb0e87c --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/static/js/wifi.js @@ -0,0 +1,176 @@ + +const getStatus = async () => { + return await fetch('/wifi/status') + .then(response => response.json()) + .catch(error => { + console.error('Error fetching WiFi status:', error); + return { mode: 'error' }; + }); +}; + +const refreshStatus = async () => { + const status = await getStatus(); + handleStatus(status); + + await fetch('/wifi/error') + .then(response => response.json()) + .then(data => { + if (data.error !== null) { + console.log('Error data:', data); + alert(`Error while trying to connect: ${data.error}.\n Switching back to hotspot mode.`); + fetch('/wifi/reset_error', { method: 'POST' }); + } + }) + .catch(error => { + console.error('Error fetching WiFi error:', error); + }); +}; + +const scanAndListWifiNetworks = async () => { + await fetch('/wifi/scan_and_list', { method: 'POST' }) + .then(response => response.json()) + .then(data => { + const ssidSelect = document.getElementById('ssid'); + data.forEach(ssid => { + const option = document.createElement('option'); + option.value = ssid; + option.textContent = ssid; + ssidSelect.appendChild(option); + }); + }) + .catch(() => { + const ssidSelect = document.getElementById('ssid'); + const option = document.createElement('option'); + option.value = ""; + option.textContent = "Unable to load networks"; + ssidSelect.appendChild(option); + }); +}; + +const connectToWifi = (_) => { + const ssid = document.getElementById('ssid').value; + const password = document.getElementById('password').value; + + if (!ssid) { + alert('Please enter an SSID.'); + return; + } + + fetch(`/wifi/connect?ssid=${encodeURIComponent(ssid)}&password=${encodeURIComponent(password)}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }) + .then(response => { + if (!response.ok) { + return response.json().then(errData => { + throw new Error(errData.detail || 'Failed to connect to WiFi'); + }); + } + + // Clear the form fields + document.getElementById('ssid').value = ''; + document.getElementById('password').value = ''; + + return response.json(); + }) + .then(data => { + handleStatus({ mode: 'busy' }); + }) + .catch(error => { + console.error('Error connecting to WiFi:', error); + alert(`Error connecting to WiFi: ${error.message}`); + }); + return false; // Prevent form submission +}; + +let currentMode = null; + +const handleStatus = (status) => { + const statusDiv = document.getElementById('wifi-status'); + + const knownNetworksDiv = document.getElementById('known-networks'); + const knownNetworksList = document.getElementById('known-networks-list'); + knownNetworksDiv.classList.remove('hidden'); + + const mode = status.mode; + + knownNetworksList.innerHTML = ''; + if (status.known_networks !== undefined && Array.isArray(status.known_networks)) { + status.known_networks.forEach((network) => { + const li = document.createElement('li'); + li.classList = 'flex flex-row items-center mb-1 gap-4 justify-left'; + + const nameSpan = document.createElement('span'); + nameSpan.innerText = network; + li.appendChild(nameSpan); + + // const removeBtn = document.createElement('span'); + // removeBtn.innerText = ' (remove ❌)'; + // removeBtn.style.cursor = 'pointer'; + // removeBtn.title = 'Remove network'; + // removeBtn.onclick = async () => { + // if (confirm(`Remove network '${network}'?`)) { + // removeNetwork(network); + // } + // }; + // li.appendChild(removeBtn); + + knownNetworksList.appendChild(li); + }); + } + + if (mode == 'hotspot') { + statusDiv.innerText = 'Hotspot mode active. 🔌'; + + } else if (mode == 'wlan') { + if (currentMode !== null && currentMode !== 'wlan') { + alert(`Successfully connected to WiFi network: ${status.connected_network} ✅`); + } + + statusDiv.innerText = `Connected to WiFi (SSID: ${status.connected_network}). 📶`; + + } else if (mode == 'disconnected') { + statusDiv.innerText = 'WiFi disconnected. ❌'; + } else if (mode == 'busy') { + statusDiv.innerText = 'Changing your WiFi configuration... Please wait ⏳'; + } else if (mode == 'error') { + statusDiv.innerText = 'Error connecting to WiFi. ⚠️'; + } else { + console.warn(`Unknown status: ${status}`); + } + + currentMode = mode; +}; + +const removeNetwork = async (ssid) => { + const status = await getStatus(); + + // TODO: + // if ssid !== status.connected_network: + // remove connection + // else: + // refresh nmcli? go back to hotspot if needed? +}; + +const cleanAndRefresh = async () => { + const statusDiv = document.getElementById('wifi-status'); + statusDiv.innerText = 'Checking WiFi configuration...'; + + const knownNetworksDiv = document.getElementById('known-networks'); + knownNetworksDiv.classList.add('hidden'); + + const addWifi = document.getElementById('add-wifi'); + addWifi.classList.add('hidden'); + + await scanAndListWifiNetworks(); + await refreshStatus(); + + addWifi.classList.remove('hidden'); +}; + +window.addEventListener('load', async () => { + await cleanAndRefresh(); + setInterval(refreshStatus, 1000); +}); \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/.gitignore b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b512c09d476623ff4bf8d0d63c29b784925dbdf8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/README.md b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3d7fed0f0946ebfdb2d5771b50867eaa7b0729ce --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/README.md @@ -0,0 +1,15 @@ +# Generate static Tailwind CSS + +## Requirements + +(From this folder) + +```bash +pnpm install -D tailwindcss @tailwindcss/cli +``` + +## Generate CSS + +```bash +npx @tailwindcss/cli -i ./styles/app.css -o ../static/css/app.css +``` \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/package-lock.json b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..a3f0c7643d855903a6fc9bc92e44f5e6dc185eda --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/package-lock.json @@ -0,0 +1,1127 @@ +{ + "name": "tailwindcss", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@tailwindcss/cli": "^4.1.16", + "tailwindcss": "^4.1.16" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/cli": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.16.tgz", + "integrity": "sha512-dsnANPrh2ZooHyZ/8uJhc9ecpcYtufToc21NY09NS9vF16rxPCjJ8dP7TUAtPqlUJTHSmRkN2hCdoYQIlgh4fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/watcher": "^2.5.1", + "@tailwindcss/node": "4.1.16", + "@tailwindcss/oxide": "4.1.16", + "enhanced-resolve": "^5.18.3", + "mri": "^1.2.0", + "picocolors": "^1.1.1", + "tailwindcss": "4.1.16" + }, + "bin": { + "tailwindcss": "dist/index.mjs" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz", + "integrity": "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.19", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.16" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.16.tgz", + "integrity": "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.16", + "@tailwindcss/oxide-darwin-arm64": "4.1.16", + "@tailwindcss/oxide-darwin-x64": "4.1.16", + "@tailwindcss/oxide-freebsd-x64": "4.1.16", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", + "@tailwindcss/oxide-linux-x64-musl": "4.1.16", + "@tailwindcss/oxide-wasm32-wasi": "4.1.16", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.16.tgz", + "integrity": "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz", + "integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.16.tgz", + "integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.16.tgz", + "integrity": "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.16.tgz", + "integrity": "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.16.tgz", + "integrity": "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.16.tgz", + "integrity": "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.16.tgz", + "integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.16.tgz", + "integrity": "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.16.tgz", + "integrity": "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.7", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.16.tgz", + "integrity": "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz", + "integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz", + "integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + } + } +} diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/package.json b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/package.json new file mode 100644 index 0000000000000000000000000000000000000000..9e9ee28e6ea80bd2ae7e80a7e1b5d22472b8f064 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "@tailwindcss/cli": "^4.1.16", + "tailwindcss": "^4.1.16" + } +} diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/pnpm-lock.yaml b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/pnpm-lock.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1211930a125a4ee857a1a12a0f07ff01cd342fbe --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/pnpm-lock.yaml @@ -0,0 +1,608 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@tailwindcss/cli': + specifier: ^4.1.16 + version: 4.1.16 + tailwindcss: + specifier: ^4.1.16 + version: 4.1.16 + +packages: + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + + '@tailwindcss/cli@4.1.16': + resolution: {integrity: sha512-dsnANPrh2ZooHyZ/8uJhc9ecpcYtufToc21NY09NS9vF16rxPCjJ8dP7TUAtPqlUJTHSmRkN2hCdoYQIlgh4fw==} + hasBin: true + + '@tailwindcss/node@4.1.16': + resolution: {integrity: sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==} + + '@tailwindcss/oxide-android-arm64@4.1.16': + resolution: {integrity: sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.16': + resolution: {integrity: sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.16': + resolution: {integrity: sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.16': + resolution: {integrity: sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16': + resolution: {integrity: sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.16': + resolution: {integrity: sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.16': + resolution: {integrity: sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.16': + resolution: {integrity: sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.16': + resolution: {integrity: sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.16': + resolution: {integrity: sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.16': + resolution: {integrity: sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.16': + resolution: {integrity: sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.16': + resolution: {integrity: sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==} + engines: {node: '>= 10'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + tailwindcss@4.1.16: + resolution: {integrity: sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + +snapshots: + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + + '@tailwindcss/cli@4.1.16': + dependencies: + '@parcel/watcher': 2.5.1 + '@tailwindcss/node': 4.1.16 + '@tailwindcss/oxide': 4.1.16 + enhanced-resolve: 5.18.3 + mri: 1.2.0 + picocolors: 1.1.1 + tailwindcss: 4.1.16 + + '@tailwindcss/node@4.1.16': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.16 + + '@tailwindcss/oxide-android-arm64@4.1.16': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.16': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.16': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.16': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.16': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.16': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.16': + optional: true + + '@tailwindcss/oxide@4.1.16': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.16 + '@tailwindcss/oxide-darwin-arm64': 4.1.16 + '@tailwindcss/oxide-darwin-x64': 4.1.16 + '@tailwindcss/oxide-freebsd-x64': 4.1.16 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.16 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.16 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.16 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.16 + '@tailwindcss/oxide-linux-x64-musl': 4.1.16 + '@tailwindcss/oxide-wasm32-wasi': 4.1.16 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.16 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.16 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + detect-libc@1.0.3: {} + + detect-libc@2.1.2: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + graceful-fs@4.2.11: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + jiti@2.6.1: {} + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mri@1.2.0: {} + + node-addon-api@7.1.1: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + source-map-js@1.2.1: {} + + tailwindcss@4.1.16: {} + + tapable@2.3.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/postcss.config.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/postcss.config.js new file mode 100644 index 0000000000000000000000000000000000000000..33ad091d26d8a9dc95ebdf616e217d985ec215b8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/styles/app.css b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/styles/app.css new file mode 100644 index 0000000000000000000000000000000000000000..8c28fb1018a0aceb3fbb555024e0eeef4da96c42 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/styles/app.css @@ -0,0 +1,185 @@ +@import "tailwindcss"; + +@source "../../templates/**/*.html"; +@source "../../static/js/**/*.js"; + +@font-face { + font-family: 'Asap'; + src: url('/static/fonts/Asap-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-style: normal; +} + +@font-face { + font-family: 'Asap'; + src: url('/static/fonts/Asap-Italic-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-style: italic; +} + +@font-face { + font-family: 'Archivo'; + src: url('/static/fonts/Archivo-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-style: normal; +} + +@font-face { + font-family: 'Archivo'; + src: url('/static/fonts/Archivo-Italic-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-style: italic; +} + + + +html { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + font-family: 'Archivo', 'Asap', sans-serif; +} + +.daemon-status-title { + font-size: 36px; + font-weight: 500; + letter-spacing: 0.3px; +} + +.daemon-status-collapse { + font-family: 'Asap', sans-serif; + font-weight: 400; + color: rgba(0, 0, 0, 0.7); +} + +/* APPs styles */ + +.app-section { + border-radius: 8px; + border-width: 1px; + padding: 16px; + gap: 16px; + background: #FFFFFF; +} + +.installed-app-title { + font-weight: 600; +} + +/* Hugging Face App Store Styles */ + +.app-section-title { + font-weight: 500; + font-size: 24px; + letter-spacing: 0px; +} + +.app-list-item { + padding: 4px; +} + +.hf-app-icon { + width: 42px; + height: 42px; + border-radius: 10px; + text-align: center; + font-size: 31px; + background-color: rgba(0, 0, 0, 0.1); + +} + +.hf-app-title { + font-weight: 500; + font-size: 18px; +} + +.hf-app-description { + font-family: 'Asap', sans-serif; + font-weight: 400; + font-size: 16px; + line-height: 75%; + color: rgba(0, 0, 0, 0.4); +} + +.hf-app-install-button { + font-weight: 500; + font-size: 20px; + font-style: Bold; + text-align: center; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; +} + +.wifi-status { + font-family: 'Asap', sans-serif; + font-weight: 500; + color: rgba(0, 0, 0, 0.9); + +} + +.wifi-status-info { + font-family: 'Asap', sans-serif; + font-weight: 400; + color: rgba(0, 0, 0, 0.7); +} + + +.notification-modal { + position: fixed; + bottom: 24px; + right: 24px; + z-index: 9999; + min-width: 300px; + max-width: 400px; + background: #fff; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); + border-radius: 8px; + display: none; + animation: fadeInUp 0.3s; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(40px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +.notification-content { + padding: 20px 28px; + border-radius: 8px; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15); + display: flex; + align-items: center; + justify-content: space-between; +} + +/* Notification variants */ +.notification-content.info { + background: #fff; + border: 1px solid #e0e0e0; +} + +.notification-content.error { + background: #ffeaea; + border: 1px solid #ff4d4f; + color: #b71c1c; +} + + +.close-btn { + background: none; + border: none; + font-size: 1.5em; + cursor: pointer; + color: #888; +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/tailwind.config.js b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/tailwind.config.js new file mode 100644 index 0000000000000000000000000000000000000000..e5d481b84c2f2a5158ad670500d8279864a51178 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/tailwindcss/tailwind.config.js @@ -0,0 +1,11 @@ +module.exports = { + purge: [], + darkMode: false, // or 'media' or 'class' + theme: { + extend: {}, + }, + variants: { + extend: {}, + }, + plugins: [], +} diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/base.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/base.html new file mode 100644 index 0000000000000000000000000000000000000000..06f7fb80f8800acfcbaa51204f8eb45ba2bbc5e1 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/base.html @@ -0,0 +1,21 @@ + + + + + + + {% block title %}Reachy Mini dashboard{% endblock %} + + + {% block extra_js %}{% endblock %} + + + + + +
    + {% block content %}{% endblock %} +
    + + + \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/index.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..36e31060c328409894d0f408477c9b19d81fa7fc --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/index.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} + +{% block content %} + +
    + {% include "sections/daemon.html" %} + {% include "sections/apps.html" %} + {% include "sections/appstore.html" %} + {% include "sections/notification.html" %} +
    +{% endblock %} + +{% block extra_js %} + + + + + + +{% endblock %} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/apps.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/apps.html new file mode 100644 index 0000000000000000000000000000000000000000..d1b4601ea1a537888fcd6e757fc4adf4ab64d82e --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/apps.html @@ -0,0 +1,8 @@ +
    +
    +
    Applications
    +
    +
      +
      +
      +
      \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/appstore.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/appstore.html new file mode 100644 index 0000000000000000000000000000000000000000..2bc25425c2a4a4ea688268f541785d5fadc04cc0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/appstore.html @@ -0,0 +1,29 @@ +
      + + + + +
      Install from 🤗 Hugging Face
      +
      +
        Loading app from 🤗...
      +
      +
      \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/daemon.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/daemon.html new file mode 100644 index 0000000000000000000000000000000000000000..262358448aa6058f864a9ae45cbe5acf584a678c --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/daemon.html @@ -0,0 +1,45 @@ +
      + +
      + +
      +
      +
      +
      Reachy Mini
      + + + + +
      + +
      +
      + + +
      +
      + +
      + {% include 'sections/move_player.html' %} +
      + {% if args.wireless_version %} + + {% endif %} +
      \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/move_player.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/move_player.html new file mode 100644 index 0000000000000000000000000000000000000000..941e6843048a9dea282df7bc403d9af23e80b000 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/move_player.html @@ -0,0 +1,121 @@ +
      +
      +
      Move player
      +
      + + +
      +
      +
      + + +
      +
      + +
      +
      +
      Volume control
      +
      Loading...
      +
      + +
      +
      + + + + + + + + + + + + + + + + 50 +
      + + +
      + + Advanced settings + +
      + +
      +
      +
      Microphone
      +
      Loading...
      +
      +
      + + + + + + + + + + + + + + + + + + 50 +
      +
      +
      +
      +
      +
      diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/notification.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/notification.html new file mode 100644 index 0000000000000000000000000000000000000000..97dd7b9ea461752ad181516368b3d1f31d172fd3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/notification.html @@ -0,0 +1,19 @@ + +
      +
      + + + +
      +
      + + \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/update.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/update.html new file mode 100644 index 0000000000000000000000000000000000000000..e42595a4442f989dcfb6a356b978e89f7bb12768 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/update.html @@ -0,0 +1,54 @@ +
      +
      Reachy Mini Update
      + +
      + + +
      + +
      +
      +
      +
      +
      +
      +
      +
      + +
      + +
      +
      +
      + + + + \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/wifi.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/wifi.html new file mode 100644 index 0000000000000000000000000000000000000000..9d55b418e326c134008b8ec93060902d813e0d54 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/sections/wifi.html @@ -0,0 +1,46 @@ +
      +
      +
      Setup your WiFi
      + +
      + +
      +
      Checking WiFi configuration...
      + +
      + +
      \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/settings.html b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/settings.html new file mode 100644 index 0000000000000000000000000000000000000000..42c83981a3396116e934dc7670cfcec55b7ffcbe --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dashboard/templates/settings.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block content %} + +
      + {% include "sections/update.html" %} + {% include "sections/wifi.html" %} +
      +{% endblock %} + +{% block extra_js %} + + +{% endblock %} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/dependencies.py b/reachy_mini/src/reachy_mini/daemon/app/dependencies.py new file mode 100644 index 0000000000000000000000000000000000000000..8299f7765ee0c17be1da4c12c6e110db853e933b --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/dependencies.py @@ -0,0 +1,41 @@ +"""FastAPI common request dependencies.""" + +from fastapi import HTTPException, Request, WebSocket + +from ...apps.manager import AppManager +from ..backend.abstract import Backend +from ..daemon import Daemon + + +def get_daemon(request: Request) -> Daemon: + """Get the daemon as request dependency.""" + assert isinstance(request.app.state.daemon, Daemon) + return request.app.state.daemon + + +def get_backend(request: Request) -> Backend: + """Get the backend as request dependency.""" + backend = request.app.state.daemon.backend + + if backend is None or not backend.ready.is_set(): + raise HTTPException(status_code=503, detail="Backend not running") + + assert isinstance(backend, Backend) + return backend + + +def get_app_manager(request: Request) -> "AppManager": + """Get the app manager as request dependency.""" + assert isinstance(request.app.state.app_manager, AppManager) + return request.app.state.app_manager + + +def ws_get_backend(websocket: WebSocket) -> Backend: + """Get the backend as websocket dependency.""" + backend = websocket.app.state.daemon.backend + + if backend is None or not backend.ready.is_set(): + raise HTTPException(status_code=503, detail="Backend not running") + + assert isinstance(backend, Backend) + return backend diff --git a/reachy_mini/src/reachy_mini/daemon/app/main.py b/reachy_mini/src/reachy_mini/daemon/app/main.py new file mode 100644 index 0000000000000000000000000000000000000000..a4cfe0be091293832b6f9470f89841559a7b24ce --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/main.py @@ -0,0 +1,347 @@ +"""Daemon entry point for the Reachy Mini robot. + +This script serves as the command-line interface (CLI) entry point for the Reachy Mini daemon. +It initializes the daemon with specified parameters such as simulation mode, serial port, +scene to load, and logging level. The daemon runs indefinitely, handling requests and +managing the robot's state. + +""" + +import argparse +import asyncio +import logging +from contextlib import asynccontextmanager +from dataclasses import dataclass +from pathlib import Path +from typing import AsyncGenerator + +import uvicorn +from fastapi import APIRouter, FastAPI, Request +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates + +from reachy_mini.apps.manager import AppManager +from reachy_mini.daemon.app.routers import ( + apps, + daemon, + kinematics, + motors, + move, + state, + volume, +) +from reachy_mini.daemon.daemon import Daemon + + +@dataclass +class Args: + """Arguments for configuring the Reachy Mini daemon.""" + + log_level: str = "INFO" + + wireless_version: bool = False + + serialport: str = "auto" + hardware_config_filepath: str | None = None + + sim: bool = False + scene: str = "empty" + headless: bool = False + + kinematics_engine: str = "AnalyticalKinematics" + check_collision: bool = False + + autostart: bool = True + timeout_health_check: float | None = None + + wake_up_on_start: bool = True + goto_sleep_on_stop: bool = True + + fastapi_host: str = "0.0.0.0" + fastapi_port: int = 8000 + + localhost_only: bool | None = None + + +def create_app(args: Args, health_check_event: asyncio.Event | None = None) -> FastAPI: + """Create and configure the FastAPI application.""" + localhost_only = ( + args.localhost_only + if args.localhost_only is not None + else (False if args.wireless_version else True) + ) + + @asynccontextmanager + async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: + """Lifespan context manager for the FastAPI application.""" + args = app.state.args # type: Args + + if args.autostart: + await app.state.daemon.start( + serialport=args.serialport, + sim=args.sim, + scene=args.scene, + headless=args.headless, + kinematics_engine=args.kinematics_engine, + check_collision=args.check_collision, + wake_up_on_start=args.wake_up_on_start, + localhost_only=localhost_only, + hardware_config_filepath=args.hardware_config_filepath, + ) + yield + await app.state.app_manager.close() + await app.state.daemon.stop( + goto_sleep_on_stop=args.goto_sleep_on_stop, + ) + + app = FastAPI( + lifespan=lifespan, + ) + + app.state.args = args + app.state.daemon = Daemon(wireless_version=args.wireless_version) + app.state.app_manager = AppManager() + + router = APIRouter(prefix="/api") + router.include_router(apps.router) + router.include_router(daemon.router) + router.include_router(kinematics.router) + router.include_router(motors.router) + router.include_router(move.router) + router.include_router(state.router) + router.include_router(volume.router) + + if args.wireless_version: + from .routers import update, wifi_config + + app.include_router(update.router) + app.include_router(wifi_config.router) + + app.include_router(router) + + if health_check_event is not None: + + @app.post("/health-check") + async def health_check() -> dict[str, str]: + """Health check endpoint to reset the health check timer.""" + health_check_event.set() + return {"status": "ok"} + + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # or restrict to your HF domain + allow_methods=["*"], + allow_headers=["*"], + ) + + STATIC_DIR = Path(__file__).parent / "dashboard" / "static" + TEMPLATES_DIR = Path(__file__).parent / "dashboard" / "templates" + + app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static") + templates = Jinja2Templates(directory=str(TEMPLATES_DIR)) + + @app.get("/") + async def dashboard(request: Request) -> HTMLResponse: + """Render the dashboard.""" + return templates.TemplateResponse( + "index.html", {"request": request, "args": args} + ) + + if args.wireless_version: + + @app.get("/settings") + async def settings(request: Request) -> HTMLResponse: + """Render the settings page.""" + return templates.TemplateResponse("settings.html", {"request": request}) + + return app + + +def run_app(args: Args) -> None: + """Run the FastAPI app with Uvicorn.""" + logging.basicConfig(level=logging.INFO) + + health_check_event = asyncio.Event() + app = create_app(args, health_check_event) + + config = uvicorn.Config(app, host=args.fastapi_host, port=args.fastapi_port) + server = uvicorn.Server(config) + + async def health_check_timeout(timeout_seconds: float) -> None: + while True: + try: + await asyncio.wait_for( + health_check_event.wait(), + timeout=timeout_seconds, + ) + health_check_event.clear() + except asyncio.TimeoutError: + logging.warning("Health check timeout reached, stopping app.") + server.should_exit = True + break + + loop = asyncio.get_event_loop() + if args.timeout_health_check is not None: + loop.create_task(health_check_timeout(args.timeout_health_check)) + + try: + loop.run_until_complete(server.serve()) + except KeyboardInterrupt: + logging.info("Received Ctrl-C, shutting down gracefully.") + finally: + # Optional: additional cleanup here + pass + + +def main() -> None: + """Run the FastAPI app with Uvicorn.""" + default_args = Args() + + parser = argparse.ArgumentParser(description="Run the Reachy Mini daemon.") + parser.add_argument( + "--wireless-version", + action="store_true", + default=default_args.wireless_version, + help="Use the wireless version of Reachy Mini (default: False).", + ) + + # Real robot mode + parser.add_argument( + "-p", + "--serialport", + type=str, + default=default_args.serialport, + help="Serial port for real motors (default: will try to automatically find the port).", + ) + default_hw_config_path = str( + ( + Path(__file__).parent.parent.parent + / "assets" + / "config" + / "hardware_config.yaml" + ).resolve() + ) + parser.add_argument( + "--hardware-config-filepath", + type=str, + default=default_hw_config_path, + help=f"Path to the hardware configuration YAML file (default: {default_hw_config_path}).", + ) + # Simulation mode + parser.add_argument( + "--sim", + action="store_true", + default=default_args.sim, + help="Run in simulation mode using Mujoco.", + ) + parser.add_argument( + "--scene", + type=str, + default=default_args.scene, + help="Name of the scene to load (default: empty)", + ) + parser.add_argument( + "--headless", + action="store_true", + default=default_args.headless, + help="Run the daemon in headless mode (default: False).", + ) + # Daemon options + parser.add_argument( + "--autostart", + action="store_true", + default=default_args.autostart, + help="Automatically start the daemon on launch (default: True).", + ) + parser.add_argument( + "--no-autostart", + action="store_false", + dest="autostart", + help="Do not automatically start the daemon on launch (default: False).", + ) + parser.add_argument( + "--timeout-health-check", + type=float, + default=None, + help="Set the health check timeout in seconds (default: None).", + ) + parser.add_argument( + "--wake-up-on-start", + action="store_true", + default=default_args.wake_up_on_start, + help="Wake up the robot on daemon start (default: True).", + ) + parser.add_argument( + "--no-wake-up-on-start", + action="store_false", + dest="wake_up_on_start", + help="Do not wake up the robot on daemon start (default: False).", + ) + parser.add_argument( + "--goto-sleep-on-stop", + action="store_true", + default=default_args.goto_sleep_on_stop, + help="Put the robot to sleep on daemon stop (default: True).", + ) + parser.add_argument( + "--no-goto-sleep-on-stop", + action="store_false", + dest="goto_sleep_on_stop", + help="Do not put the robot to sleep on daemon stop (default: False).", + ) + # Zenoh server options + parser.add_argument( + "--localhost-only", + action="store_true", + default=default_args.localhost_only, + help="Restrict the server to localhost only (default: True).", + ) + parser.add_argument( + "--no-localhost-only", + action="store_false", + dest="localhost_only", + help="Allow the server to listen on all interfaces (default: False).", + ) + # Kinematics options + parser.add_argument( + "--check-collision", + action="store_true", + default=default_args.check_collision, + help="Enable collision checking (default: False).", + ) + + parser.add_argument( + "--kinematics-engine", + type=str, + default=default_args.kinematics_engine, + choices=["Placo", "NN", "AnalyticalKinematics"], + help="Set the kinematics engine (default: AnalyticalKinematics).", + ) + # FastAPI server options + parser.add_argument( + "--fastapi-host", + type=str, + default=default_args.fastapi_host, + ) + parser.add_argument( + "--fastapi-port", + type=int, + default=default_args.fastapi_port, + ) + # Logging options + parser.add_argument( + "--log-level", + type=str, + default=default_args.log_level, + choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], + help="Set the logging level (default: INFO).", + ) + + args = parser.parse_args() + run_app(Args(**vars(args))) + + +if __name__ == "__main__": + main() diff --git a/reachy_mini/src/reachy_mini/daemon/app/models.py b/reachy_mini/src/reachy_mini/daemon/app/models.py new file mode 100644 index 0000000000000000000000000000000000000000..19a5310afc6431dc76db6e399701f62bc17826d8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/models.py @@ -0,0 +1,149 @@ +"""Common pydantic models definitions.""" + +from datetime import datetime + +import numpy as np +from numpy.typing import NDArray +from pydantic import BaseModel +from scipy.spatial.transform import Rotation as R + +from reachy_mini.daemon.backend.abstract import MotorControlMode + + +class Matrix4x4Pose(BaseModel): + """Represent a 3D pose by its 4x4 transformation matrix (translation is expressed in meters).""" + + m: tuple[ + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + ] + + @classmethod + def from_pose_array(cls, arr: NDArray[np.float64]) -> "Matrix4x4Pose": + """Create a Matrix4x4 pose representation from a 4x4 pose array.""" + assert arr.shape == (4, 4), "Array must be of shape (4, 4)" + m: tuple[ + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + float, + ] = tuple(arr.flatten().tolist()) # type: ignore [assignment] + return cls(m=m) + + def to_pose_array(self) -> NDArray[np.float64]: + """Convert the Matrix4x4Pose to a 4x4 numpy array.""" + return np.array(self.m).reshape((4, 4)) + + +class XYZRPYPose(BaseModel): + """Represent a 3D pose using position (x, y, z) in meters and orientation (roll, pitch, yaw) angles in radians.""" + + x: float = 0.0 + y: float = 0.0 + z: float = 0.0 + roll: float = 0.0 + pitch: float = 0.0 + yaw: float = 0.0 + + @classmethod + def from_pose_array(cls, arr: NDArray[np.float64]) -> "XYZRPYPose": + """Create an XYZRPYPose representation from a 4x4 pose array.""" + assert arr.shape == (4, 4), "Array must be of shape (4, 4)" + + x, y, z = arr[0, 3], arr[1, 3], arr[2, 3] + roll, pitch, yaw = R.from_matrix(arr[:3, :3]).as_euler("xyz") + + return cls( + x=x, + y=y, + z=z, + roll=roll, + pitch=pitch, + yaw=yaw, + ) + + def to_pose_array(self) -> NDArray[np.float64]: + """Convert the XYZRPYPose to a 4x4 numpy array.""" + rotation = R.from_euler("xyz", [self.roll, self.pitch, self.yaw]) + pose_matrix = np.eye(4) + pose_matrix[:3, 3] = [self.x, self.y, self.z] + pose_matrix[:3, :3] = rotation.as_matrix() + return pose_matrix + + +AnyPose = XYZRPYPose | Matrix4x4Pose + + +def as_any_pose(pose: NDArray[np.float64], use_matrix: bool) -> AnyPose: + """Convert a numpy array to an AnyPose representation.""" + return ( + Matrix4x4Pose.from_pose_array(pose) + if use_matrix + else XYZRPYPose.from_pose_array(pose) + ) + + +class FullBodyTarget(BaseModel): + """Represent the full body including the head pose and the joints for antennas.""" + + target_head_pose: AnyPose | None = None + target_antennas: tuple[float, float] | None = None + target_body_yaw: float | None = None + timestamp: datetime | None = None + + model_config = { + "json_schema_extra": { + "examples": [ + { + "target_head_pose": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "roll": 0.0, + "pitch": 0.0, + "yaw": 0.0, + }, + "target_antennas": [0.0, 0.0], + "target_body_yaw": 0.0, + } + ] + } + } + + +class FullState(BaseModel): + """Represent the full state of the robot including all joint positions and poses.""" + + control_mode: MotorControlMode | None = None + head_pose: AnyPose | None = None + head_joints: list[float] | None = None + body_yaw: float | None = None + antennas_position: list[float] | None = None + timestamp: datetime | None = None + passive_joints: list[float] | None = None diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/apps.py b/reachy_mini/src/reachy_mini/daemon/app/routers/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..163b58f5473b15ce93f608f823813f55d8baba07 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/apps.py @@ -0,0 +1,114 @@ +"""Apps router for apps management.""" + +from fastapi import ( + APIRouter, + Depends, + HTTPException, + WebSocket, +) + +from reachy_mini.apps import AppInfo, SourceKind +from reachy_mini.apps.manager import AppManager, AppStatus +from reachy_mini.daemon.app import bg_job_register +from reachy_mini.daemon.app.dependencies import get_app_manager + +router = APIRouter(prefix="/apps") + + +@router.get("/list-available/{source_kind}") +async def list_available_apps( + source_kind: SourceKind, + app_manager: "AppManager" = Depends(get_app_manager), +) -> list[AppInfo]: + """List available apps (including not installed).""" + return await app_manager.list_available_apps(source_kind) + + +@router.get("/list-available") +async def list_all_available_apps( + app_manager: "AppManager" = Depends(get_app_manager), +) -> list[AppInfo]: + """List all available apps (including not installed).""" + return await app_manager.list_all_available_apps() + + +@router.post("/install") +async def install_app( + app_info: AppInfo, + app_manager: "AppManager" = Depends(get_app_manager), +) -> dict[str, str]: + """Install a new app by its info (background, returns job_id).""" + job_id = bg_job_register.run_command( + "install", app_manager.install_new_app, app_info + ) + return {"job_id": job_id} + + +@router.post("/remove/{app_name}") +async def remove_app( + app_name: str, + app_manager: "AppManager" = Depends(get_app_manager), +) -> dict[str, str]: + """Remove an installed app by its name (background, returns job_id).""" + job_id = bg_job_register.run_command("remove", app_manager.remove_app, app_name) + return {"job_id": job_id} + + +@router.get("/job-status/{job_id}") +async def job_status(job_id: str) -> bg_job_register.JobInfo: + """Get status/logs for a job.""" + try: + return bg_job_register.get_info(job_id) + except Exception as e: + raise HTTPException(status_code=404, detail=str(e)) + + +# WebSocket route for live job status/logs +@router.websocket("/ws/apps-manager/{job_id}") +async def ws_apps_manager(websocket: WebSocket, job_id: str) -> None: + """WebSocket route to stream live job status/logs for a job, sending updates as soon as new logs are available.""" + await websocket.accept() + await bg_job_register.ws_poll_info(websocket, job_id) + await websocket.close() + + +@router.post("/start-app/{app_name}") +async def start_app( + app_name: str, + app_manager: "AppManager" = Depends(get_app_manager), +) -> AppStatus: + """Start an app by its name.""" + try: + return await app_manager.start_app(app_name) + except RuntimeError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.post("/restart-current-app") +async def restart_app( + app_manager: "AppManager" = Depends(get_app_manager), +) -> AppStatus: + """Restart the currently running app.""" + try: + return await app_manager.restart_current_app() + except RuntimeError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.post("/stop-current-app") +async def stop_app( + app_manager: "AppManager" = Depends(get_app_manager), +) -> None: + """Stop the currently running app.""" + try: + return await app_manager.stop_current_app() + except RuntimeError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.get("/current-app-status") +async def current_app_status( + app_manager: "AppManager" = Depends(get_app_manager), +) -> AppStatus | None: + """Get the status of the currently running app, if any.""" + return await app_manager.current_app_status() diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/daemon.py b/reachy_mini/src/reachy_mini/daemon/app/routers/daemon.py new file mode 100644 index 0000000000000000000000000000000000000000..3de3be57a431b7029edcb5b2e98b5e38e3c8fc6d --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/daemon.py @@ -0,0 +1,82 @@ +"""Daemon-related API routes.""" + +import logging +import threading + +from fastapi import APIRouter, Depends, HTTPException, Request + +from reachy_mini.daemon.app import bg_job_register + +from ...daemon import Daemon, DaemonStatus +from ..dependencies import get_daemon + +router = APIRouter( + prefix="/daemon", +) +busy_lock = threading.Lock() + + +@router.post("/start") +async def start_daemon( + request: Request, + wake_up: bool, + daemon: Daemon = Depends(get_daemon), +) -> dict[str, str]: + """Start the daemon.""" + if busy_lock.locked(): + raise HTTPException(status_code=409, detail="Daemon is busy.") + + async def start(logger: logging.Logger) -> None: + with busy_lock: + await daemon.start( + sim=request.app.state.args.sim, + serialport=request.app.state.args.serialport, + scene=request.app.state.args.scene, + localhost_only=request.app.state.args.localhost_only, + wake_up_on_start=wake_up, + check_collision=request.app.state.args.check_collision, + kinematics_engine=request.app.state.args.kinematics_engine, + headless=request.app.state.args.headless, + hardware_config_filepath=request.app.state.args.hardware_config_filepath, + ) + + job_id = bg_job_register.run_command("daemon-start", start) + return {"job_id": job_id} + + +@router.post("/stop") +async def stop_daemon( + goto_sleep: bool, daemon: Daemon = Depends(get_daemon) +) -> dict[str, str]: + """Stop the daemon, optionally putting the robot to sleep.""" + if busy_lock.locked(): + raise HTTPException(status_code=409, detail="Daemon is busy.") + + async def stop(logger: logging.Logger) -> None: + with busy_lock: + await daemon.stop(goto_sleep_on_stop=goto_sleep) + + job_id = bg_job_register.run_command("daemon-stop", stop) + return {"job_id": job_id} + + +@router.post("/restart") +async def restart_daemon( + request: Request, daemon: Daemon = Depends(get_daemon) +) -> dict[str, str]: + """Restart the daemon.""" + if busy_lock.locked(): + raise HTTPException(status_code=409, detail="Daemon is busy.") + + async def restart(logger: logging.Logger) -> None: + with busy_lock: + await daemon.restart() + + job_id = bg_job_register.run_command("daemon-restart", restart) + return {"job_id": job_id} + + +@router.get("/status") +async def get_daemon_status(daemon: Daemon = Depends(get_daemon)) -> DaemonStatus: + """Get the current status of the daemon.""" + return daemon.status() diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/kinematics.py b/reachy_mini/src/reachy_mini/daemon/app/routers/kinematics.py new file mode 100644 index 0000000000000000000000000000000000000000..71834eb17ed6e895309d13e267097a33e45ba7c3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/kinematics.py @@ -0,0 +1,57 @@ +"""Kinematics router for handling kinematics-related requests. + +This module defines the API endpoints for interacting with the kinematics +subsystem of the robot. It provides endpoints for retrieving URDF representation, +and other kinematics-related information. +""" + +from pathlib import Path +from typing import Any + +from fastapi import APIRouter, Depends, HTTPException, Response + +from ....daemon.backend.abstract import Backend +from ..dependencies import get_backend + +router = APIRouter( + prefix="/kinematics", +) + +STL_ASSETS_DIR = ( + Path(__file__).parent.parent.parent.parent + / "descriptions" + / "reachy_mini" + / "urdf" + / "assets" +) + + +@router.get("/info") +async def get_kinematics_info( + backend: Backend = Depends(get_backend), +) -> dict[str, Any]: + """Get the current information of the kinematics.""" + return { + "info": { + "engine": backend.kinematics_engine, + "collision check": backend.check_collision, + } + } + + +@router.get("/urdf") +async def get_urdf(backend: Backend = Depends(get_backend)) -> dict[str, str]: + """Get the URDF representation of the robot.""" + return {"urdf": backend.get_urdf()} + + +@router.get("/stl/{filename}") +async def get_stl_file(filename: Path) -> Response: + """Get the path to an STL asset file.""" + file_path = STL_ASSETS_DIR / filename + try: + with open(file_path, "rb") as file: + content = file.read() + return Response(content, media_type="model/stl") + except FileNotFoundError: + raise HTTPException(status_code=404, detail=f"STL file not found {file_path}") diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/motors.py b/reachy_mini/src/reachy_mini/daemon/app/routers/motors.py new file mode 100644 index 0000000000000000000000000000000000000000..0b8b65a115281735f993f7f0f3a2780fb2d39da6 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/motors.py @@ -0,0 +1,41 @@ +"""Motors router. + +Provides endpoints to get and set the motor control mode. +""" + +from fastapi import APIRouter, Depends +from pydantic import BaseModel + +from ....daemon.backend.abstract import Backend, MotorControlMode +from ..dependencies import get_backend + +router = APIRouter( + prefix="/motors", +) + + +class MotorStatus(BaseModel): + """Represents the status of the motors. + + Exposes + - mode: The current motor control mode (enabled, disabled, gravity_compensation). + """ + + mode: MotorControlMode + + +@router.get("/status") +async def get_motor_status(backend: Backend = Depends(get_backend)) -> MotorStatus: + """Get the current status of the motors.""" + return MotorStatus(mode=backend.get_motor_control_mode()) + + +@router.post("/set_mode/{mode}") +async def set_motor_mode( + mode: MotorControlMode, + backend: Backend = Depends(get_backend), +) -> dict[str, str]: + """Set the motor control mode.""" + backend.set_motor_control_mode(mode) + + return {"status": f"motors changed to {mode} mode"} diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/move.py b/reachy_mini/src/reachy_mini/daemon/app/routers/move.py new file mode 100644 index 0000000000000000000000000000000000000000..cebea5fc1534363bd6f8ba2696dffbe531d18501 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/move.py @@ -0,0 +1,261 @@ +"""Movement-related API routes. + +This exposes: +- goto +- play (wake_up, goto_sleep) +- stop running moves +- set_target and streaming set_target +""" + +import asyncio +import json +from enum import Enum +from typing import Any, Coroutine +from uuid import UUID, uuid4 + +import numpy as np +from fastapi import APIRouter, Depends, HTTPException, WebSocket, WebSocketDisconnect +from huggingface_hub.errors import RepositoryNotFoundError +from pydantic import BaseModel + +from reachy_mini.motion.recorded_move import RecordedMoves + +from ....daemon.backend.abstract import Backend +from ..dependencies import get_backend, ws_get_backend +from ..models import AnyPose, FullBodyTarget + +move_tasks: dict[UUID, asyncio.Task[None]] = {} +move_listeners: list[WebSocket] = [] + + +router = APIRouter(prefix="/move") + + +class InterpolationMode(str, Enum): + """Interpolation modes for movement.""" + + # TODO: This should be the same as for the backend + + LINEAR = "linear" + MINJERK = "minjerk" + EASE = "ease" + CARTOON = "cartoon" + + +class GotoModelRequest(BaseModel): + """Request model for the goto endpoint.""" + + head_pose: AnyPose | None = None + antennas: tuple[float, float] | None = None + body_yaw: float | None = None + duration: float + interpolation: InterpolationMode = InterpolationMode.MINJERK + + model_config = { + "json_schema_extra": { + "examples": [ + { + "head_pose": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "roll": 0.0, + "pitch": 0.0, + "yaw": 0.0, + }, + "antennas": [0.0, 0.0], + "body_yaw": 0.0, + "duration": 2.0, + "interpolation": "minjerk", + }, + { + "antennas": [0.0, 0.0], + "duration": 1.0, + "interpolation": "linear", + }, + ], + } + } + + +class MoveUUID(BaseModel): + """Model representing a unique identifier for a move task.""" + + uuid: UUID + + +def create_move_task(coro: Coroutine[Any, Any, None]) -> MoveUUID: + """Create a new move task using async task coroutine.""" + uuid = uuid4() + + async def notify_listeners(message: str, details: str = "") -> None: + for ws in move_listeners: + try: + await ws.send_json( + { + "type": message, + "uuid": str(uuid), + "details": details, + } + ) + except (RuntimeError, WebSocketDisconnect): + move_listeners.remove(ws) + + async def wrap_coro() -> None: + try: + await notify_listeners("move_started") + await coro + await notify_listeners("move_completed") + except Exception as e: + await notify_listeners("move_failed", details=str(e)) + except asyncio.CancelledError: + await notify_listeners("move_cancelled") + finally: + move_tasks.pop(uuid, None) + + task = asyncio.create_task(wrap_coro()) + move_tasks[uuid] = task + + return MoveUUID(uuid=uuid) + + +async def stop_move_task(uuid: UUID) -> dict[str, str]: + """Stop a running move task by cancelling it.""" + if uuid not in move_tasks: + raise KeyError(f"Running move with UUID {uuid} not found") + + task = move_tasks.pop(uuid, None) + assert task is not None + + if task: + if task.cancel(): + try: + await task + except asyncio.CancelledError: + pass + + return { + "message": f"Stopped move with UUID: {uuid}", + } + + +@router.get("/running") +async def get_running_moves() -> list[MoveUUID]: + """Get a list of currently running move tasks.""" + return [MoveUUID(uuid=uuid) for uuid in move_tasks.keys()] + + +@router.post("/goto") +async def goto( + goto_req: GotoModelRequest, backend: Backend = Depends(get_backend) +) -> MoveUUID: + """Request a movement to a specific target.""" + return create_move_task( + backend.goto_target( + head=goto_req.head_pose.to_pose_array() if goto_req.head_pose else None, + antennas=np.array(goto_req.antennas) if goto_req.antennas else None, + body_yaw=goto_req.body_yaw, + duration=goto_req.duration, + ) + ) + + +@router.post("/play/wake_up") +async def play_wake_up(backend: Backend = Depends(get_backend)) -> MoveUUID: + """Request the robot to wake up.""" + return create_move_task(backend.wake_up()) + + +@router.post("/play/goto_sleep") +async def play_goto_sleep(backend: Backend = Depends(get_backend)) -> MoveUUID: + """Request the robot to go to sleep.""" + return create_move_task(backend.goto_sleep()) + + +@router.get("/recorded-move-datasets/list/{dataset_name:path}") +async def list_recorded_move_dataset( + dataset_name: str, +) -> list[str]: + """List available recorded moves in a dataset.""" + try: + moves = RecordedMoves(dataset_name) + except RepositoryNotFoundError as e: + raise HTTPException(status_code=404, detail=str(e)) + + return moves.list_moves() + + +@router.post("/play/recorded-move-dataset/{dataset_name:path}/{move_name}") +async def play_recorded_move_dataset( + dataset_name: str, + move_name: str, + backend: Backend = Depends(get_backend), +) -> MoveUUID: + """Request the robot to play a predefined recorded move from a dataset.""" + try: + recorded_moves = RecordedMoves(dataset_name) + except RepositoryNotFoundError as e: + raise HTTPException(status_code=404, detail=str(e)) + try: + move = recorded_moves.get(move_name) + except ValueError as e: + raise HTTPException(status_code=404, detail=str(e)) + return create_move_task(backend.play_move(move)) + + +@router.post("/stop") +async def stop_move(uuid: MoveUUID) -> dict[str, str]: + """Stop a running move task.""" + return await stop_move_task(uuid.uuid) + + +@router.websocket("/ws/updates") +async def ws_move_updates( + websocket: WebSocket, +) -> None: + """WebSocket route to stream move updates.""" + await websocket.accept() + try: + move_listeners.append(websocket) + while True: + _ = await websocket.receive_text() + except WebSocketDisconnect: + move_listeners.remove(websocket) + + +# --- FullBodyTarget streaming and single set_target --- +@router.post("/set_target") +async def set_target( + target: FullBodyTarget, + backend: Backend = Depends(get_backend), +) -> dict[str, str]: + """POST route to set a single FullBodyTarget.""" + backend.set_target( + head=target.target_head_pose.to_pose_array() + if target.target_head_pose + else None, + antennas=np.array(target.target_antennas) if target.target_antennas else None, + body_yaw=target.target_body_yaw, + ) + return {"status": "ok"} + + +@router.websocket("/ws/set_target") +async def ws_set_target( + websocket: WebSocket, backend: Backend = Depends(ws_get_backend) +) -> None: + """WebSocket route to stream FullBodyTarget set_target calls.""" + await websocket.accept() + try: + while True: + data = await websocket.receive_text() + try: + target = FullBodyTarget.model_validate_json(data) + await set_target(target, backend) + + except Exception as e: + await websocket.send_text( + json.dumps({"status": "error", "detail": str(e)}) + ) + except WebSocketDisconnect: + pass diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/state.py b/reachy_mini/src/reachy_mini/daemon/app/routers/state.py new file mode 100644 index 0000000000000000000000000000000000000000..1ba1aea21a545babf68cf870c6f9d9f2324bc822 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/state.py @@ -0,0 +1,146 @@ +"""State-related API routes. + +This exposes: +- basic get routes to retrieve most common fields +- full state and streaming state updates +""" + +import asyncio +from datetime import datetime, timezone +from typing import Any + +from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect + +from ....daemon.backend.abstract import Backend +from ..dependencies import get_backend, ws_get_backend +from ..models import AnyPose, FullState, as_any_pose + +router = APIRouter(prefix="/state") + + +@router.get("/present_head_pose") +async def get_head_pose( + use_pose_matrix: bool = False, + backend: Backend = Depends(get_backend), +) -> AnyPose: + """Get the present head pose. + + Arguments: + use_pose_matrix (bool): Whether to use the pose matrix representation (4x4 flattened) or the translation + Euler angles representation (x, y, z, roll, pitch, yaw). + backend (Backend): The backend instance. + + Returns: + AnyPose: The present head pose. + + """ + return as_any_pose(backend.get_present_head_pose(), use_pose_matrix) + + +@router.get("/present_body_yaw") +async def get_body_yaw( + backend: Backend = Depends(get_backend), +) -> float: + """Get the present body yaw (in radians).""" + return backend.get_present_body_yaw() + + +@router.get("/present_antenna_joint_positions") +async def get_antenna_joint_positions( + backend: Backend = Depends(get_backend), +) -> tuple[float, float]: + """Get the present antenna joint positions (in radians) - (left, right).""" + pos = backend.get_present_antenna_joint_positions() + assert len(pos) == 2 + return (pos[0], pos[1]) + + +@router.get("/full") +async def get_full_state( + with_control_mode: bool = True, + with_head_pose: bool = True, + with_target_head_pose: bool = False, + with_head_joints: bool = False, + with_target_head_joints: bool = False, + with_body_yaw: bool = True, + with_target_body_yaw: bool = False, + with_antenna_positions: bool = True, + with_target_antenna_positions: bool = False, + with_passive_joints: bool = False, + use_pose_matrix: bool = False, + backend: Backend = Depends(get_backend), +) -> FullState: + """Get the full robot state, with optional fields.""" + result: dict[str, Any] = {} + + if with_control_mode: + result["control_mode"] = backend.get_motor_control_mode().value + + if with_head_pose: + pose = backend.get_present_head_pose() + result["head_pose"] = as_any_pose(pose, use_pose_matrix) + if with_target_head_pose: + target_pose = backend.target_head_pose + assert target_pose is not None + result["target_head_pose"] = as_any_pose(target_pose, use_pose_matrix) + if with_head_joints: + result["head_joints"] = backend.get_present_head_joint_positions() + if with_target_head_joints: + result["target_head_joints"] = backend.target_head_joint_positions + if with_body_yaw: + result["body_yaw"] = backend.get_present_body_yaw() + if with_target_body_yaw: + result["target_body_yaw"] = backend.target_body_yaw + if with_antenna_positions: + result["antennas_position"] = backend.get_present_antenna_joint_positions() + if with_target_antenna_positions: + result["target_antennas_position"] = backend.target_antenna_joint_positions + if with_passive_joints: + joints = backend.get_present_passive_joint_positions() + if joints is not None: + result["passive_joints"] = list(joints.values()) + else: + result["passive_joints"] = None + + result["timestamp"] = datetime.now(timezone.utc) + return FullState.model_validate(result) + + +@router.websocket("/ws/full") +async def ws_full_state( + websocket: WebSocket, + frequency: float = 10.0, + with_head_pose: bool = True, + with_target_head_pose: bool = False, + with_head_joints: bool = False, + with_target_head_joints: bool = False, + with_body_yaw: bool = True, + with_target_body_yaw: bool = False, + with_antenna_positions: bool = True, + with_target_antenna_positions: bool = False, + with_passive_joints: bool = False, + use_pose_matrix: bool = False, + backend: Backend = Depends(ws_get_backend), +) -> None: + """WebSocket endpoint to stream the full state of the robot.""" + await websocket.accept() + period = 1.0 / frequency + + try: + while True: + full_state = await get_full_state( + with_head_pose=with_head_pose, + with_target_head_pose=with_target_head_pose, + with_head_joints=with_head_joints, + with_target_head_joints=with_target_head_joints, + with_body_yaw=with_body_yaw, + with_target_body_yaw=with_target_body_yaw, + with_antenna_positions=with_antenna_positions, + with_target_antenna_positions=with_target_antenna_positions, + with_passive_joints=with_passive_joints, + use_pose_matrix=use_pose_matrix, + backend=backend, + ) + await websocket.send_text(full_state.model_dump_json()) + await asyncio.sleep(period) + except WebSocketDisconnect: + pass diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/update.py b/reachy_mini/src/reachy_mini/daemon/app/routers/update.py new file mode 100644 index 0000000000000000000000000000000000000000..cd2e4bf8f43dd0e8b49e2b8f398634bc92a1a880 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/update.py @@ -0,0 +1,86 @@ +"""Update router for Reachy Mini Daemon API. + +This module provides endpoints to check for updates, start updates, and monitor update status. +""" + +import logging +import threading + +import requests +from fastapi import APIRouter, HTTPException, WebSocket + +from reachy_mini.daemon.app import bg_job_register +from reachy_mini.daemon.app.bg_job_register import JobInfo +from reachy_mini.utils.wireless_version.update import update_reachy_mini +from reachy_mini.utils.wireless_version.update_available import ( + get_local_version, + get_pypi_version, + is_update_available, +) + +router = APIRouter(prefix="/update") +busy_lock = threading.Lock() + + +@router.get("/available") +def available(pre_release: bool = False) -> dict[str, dict[str, dict[str, bool | str]]]: + """Check if an update is available for Reachy Mini Wireless.""" + if busy_lock.locked(): + raise HTTPException(status_code=400, detail="Update is in progress") + + current_version = str(get_local_version("reachy_mini")) + + try: + is_available = is_update_available("reachy_mini", pre_release) + available = str(get_pypi_version("reachy_mini", pre_release)) + except (ConnectionError, requests.exceptions.ConnectionError): + is_available = False + available = "unknown" + + return { + "update": { + "reachy_mini": { + "is_available": is_available, + "current_version": current_version, + "available_version": available, + } + } + } + + +@router.post("/start") +def start_update(pre_release: bool = False) -> dict[str, str]: + """Start the update process for Reachy Mini Wireless version.""" + if busy_lock.locked(): + raise HTTPException(status_code=400, detail="Update already in progress") + + if not is_update_available("reachy_mini", pre_release): + raise HTTPException(status_code=400, detail="No update available") + + async def update_wrapper(logger: logging.Logger) -> None: + with busy_lock: + await update_reachy_mini(pre_release, logger) + + job_uuid = bg_job_register.run_command( + "update_reachy_mini", + update_wrapper, + ) + + return {"job_id": job_uuid} + + +@router.get("/info") +def get_update_info(job_id: str) -> JobInfo: + """Get the info of an update job.""" + try: + return bg_job_register.get_info(job_id) + except ValueError as e: + raise HTTPException(status_code=404, detail=str(e)) + + +@router.websocket("/ws/logs") +async def websocket_logs(websocket: WebSocket, job_id: str) -> None: + """WebSocket endpoint to stream update logs in real time.""" + await websocket.accept() + await bg_job_register.ws_poll_info(websocket, job_id) + await websocket.close() diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/volume.py b/reachy_mini/src/reachy_mini/daemon/app/routers/volume.py new file mode 100644 index 0000000000000000000000000000000000000000..f5099018a39fa13e8a521922d259138786627fc2 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/volume.py @@ -0,0 +1,416 @@ +"""Volume control API routes. + +This exposes: +- get current volume +- set volume +- same for microphone +- play test sound (optional) +""" + +import logging +import platform +import subprocess +from typing import Optional + +from fastapi import APIRouter, Depends, HTTPException +from pydantic import BaseModel, Field + +from reachy_mini.daemon.app.dependencies import get_backend +from reachy_mini.daemon.backend.abstract import Backend + +router = APIRouter(prefix="/volume") +logger = logging.getLogger(__name__) + +# Constants +AUDIO_COMMAND_TIMEOUT = 2 # Timeout in seconds for audio commands + +# Device-specific card names for amixer +DEVICE_CARD_NAMES = { + "reachy_mini_audio": "Audio", # Reachy Mini Audio device + "respeaker": "Array", # Legacy ReSpeaker device + "default": "Audio", # Default to Reachy Mini Audio +} + + +class VolumeRequest(BaseModel): + """Request model for setting volume.""" + + volume: int = Field(..., ge=0, le=100, description="Volume level (0-100)") + + +class VolumeResponse(BaseModel): + """Response model for volume operations.""" + + volume: int + device: str + platform: str + + +class TestSoundResponse(BaseModel): + """Response model for test sound operations.""" + + status: str + message: str + + +def get_current_platform() -> str: + """Get the current platform.""" + system = platform.system() + if system == "Darwin": + return "macOS" + elif system == "Linux": + return "Linux" + else: + return system + + +def detect_audio_device() -> str: + """Detect the current audio output device.""" + system = platform.system() + + if system == "Linux": + # Try to detect if Reachy Mini Audio or legacy Respeaker is available + try: + result = subprocess.run( + ["aplay", "-l"], + capture_output=True, + text=True, + timeout=AUDIO_COMMAND_TIMEOUT, + ) + output_lower = result.stdout.lower() + if "reachy mini audio" in output_lower: + return "reachy_mini_audio" + elif "respeaker" in output_lower: + return "respeaker" + except (subprocess.TimeoutExpired, FileNotFoundError): + pass + return "default" + elif system == "Darwin": + return "system" + else: + return "unknown" + + +def get_linux_card_name() -> str: + """Get the appropriate card name for Linux amixer commands based on detected device.""" + device = detect_audio_device() + return DEVICE_CARD_NAMES.get(device, DEVICE_CARD_NAMES["default"]) + + +# macOS Volume Control + + +def get_volume_macos() -> Optional[int]: + """Get current system volume on macOS.""" + try: + result = subprocess.run( + ["osascript", "-e", "output volume of (get volume settings)"], + capture_output=True, + text=True, + timeout=AUDIO_COMMAND_TIMEOUT, + ) + if result.returncode == 0: + return int(result.stdout.strip()) + except (subprocess.TimeoutExpired, FileNotFoundError, ValueError) as e: + logger.error(f"Failed to get macOS volume: {e}") + return None + + +def set_volume_macos(volume: int) -> bool: + """Set system volume on macOS using osascript.""" + try: + subprocess.run( + ["osascript", "-e", f"set volume output volume {volume}"], + capture_output=True, + timeout=AUDIO_COMMAND_TIMEOUT, + check=True, + ) + return True + except ( + subprocess.TimeoutExpired, + FileNotFoundError, + subprocess.CalledProcessError, + ) as e: + logger.error(f"Failed to set macOS volume: {e}") + return False + + +# Linux Volume Control + + +def get_volume_linux() -> Optional[int]: + """Get current volume on Linux using amixer.""" + card_name = get_linux_card_name() + try: + result = subprocess.run( + ["amixer", "-c", card_name, "sget", "PCM"], + capture_output=True, + text=True, + timeout=AUDIO_COMMAND_TIMEOUT, + ) + if result.returncode == 0: + # Parse output to extract volume percentage + for line in result.stdout.splitlines(): + if "Left:" in line and "[" in line: + # Extract percentage between brackets + parts = line.split("[") + for part in parts: + if "%" in part: + volume_str = part.split("%")[0] + return int(volume_str) + except (subprocess.TimeoutExpired, FileNotFoundError, ValueError) as e: + logger.error(f"Failed to get Linux volume: {e}") + return None + + +def set_volume_linux(volume: int) -> bool: + """Set current volume on Linux using amixer.""" + card_name = get_linux_card_name() + try: + subprocess.run( + ["amixer", "-c", card_name, "sset", "PCM", f"{volume}%"], + capture_output=True, + text=True, + timeout=AUDIO_COMMAND_TIMEOUT, + check=True, + ) + return True + except ( + subprocess.TimeoutExpired, + FileNotFoundError, + subprocess.CalledProcessError, + ValueError, + ) as e: + logger.error(f"Failed to set Linux volume: {e}") + return False + + +# API Endpoints - Speaker Volume + + +@router.get("/current") +async def get_volume() -> VolumeResponse: + """Get the current volume level.""" + system = get_current_platform() + device = detect_audio_device() + + volume = None + if system == "macOS": + volume = get_volume_macos() + elif system == "Linux": + volume = get_volume_linux() + + if volume is None: + raise HTTPException(status_code=500, detail="Failed to get volume") + + return VolumeResponse(volume=volume, device=device, platform=system) + + +@router.post("/set") +async def set_volume( + volume_req: VolumeRequest, + backend: Backend = Depends(get_backend), +) -> VolumeResponse: + """Set the volume level and play a test sound.""" + system = get_current_platform() + device = detect_audio_device() + + success = False + if system == "macOS": + success = set_volume_macos(volume_req.volume) + elif system == "Linux": + success = set_volume_linux(volume_req.volume) + else: + raise HTTPException( + status_code=501, + detail=f"Volume control not supported on {system}", + ) + + if not success: + raise HTTPException(status_code=500, detail="Failed to set volume") + + # Play test sound + test_sound = "impatient1.wav" + if backend.audio: + try: + backend.audio.play_sound(test_sound, autoclean=True) + except Exception as e: + msg = str(e).lower() + if "device unavailable" in msg or "-9985" in msg: + logger.warning( + "Test sound not played: audio device busy (likely GStreamer): %s", + e, + ) + else: + logger.warning("Failed to play test sound: %s", e) + else: + logger.warning("No audio backend available, skipping test sound.") + + return VolumeResponse(volume=volume_req.volume, device=device, platform=system) + + +@router.post("/test-sound") +async def play_test_sound(backend: Backend = Depends(get_backend)) -> TestSoundResponse: + """Play a test sound.""" + test_sound = "impatient1.wav" + + if not backend.audio: + raise HTTPException(status_code=503, detail="Audio device not available") + + try: + backend.audio.play_sound(test_sound, autoclean=True) + return TestSoundResponse(status="ok", message="Test sound played") + except Exception as e: + msg = str(e).lower() + + # Special-case ALSA / PortAudio device-busy situation + if "device unavailable" in msg or "-9985" in msg: + logger.warning( + "Test sound request while audio device is busy (likely GStreamer): %s", + e, + ) + # Still 200, but tell the caller it was skipped + return TestSoundResponse( + status="busy", + message="Audio device is currently in use, test sound was skipped.", + ) + + # Any other error is treated as a real failure + logger.error("Failed to play test sound: %s", e, exc_info=True) + raise HTTPException( + status_code=500, + detail="Failed to play test sound (see logs for details)", + ) + + +# macOS Microphone Control + + +def get_microphone_volume_macos() -> Optional[int]: + """Get current microphone input volume on macOS.""" + try: + result = subprocess.run( + ["osascript", "-e", "input volume of (get volume settings)"], + capture_output=True, + text=True, + timeout=AUDIO_COMMAND_TIMEOUT, + ) + if result.returncode == 0: + return int(result.stdout.strip()) + except (subprocess.TimeoutExpired, FileNotFoundError, ValueError) as e: + logger.error(f"Failed to get macOS microphone volume: {e}") + return None + + +def set_microphone_volume_macos(volume: int) -> bool: + """Set microphone input volume on macOS using osascript.""" + try: + subprocess.run( + ["osascript", "-e", f"set volume input volume {volume}"], + capture_output=True, + timeout=AUDIO_COMMAND_TIMEOUT, + check=True, + ) + return True + except ( + subprocess.TimeoutExpired, + FileNotFoundError, + subprocess.CalledProcessError, + ) as e: + logger.error(f"Failed to set macOS microphone volume: {e}") + return False + + +# Linux Microphone Control + + +def get_microphone_volume_linux() -> Optional[int]: + """Get current microphone input volume on Linux using amixer.""" + card_name = get_linux_card_name() + try: + result = subprocess.run( + ["amixer", "-c", card_name, "sget", "Headset"], + capture_output=True, + text=True, + timeout=AUDIO_COMMAND_TIMEOUT, + ) + if result.returncode == 0: + # Parse output to extract volume percentage + for line in result.stdout.splitlines(): + if "Left:" in line and "[" in line: + parts = line.split("[") + for part in parts: + if "%" in part: + volume_str = part.split("%")[0] + return int(volume_str) + except (subprocess.TimeoutExpired, FileNotFoundError, ValueError) as e: + logger.error(f"Failed to get Linux microphone volume: {e}") + return None + + +def set_microphone_volume_linux(volume: int) -> bool: + """Set microphone input volume on Linux using amixer.""" + card_name = get_linux_card_name() + try: + subprocess.run( + ["amixer", "-c", card_name, "sset", "Headset", f"{volume}%"], + capture_output=True, + text=True, + timeout=AUDIO_COMMAND_TIMEOUT, + check=True, + ) + return True + except ( + subprocess.TimeoutExpired, + FileNotFoundError, + subprocess.CalledProcessError, + ValueError, + ) as e: + logger.error(f"Failed to set Linux microphone volume: {e}") + return False + + +# API Endpoints - Microphone Volume + + +@router.get("/microphone/current") +async def get_microphone_volume() -> VolumeResponse: + """Get the current microphone input volume level.""" + system = get_current_platform() + device = detect_audio_device() + + volume = None + if system == "macOS": + volume = get_microphone_volume_macos() + elif system == "Linux": + volume = get_microphone_volume_linux() + + if volume is None: + raise HTTPException(status_code=500, detail="Failed to get microphone volume") + + return VolumeResponse(volume=volume, device=device, platform=system) + + +@router.post("/microphone/set") +async def set_microphone_volume( + volume_req: VolumeRequest, +) -> VolumeResponse: + """Set the microphone input volume level.""" + system = get_current_platform() + device = detect_audio_device() + + success = False + if system == "macOS": + success = set_microphone_volume_macos(volume_req.volume) + elif system == "Linux": + success = set_microphone_volume_linux(volume_req.volume) + else: + raise HTTPException( + status_code=501, + detail=f"Microphone volume control not supported on {system}", + ) + + if not success: + raise HTTPException(status_code=500, detail="Failed to set microphone volume") + + return VolumeResponse(volume=volume_req.volume, device=device, platform=system) diff --git a/reachy_mini/src/reachy_mini/daemon/app/routers/wifi_config.py b/reachy_mini/src/reachy_mini/daemon/app/routers/wifi_config.py new file mode 100644 index 0000000000000000000000000000000000000000..0285ecd3465c22a00ca86840f0180cf4768b89ff --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/routers/wifi_config.py @@ -0,0 +1,219 @@ +"""WiFi Configuration Routers.""" + +import logging +from enum import Enum +from threading import Lock, Thread + +import nmcli +from fastapi import APIRouter, HTTPException +from pydantic import BaseModel + +HOTSPOT_SSID = "reachy-mini-ap" +HOTSPOT_PASSWORD = "reachy-mini" + + +router = APIRouter( + prefix="/wifi", +) + +busy_lock = Lock() +error: Exception | None = None +logger = logging.getLogger(__name__) + + +class WifiMode(Enum): + """WiFi possible modes.""" + + HOTSPOT = "hotspot" + WLAN = "wlan" + DISCONNECTED = "disconnected" + BUSY = "busy" + + +class WifiStatus(BaseModel): + """WiFi status model.""" + + mode: WifiMode + known_networks: list[str] + connected_network: str | None + + +def get_current_wifi_mode() -> WifiMode: + """Get the current WiFi mode.""" + if busy_lock.locked(): + return WifiMode.BUSY + + conn = get_wifi_connections() + if check_if_connection_active("Hotspot"): + return WifiMode.HOTSPOT + elif any(c.device != "--" for c in conn): + return WifiMode.WLAN + else: + return WifiMode.DISCONNECTED + + +@router.get("/status") +def get_wifi_status() -> WifiStatus: + """Get the current WiFi status.""" + mode = get_current_wifi_mode() + + connections = get_wifi_connections() + known_networks = [c.name for c in connections if c.name != "Hotspot"] + + connected_network = next((c.name for c in connections if c.device != "--"), None) + + return WifiStatus( + mode=mode, + known_networks=known_networks, + connected_network=connected_network, + ) + + +@router.get("/error") +def get_last_wifi_error() -> dict[str, str | None]: + """Get the last WiFi error.""" + global error + if error is None: + return {"error": None} + return {"error": str(error)} + + +@router.post("/reset_error") +def reset_last_wifi_error() -> dict[str, str]: + """Reset the last WiFi error.""" + global error + error = None + return {"status": "ok"} + + +@router.post("/setup_hotspot") +def setup_hotspot( + ssid: str = HOTSPOT_SSID, + password: str = HOTSPOT_PASSWORD, +) -> None: + """Set up a WiFi hotspot. It will create a new hotspot using nmcli if one does not already exist.""" + if busy_lock.locked(): + raise HTTPException(status_code=409, detail="Another operation is in progress.") + + def hotspot() -> None: + with busy_lock: + setup_wifi_connection( + name="Hotspot", ssid=ssid, password=password, is_hotspot=True + ) + + Thread(target=hotspot).start() + # TODO: wait for it to be really started + + +@router.post("/connect") +def connect_to_wifi_network( + ssid: str, + password: str, +) -> None: + """Connect to a WiFi network. It will create a new connection using nmcli if the specified SSID is not already configured.""" + logger.warning(f"Request to connect to WiFi network '{ssid}' received.") + + if busy_lock.locked(): + raise HTTPException(status_code=409, detail="Another operation is in progress.") + + def connect() -> None: + global error + with busy_lock: + try: + error = None + setup_wifi_connection(name=ssid, ssid=ssid, password=password) + except Exception as e: + error = e + logger.error(f"Failed to connect to WiFi network '{ssid}': {e}") + logger.info("Reverting to hotspot...") + remove_connection(name=ssid) + setup_wifi_connection( + name="Hotspot", + ssid=HOTSPOT_SSID, + password=HOTSPOT_PASSWORD, + is_hotspot=True, + ) + + Thread(target=connect).start() + # TODO: wait for it to be really connected + + +@router.post("/scan_and_list") +def scan_wifi() -> list[str]: + """Scan for available WiFi networks ordered by signal power.""" + wifi = scan_available_wifi() + + seen = set() + ssids = [x.ssid for x in wifi if x.ssid not in seen and not seen.add(x.ssid)] # type: ignore + + return ssids + + +# NMCLI WRAPPERS +def scan_available_wifi() -> list[nmcli.data.device.DeviceWifi]: + """Scan for available WiFi networks.""" + nmcli.device.wifi_rescan() + devices: list[nmcli.data.device.DeviceWifi] = nmcli.device.wifi() + return devices + + +def get_wifi_connections() -> list[nmcli.data.connection.Connection]: + """Get the list of WiFi connection.""" + return [conn for conn in nmcli.connection() if conn.conn_type == "wifi"] + + +def check_if_connection_exists(name: str) -> bool: + """Check if a WiFi connection with the given SSID already exists.""" + return any(c.name == name for c in get_wifi_connections()) + + +def check_if_connection_active(name: str) -> bool: + """Check if a WiFi connection with the given SSID is currently active.""" + return any(c.name == name and c.device != "--" for c in get_wifi_connections()) + + +def setup_wifi_connection( + name: str, ssid: str, password: str, is_hotspot: bool = False +) -> None: + """Set up a WiFi connection using nmcli.""" + logger.info(f"Setting up WiFi connection (ssid='{ssid}')...") + + if not check_if_connection_exists(name): + logger.info("WiFi configuration does not exist. Creating...") + if is_hotspot: + nmcli.device.wifi_hotspot(ssid=ssid, password=password) + else: + nmcli.device.wifi_connect(ssid=ssid, password=password) + return + + logger.info("WiFi configuration already exists.") + if not check_if_connection_active(name): + logger.info("WiFi is not active. Activating...") + nmcli.connection.up(name) + return + + logger.info(f"Connection {name} is already active.") + + +def remove_connection(name: str) -> None: + """Remove a WiFi connection using nmcli.""" + if check_if_connection_exists(name): + logger.info(f"Removing WiFi connection '{name}'...") + nmcli.connection.delete(name) + + +# Setup WiFi connection on startup + +# This make sure the wlan0 is up and running +scan_available_wifi() + +# On startup, if no WiFi connection is active, set up the default hotspot +if get_current_wifi_mode() == WifiMode.DISCONNECTED: + logger.info("No WiFi connection active. Setting up hotspot...") + + setup_wifi_connection( + name="Hotspot", + ssid=HOTSPOT_SSID, + password=HOTSPOT_PASSWORD, + is_hotspot=True, + ) diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/__init__.py b/reachy_mini/src/reachy_mini/daemon/app/services/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c7775ec9a514eec1cf24d26c0f68f3bea568da78 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/__init__.py @@ -0,0 +1 @@ +"""Services package.""" diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py new file mode 100644 index 0000000000000000000000000000000000000000..15dc4399e353b7eff49c5dac9e95283fa0a12ac3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py @@ -0,0 +1,454 @@ +#!/usr/bin/env python3 +"""Bluetooth service for Reachy Mini using direct DBus API. + +Includes a fixed NoInputNoOutput agent for automatic Just Works pairing. +""" +# mypy: ignore-errors + +import logging +import os +import subprocess +from typing import Callable + +import dbus +import dbus.mainloop.glib +import dbus.service +from gi.repository import GLib + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# Service and Characteristic UUIDs +SERVICE_UUID = "12345678-1234-5678-1234-56789abcdef0" +COMMAND_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef1" +RESPONSE_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef2" + +BLUEZ_SERVICE_NAME = "org.bluez" +GATT_MANAGER_IFACE = "org.bluez.GattManager1" +DBUS_OM_IFACE = "org.freedesktop.DBus.ObjectManager" +DBUS_PROP_IFACE = "org.freedesktop.DBus.Properties" +GATT_SERVICE_IFACE = "org.bluez.GattService1" +GATT_CHRC_IFACE = "org.bluez.GattCharacteristic1" +LE_ADVERTISING_MANAGER_IFACE = "org.bluez.LEAdvertisingManager1" +LE_ADVERTISEMENT_IFACE = "org.bluez.LEAdvertisement1" +AGENT_PATH = "/org/bluez/agent" + + +# ======================= +# BLE Agent for Just Works +# ======================= +class NoInputAgent(dbus.service.Object): + """BLE Agent for Just Works pairing.""" + + @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="") + def Release(self, *args): + """Handle release of the agent.""" + logger.info("Agent released") + + @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="s") + def RequestPinCode(self, *args): + """Automatically provide an empty pin code for Just Works pairing.""" + logger.info(f"RequestPinCode called with args: {args}, returning empty") + return "" + + @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="u") + def RequestPasskey(self, *args): + """Automatically provide a passkey of 0 for Just Works pairing.""" + logger.info(f"RequestPasskey called with args: {args}, returning 0") + return dbus.UInt32(0) + + @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="") + def RequestConfirmation(self, *args): + """Automatically confirm the pairing request.""" + logger.info( + f"RequestConfirmation called with args: {args}, accepting automatically" + ) + return + + @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="") + def DisplayPinCode(self, *args): + """Handle displaying the pin code (not used in Just Works).""" + logger.info(f"DisplayPinCode called with args: {args}") + + @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="") + def DisplayPasskey(self, *args): + """Handle displaying the passkey (not used in Just Works).""" + logger.info(f"DisplayPasskey called with args: {args}") + + @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="") + def AuthorizeService(self, *args): + """Handle service authorization requests.""" + logger.info(f"AuthorizeService called with args: {args}") + + @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="") + def Cancel(self, *args): + """Handle cancellation of the agent request.""" + logger.info("Agent request canceled") + + +# ======================= +# BLE Advertisement +# ======================= +class Advertisement(dbus.service.Object): + """BLE Advertisement.""" + + PATH_BASE = "/org/bluez/advertisement" + + def __init__(self, bus, index, advertising_type, local_name): + """Initialize the Advertisement.""" + self.path = self.PATH_BASE + str(index) + self.bus = bus + self.ad_type = advertising_type + self.local_name = local_name + self.service_uuids = None + self.include_tx_power = False + dbus.service.Object.__init__(self, bus, self.path) + + def get_properties(self): + """Return the properties of the advertisement.""" + props = {"Type": self.ad_type} + if self.local_name: + props["LocalName"] = dbus.String(self.local_name) + if self.service_uuids: + props["ServiceUUIDs"] = dbus.Array(self.service_uuids, signature="s") + props["Appearance"] = dbus.UInt16(0x0000) + props["Duration"] = dbus.UInt16(0) + props["Timeout"] = dbus.UInt16(0) + return {LE_ADVERTISEMENT_IFACE: props} + + def get_path(self): + """Return the object path.""" + return dbus.ObjectPath(self.path) + + @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}") + def GetAll(self, interface): + """Return all properties of the advertisement.""" + if interface != LE_ADVERTISEMENT_IFACE: + raise dbus.exceptions.DBusException( + "org.freedesktop.DBus.Error.InvalidArgs", + "Unknown interface " + interface, + ) + return self.get_properties()[LE_ADVERTISEMENT_IFACE] + + @dbus.service.method(LE_ADVERTISEMENT_IFACE, in_signature="", out_signature="") + def Release(self): + """Handle release of the advertisement.""" + logger.info("Advertisement released") + + +# ======================= +# BLE Characteristics & Service +# ======================= +class Characteristic(dbus.service.Object): + """GATT Characteristic.""" + + def __init__(self, bus, index, uuid, flags, service): + """Initialize the Characteristic.""" + self.path = service.path + "/char" + str(index) + self.bus = bus + self.uuid = uuid + self.service = service + self.flags = flags + self.value = [] + dbus.service.Object.__init__(self, bus, self.path) + + def get_properties(self): + """Return the properties of the characteristic.""" + return { + GATT_CHRC_IFACE: { + "Service": self.service.get_path(), + "UUID": self.uuid, + "Flags": self.flags, + } + } + + def get_path(self): + """Return the object path.""" + return dbus.ObjectPath(self.path) + + @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}") + def GetAll(self, interface): + """Return all properties of the characteristic.""" + if interface != GATT_CHRC_IFACE: + raise dbus.exceptions.DBusException( + "org.freedesktop.DBus.Error.InvalidArgs", "Unknown interface" + ) + return self.get_properties()[GATT_CHRC_IFACE] + + @dbus.service.method(GATT_CHRC_IFACE, in_signature="a{sv}", out_signature="ay") + def ReadValue(self, options): + """Handle read from the characteristic.""" + return dbus.Array(self.value, signature="y") + + @dbus.service.method(GATT_CHRC_IFACE, in_signature="aya{sv}") + def WriteValue(self, value, options): + """Handle write to the characteristic.""" + self.value = value + + +class CommandCharacteristic(Characteristic): + """Command Characteristic.""" + + def __init__(self, bus, index, service, command_handler: Callable[[bytes], str]): + """Initialize the Command Characteristic.""" + super().__init__(bus, index, COMMAND_CHAR_UUID, ["write"], service) + self.command_handler = command_handler + + def WriteValue(self, value, options): + """Handle write to the Command Characteristic.""" + command_bytes = bytes(value) + response = self.command_handler(command_bytes) + self.service.response_char.value = [ + dbus.Byte(b) for b in response.encode("utf-8") + ] + logger.info(f"Command received: {response}") + + +class ResponseCharacteristic(Characteristic): + """Response Characteristic.""" "" + + def __init__(self, bus, index, service): + """Initialize the Response Characteristic.""" + super().__init__(bus, index, RESPONSE_CHAR_UUID, ["read", "notify"], service) + + +class Service(dbus.service.Object): + """GATT Service.""" + + PATH_BASE = "/org/bluez/service" + + def __init__( + self, bus, index, uuid, primary, command_handler: Callable[[bytes], str] + ): + """Initialize the GATT Service.""" + self.path = self.PATH_BASE + str(index) + self.bus = bus + self.uuid = uuid + self.primary = primary + self.characteristics = [] + dbus.service.Object.__init__(self, bus, self.path) + # Response characteristic first + self.response_char = ResponseCharacteristic(bus, 1, self) + self.add_characteristic(self.response_char) + # Command characteristic + self.add_characteristic(CommandCharacteristic(bus, 0, self, command_handler)) + + def get_properties(self): + """Return the properties of the service.""" + return { + GATT_SERVICE_IFACE: { + "UUID": self.uuid, + "Primary": self.primary, + "Characteristics": [ch.get_path() for ch in self.characteristics], + } + } + + def get_path(self): + """Return the object path.""" + return dbus.ObjectPath(self.path) + + def add_characteristic(self, ch): + """Add a characteristic to the service.""" + self.characteristics.append(ch) + + @dbus.service.method(DBUS_PROP_IFACE, in_signature="s", out_signature="a{sv}") + def GetAll(self, interface): + """Return all properties of the service.""" + if interface != GATT_SERVICE_IFACE: + raise dbus.exceptions.DBusException( + "org.freedesktop.DBus.Error.InvalidArgs", "Unknown interface" + ) + return self.get_properties()[GATT_SERVICE_IFACE] + + +class Application(dbus.service.Object): + """GATT Application.""" + + def __init__(self, bus, command_handler: Callable[[bytes], str]): + """Initialize the GATT Application.""" + self.path = "/" + self.services = [] + dbus.service.Object.__init__(self, bus, self.path) + self.services.append(Service(bus, 0, SERVICE_UUID, True, command_handler)) + + def get_path(self): + """Return the object path.""" + return dbus.ObjectPath(self.path) + + @dbus.service.method(DBUS_OM_IFACE, out_signature="a{oa{sa{sv}}}") + def GetManagedObjects(self): + """Return a dictionary of all managed objects.""" + resp = {} + for service in self.services: + resp[service.get_path()] = service.get_properties() + for ch in service.characteristics: + resp[ch.get_path()] = ch.get_properties() + return resp + + +# ======================= +# Bluetooth Command Server +# ======================= +class BluetoothCommandService: + """Bluetooth Command Service.""" + + def __init__(self, device_name="ReachyMini", pin_code="00000"): + """Initialize the Bluetooth Command Service.""" + self.device_name = device_name + self.pin_code = pin_code + self.connected = False + self.bus = None + self.app = None + self.adv = None + self.mainloop = None + + def _handle_command(self, value: bytes) -> str: + command_str = value.decode("utf-8").strip() + logger.info(f"Received command: {command_str}") + # Custom command handling + if command_str.upper() == "PING": + return "PONG" + elif command_str.upper() == "STATUS": + # exec a "sudo ls" command and print the result + try: + result = subprocess.run(["sudo", "ls"], capture_output=True, text=True) + logger.info(f"Command output: {result.stdout}") + except Exception as e: + logger.error(f"Error executing command: {e}") + return "OK: System running" + elif command_str.startswith("PIN_"): + pin = command_str[4:].strip() + if pin == self.pin_code: + self.connected = True + return "OK: Connected" + else: + return "ERROR: Incorrect PIN" + + # else if command starts with "CMD_xxxxx" check if commands directory contains the said named script command xxxx.sh and run its, show output or/and send to read + elif command_str.startswith("CMD_"): + if not self.connected: + return "ERROR: Not connected. Please authenticate first." + try: + script_name = command_str[4:].strip() + ".sh" + script_path = os.path.join("commands", script_name) + if os.path.isfile(script_path): + try: + result = subprocess.run( + ["sudo", script_path], capture_output=True, text=True + ) + logger.info(f"Command output: {result.stdout}") + except Exception as e: + logger.error(f"Error executing command: {e}") + else: + return f"ERROR: Command '{script_name}' not found" + except Exception as e: + logger.error(f"Error processing command: {e}") + return "ERROR: Command execution failed" + finally: + self.connected = False # reset connection after command + else: + return f"ECHO: {command_str}" + + def start(self): + """Start the Bluetooth Command Service.""" + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + + # BLE Agent registration + agent_manager = dbus.Interface( + self.bus.get_object("org.bluez", "/org/bluez"), "org.bluez.AgentManager1" + ) + # agent = NoInputAgent(self.bus, AGENT_PATH) + agent_manager.RegisterAgent(AGENT_PATH, "NoInputNoOutput") + agent_manager.RequestDefaultAgent(AGENT_PATH) + logger.info("BLE Agent registered for Just Works pairing") + + # Find adapter + adapter = self._find_adapter() + if not adapter: + raise Exception("Bluetooth adapter not found") + + adapter_props = dbus.Interface(adapter, DBUS_PROP_IFACE) + adapter_props.Set("org.bluez.Adapter1", "Powered", dbus.Boolean(True)) + adapter_props.Set("org.bluez.Adapter1", "Discoverable", dbus.Boolean(True)) + adapter_props.Set("org.bluez.Adapter1", "DiscoverableTimeout", dbus.UInt32(0)) + adapter_props.Set("org.bluez.Adapter1", "Pairable", dbus.Boolean(True)) + + # Register GATT application + service_manager = dbus.Interface(adapter, GATT_MANAGER_IFACE) + self.app = Application(self.bus, self._handle_command) + service_manager.RegisterApplication( + self.app.get_path(), + {}, + reply_handler=lambda: logger.info("GATT app registered"), + error_handler=lambda e: logger.error(f"Failed to register GATT app: {e}"), + ) + + # Register advertisement + ad_manager = dbus.Interface(adapter, LE_ADVERTISING_MANAGER_IFACE) + self.adv = Advertisement(self.bus, 0, "peripheral", self.device_name) + self.adv.service_uuids = [SERVICE_UUID] + ad_manager.RegisterAdvertisement( + self.adv.get_path(), + {}, + reply_handler=lambda: logger.info("Advertisement registered"), + error_handler=lambda e: logger.error( + f"Failed to register advertisement: {e}" + ), + ) + + logger.info(f"✓ Bluetooth service started as '{self.device_name}'") + + def _find_adapter(self): + remote_om = dbus.Interface( + self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE + ) + objects = remote_om.GetManagedObjects() + for path, props in objects.items(): + if GATT_MANAGER_IFACE in props and LE_ADVERTISING_MANAGER_IFACE in props: + return self.bus.get_object(BLUEZ_SERVICE_NAME, path) + return None + + def run(self): + """Run the Bluetooth Command Service.""" + self.start() + self.mainloop = GLib.MainLoop() + try: + logger.info("Running. Press Ctrl+C to exit...") + self.mainloop.run() + except KeyboardInterrupt: + logger.info("Shutting down...") + self.mainloop.quit() + + +def get_pin() -> str: + """Extract the last 5 digits of the serial number from dfu-util -l output.""" + default_pin = "46879" + try: + result = subprocess.run(["dfu-util", "-l"], capture_output=True, text=True) + lines = result.stdout.splitlines() + for line in lines: + if "serial=" in line: + # Extract serial number + serial_part = line.split("serial=")[-1].strip().strip('"') + if len(serial_part) >= 5: + return serial_part[-5:] + return default_pin # fallback if not found + except Exception as e: + logger.error(f"Error getting pin from serial: {e}") + return default_pin + + +# ======================= +# Main +# ======================= +def main(): + """Run the Bluetooth Command Service.""" + pin = get_pin() + + bt_service = BluetoothCommandService(device_name="ReachyMini", pin_code=pin) + bt_service.run() + + +if __name__ == "__main__": + main() diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/HOTSPOT.sh b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/HOTSPOT.sh new file mode 100755 index 0000000000000000000000000000000000000000..7d64481da27f96028ee3e2dbbeca1dfcd3b13cc0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/HOTSPOT.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +nmcli device disconnect wlan0 +sleep 5 +rfkill unblock wifi +systemctl restart reachy-mini-daemon.service + diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/RESTART_DAEMON.sh b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/RESTART_DAEMON.sh new file mode 100755 index 0000000000000000000000000000000000000000..3cf28b38a4c0336e2a8825697277d331d6f86424 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/RESTART_DAEMON.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + + systemctl restart reachy-mini-daemon.service + diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/SOFTWARE_RESET.sh b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/SOFTWARE_RESET.sh new file mode 100755 index 0000000000000000000000000000000000000000..d1ae109a34171fe99dc31cb57a668651f802b41d --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/commands/SOFTWARE_RESET.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +rm -rf /venvs/ +cp -r /restore/venvs/ / +chown -R pollen:pollen /venvs +systemctl restart reachy-mini-daemon.service + diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/install_service_bluetooth.sh b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/install_service_bluetooth.sh new file mode 100755 index 0000000000000000000000000000000000000000..fcd3ae24f495dab909787ebe6e7de9273b6e3034 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/bluetooth/install_service_bluetooth.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +SERVICE_NAME="reachy-mini-bluetooth" +SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" +LAUNCHER_PATH="$SCRIPT_DIR/bluetooth_service.py" +COMMANDS_DIR="$SCRIPT_DIR/commands" +SERVICE_PATH=/bluetooth/bluetooth_service.py + +sudo cp "$LAUNCHER_PATH" "$SERVICE_PATH" +sudo cp -r "$COMMANDS_DIR" /bluetooth/commands +# Ensure Python script is executable +sudo chmod +x "$SERVICE_PATH" + +# Create the systemd service file +cat < /dev/null +[Unit] +Description=Reachy Mini Bluetooth GATT Service +After=network.target bluetooth.target +Requires=bluetooth.target + +[Service] +Type=simple +ExecStart=/bin/bash -c 'sudo /usr/sbin/rfkill unblock bluetooth && sleep 2 && /usr/bin/python3 /bluetooth/bluetooth_service.py' +Restart=on-failure +User=$(whoami) +WorkingDirectory=$(dirname "$SERVICE_PATH") + +[Install] +WantedBy=multi-user.target +EOF + +# Reload systemd, enable and start the service +sudo systemctl daemon-reload +sudo systemctl enable --now "$SERVICE_NAME" + +echo "Service '$SERVICE_NAME' installed and started." diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/__init__.py b/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b912651bde9762e02f4e3d332d9881f1fd9bd7b0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/__init__.py @@ -0,0 +1 @@ +"""GPIO shutdown service package.""" diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/install_service.sh b/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/install_service.sh new file mode 100644 index 0000000000000000000000000000000000000000..4d8e10fa9b2fe7d13ac0bee48a3bca255e1c94f2 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/install_service.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +SERVICE_NAME="gpio-shutdown-daemon" +SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" +LAUNCHER_PATH="$SCRIPT_DIR/launcher.sh" + +# Create the service file +cat < /dev/null +[Unit] +Description=Reachy Mini GPIO Shutdown Daemon +After=multi-user.target + +[Service] +Type=simple +ExecStart=$LAUNCHER_PATH +Restart=on-failure +User=$(whoami) +WorkingDirectory=$(dirname "$LAUNCHER_PATH") + +[Install] +WantedBy=multi-user.target +EOF + +chmod +x $LAUNCHER_PATH + +# Reload systemd, enable and start the service +sudo systemctl daemon-reload +sudo systemctl enable --now $SERVICE_NAME + +echo "Service '$SERVICE_NAME' installed and started." \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/launcher.sh b/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/launcher.sh new file mode 100755 index 0000000000000000000000000000000000000000..7d62c5124b6b470e5cf4a9c1bc992a78a65cb443 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/launcher.sh @@ -0,0 +1,3 @@ +#!/bin/bash +source /venvs/mini_daemon/bin/activate +python -m reachy_mini.daemon.app.services.gpio_shutdown.shutdown_monitor diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/shutdown_monitor.py b/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/shutdown_monitor.py new file mode 100644 index 0000000000000000000000000000000000000000..8c9788a4fb8266531e6128b382f311ba4d801356 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/gpio_shutdown/shutdown_monitor.py @@ -0,0 +1,20 @@ +"""Monitor GPIO24 for shutdown signal.""" + +from signal import pause +from subprocess import call + +from gpiozero import Button + +shutdown_button = Button(23, pull_up=False) + + +def released() -> None: + """Handle shutdown button released.""" + print("Shutdown button released, shutting down...") + call(["sudo", "shutdown", "-h", "now"]) + + +shutdown_button.when_released = released + +print("Monitoring GPIO23 for shutdown signal...") +pause() diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/wireless/install_service.sh b/reachy_mini/src/reachy_mini/daemon/app/services/wireless/install_service.sh new file mode 100755 index 0000000000000000000000000000000000000000..9e9e9b1cebd043f3ac471fb0b6b2d4b96c748776 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/wireless/install_service.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +SERVICE_NAME="reachy-mini-daemon" +SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" +LAUNCHER_PATH="$SCRIPT_DIR/launcher.sh" + +# Create the service file +cat < /dev/null +[Unit] +Description=Reachy Mini AP Launcher Service +After=network.target + +[Service] +Type=simple +ExecStart=$LAUNCHER_PATH +Restart=on-failure +User=$(whoami) +WorkingDirectory=$(dirname "$LAUNCHER_PATH") + +[Install] +WantedBy=multi-user.target +EOF + +chmod +x $LAUNCHER_PATH + +# Reload systemd, enable and start the service +sudo systemctl daemon-reload +sudo systemctl enable --now $SERVICE_NAME + +echo "Service '$SERVICE_NAME' installed and started." \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/daemon/app/services/wireless/launcher.sh b/reachy_mini/src/reachy_mini/daemon/app/services/wireless/launcher.sh new file mode 100755 index 0000000000000000000000000000000000000000..bf971ba7291f76a4a3eb4ed46d8bf3fe869d1a82 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/app/services/wireless/launcher.sh @@ -0,0 +1,4 @@ +#!/bin/bash +source /venvs/mini_daemon/bin/activate +export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:/opt/gst-plugins-rs/lib/aarch64-linux-gnu/ +python -m reachy_mini.daemon.app.main --wireless-version --no-autostart diff --git a/reachy_mini/src/reachy_mini/daemon/backend/__init__.py b/reachy_mini/src/reachy_mini/daemon/backend/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..38eef82b1e234c864824970b6f12ef30892496e9 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/backend/__init__.py @@ -0,0 +1 @@ +"""Backend module for Reachy Mini Daemon.""" diff --git a/reachy_mini/src/reachy_mini/daemon/backend/abstract.py b/reachy_mini/src/reachy_mini/daemon/backend/abstract.py new file mode 100644 index 0000000000000000000000000000000000000000..68eb3e16d0982a8e21805e2e5ec16f9468252876 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/backend/abstract.py @@ -0,0 +1,755 @@ +"""Base class for robot backends, simulated or real. + +This module defines the `Backend` class, which serves as a base for implementing +different types of robot backends, whether they are simulated (like Mujoco) or real +(connected via serial port). The class provides methods for managing joint positions, +torque control, and other backend-specific functionalities. +It is designed to be extended by subclasses that implement the specific behavior for +each type of backend. +""" + +import asyncio +import json +import logging +import threading +import time +import typing +from abc import abstractmethod +from enum import Enum +from pathlib import Path +from typing import Annotated, Any, Dict, Optional + +import numpy as np +import zenoh +from numpy.typing import NDArray +from scipy.spatial.transform import Rotation as R + +if typing.TYPE_CHECKING: + from reachy_mini.daemon.backend.mujoco.backend import MujocoBackendStatus + from reachy_mini.daemon.backend.robot.backend import RobotBackendStatus + from reachy_mini.kinematics import AnyKinematics +from reachy_mini.media.audio_sounddevice import SoundDeviceAudio +from reachy_mini.motion.goto import GotoMove +from reachy_mini.motion.move import Move +from reachy_mini.utils.constants import MODELS_ROOT_PATH, URDF_ROOT_PATH +from reachy_mini.utils.interpolation import ( + InterpolationTechnique, + distance_between_poses, + time_trajectory, +) + + +class MotorControlMode(str, Enum): + """Enum for motor control modes.""" + + Enabled = "enabled" # Torque ON and controlled in position + Disabled = "disabled" # Torque OFF + GravityCompensation = "gravity_compensation" # Torque ON and controlled in current to compensate for gravity + + +class Backend: + """Base class for robot backends, simulated or real.""" + + def __init__( + self, + log_level: str = "INFO", + check_collision: bool = False, + kinematics_engine: str = "AnalyticalKinematics", + ) -> None: + """Initialize the backend.""" + self.logger = logging.getLogger(__name__) + self.logger.setLevel(log_level) + + self.should_stop = threading.Event() + self.ready = threading.Event() + + self.check_collision = ( + check_collision # Flag to enable/disable collision checking + ) + self.kinematics_engine = kinematics_engine + + self.logger.info(f"Using {self.kinematics_engine} kinematics engine") + + if self.check_collision: + assert self.kinematics_engine == "Placo", ( + "Collision checking is only available with Placo Kinematics" + ) + + self.gravity_compensation_mode = False # Flag for gravity compensation mode + + if self.gravity_compensation_mode: + assert self.kinematics_engine == "Placo", ( + "Gravity compensation is only available with Placo kinematics" + ) + + if self.kinematics_engine == "Placo": + from reachy_mini.kinematics import PlacoKinematics + + self.head_kinematics: AnyKinematics = PlacoKinematics( + URDF_ROOT_PATH, check_collision=self.check_collision + ) + elif self.kinematics_engine == "NN": + from reachy_mini.kinematics import NNKinematics + + self.head_kinematics = NNKinematics(MODELS_ROOT_PATH) + elif self.kinematics_engine == "AnalyticalKinematics": + from reachy_mini.kinematics import AnalyticalKinematics + + self.head_kinematics = AnalyticalKinematics() + else: + raise ValueError( + f"Unknown kinematics engine: {self.kinematics_engine}. Use 'Placo', 'NN' or 'AnalyticalKinematics'." + ) + + self.current_head_pose: Annotated[NDArray[np.float64], (4, 4)] | None = ( + None # 4x4 pose matrix + ) + self.target_head_pose: Annotated[NDArray[np.float64], (4, 4)] | None = ( + None # 4x4 pose matrix + ) + self.target_body_yaw: float | None = ( + None # Last body yaw used in IK computations + ) + + self.target_head_joint_positions: ( + Annotated[NDArray[np.float64], (7,)] | None + ) = None # [yaw, 0, 1, 2, 3, 4, 5] + self.current_head_joint_positions: ( + Annotated[NDArray[np.float64], (7,)] | None + ) = None # [yaw, 0, 1, 2, 3, 4, 5] + self.target_antenna_joint_positions: ( + Annotated[NDArray[np.float64], (2,)] | None + ) = None # [0, 1] + self.current_antenna_joint_positions: ( + Annotated[NDArray[np.float64], (2,)] | None + ) = None # [0, 1] + + self.joint_positions_publisher: zenoh.Publisher | None = None + self.pose_publisher: zenoh.Publisher | None = None + self.recording_publisher: zenoh.Publisher | None = None + self.error: str | None = None # To store any error that occurs during execution + self.is_recording = False # Flag to indicate if recording is active + self.recorded_data: list[dict[str, Any]] = [] # List to store recorded data + + # variables to store the last computed head joint positions and pose + self._last_target_body_yaw: float | None = ( + None # Last body yaw used in IK computations + ) + self._last_target_head_pose: Annotated[NDArray[np.float64], (4, 4)] | None = ( + None # Last head pose used in IK computations + ) + self.target_head_joint_current: Annotated[NDArray[np.float64], (7,)] | None = ( + None # Placeholder for head joint torque + ) + self.ik_required = False # Flag to indicate if IK computation is required + + self.is_shutting_down = False + + # Tolerance for kinematics computations + # For Forward kinematics (around 0.25deg) + # - FK is calculated at each timestep and is susceptible to noise + self._fk_kin_tolerance = 1e-3 # rads + # For Inverse kinematics (around 0.5mm and 0.1 degrees) + # - IK is calculated only when the head pose is set by the user + self._ik_kin_tolerance = { + "rad": 2e-3, # rads + "m": 0.5e-3, # m + } + + # Recording lock to guard buffer swaps and appends + self._rec_lock = threading.Lock() + + self.audio = SoundDeviceAudio(log_level=log_level) + + # Life cycle methods + def wrapped_run(self) -> None: + """Run the backend in a try-except block to store errors.""" + try: + self.run() + except Exception as e: + self.error = str(e) + self.close() + raise e + + def run(self) -> None: + """Run the backend. + + This method is a placeholder and should be overridden by subclasses. + """ + raise NotImplementedError("The method run should be overridden by subclasses.") + + def close(self) -> None: + """Close the backend. + + This method is a placeholder and should be overridden by subclasses. + """ + raise NotImplementedError( + "The method close should be overridden by subclasses." + ) + + def get_status(self) -> "RobotBackendStatus | MujocoBackendStatus": + """Return backend statistics. + + This method is a placeholder and should be overridden by subclasses. + """ + raise NotImplementedError( + "The method get_status should be overridden by subclasses." + ) + + # Present/Target joint positions + def set_joint_positions_publisher(self, publisher: zenoh.Publisher) -> None: + """Set the publisher for joint positions. + + Args: + publisher: A publisher object that will be used to publish joint positions. + + """ + self.joint_positions_publisher = publisher + + def set_pose_publisher(self, publisher: zenoh.Publisher) -> None: + """Set the publisher for head pose. + + Args: + publisher: A publisher object that will be used to publish head pose. + + """ + self.pose_publisher = publisher + + def update_target_head_joints_from_ik( + self, + pose: Annotated[NDArray[np.float64], (4, 4)] | None = None, + body_yaw: float | None = None, + ) -> None: + """Update the target head joint positions from inverse kinematics. + + Args: + pose (np.ndarray): 4x4 pose matrix representing the head pose. + body_yaw (float): The yaw angle of the body, used to adjust the head pose. + + """ + if pose is None: + pose = ( + self.target_head_pose + if self.target_head_pose is not None + else np.eye(4) + ) + + if body_yaw is None: + body_yaw = self.target_body_yaw if self.target_body_yaw is not None else 0.0 + + # Compute the inverse kinematics to get the head joint positions + joints = self.head_kinematics.ik(pose, body_yaw=body_yaw) + if joints is None or np.any(np.isnan(joints)): + raise ValueError("WARNING: Collision detected or head pose not achievable!") + + # update the target head pose and body yaw + self._last_target_head_pose = pose + self._last_target_body_yaw = body_yaw + + self.target_head_joint_positions = joints + + def set_target_head_pose( + self, + pose: Annotated[NDArray[np.float64], (4, 4)], + ) -> None: + """Set the target head pose for the robot. + + Args: + pose (np.ndarray): 4x4 pose matrix representing the head pose. + + """ + self.target_head_pose = pose + self.ik_required = True + + def set_target_body_yaw(self, body_yaw: float) -> None: + """Set the target body yaw for the robot. + + Only used when doing a set_target() with a standalone body_yaw (no head pose). + + Args: + body_yaw (float): The yaw angle of the body + + """ + self.target_body_yaw = body_yaw + self.ik_required = True # Do we need that here? + + def set_target_head_joint_positions( + self, positions: Annotated[NDArray[np.float64], (7,)] | None + ) -> None: + """Set the head joint positions. + + Args: + positions (List[float]): A list of joint positions for the head. + + """ + self.target_head_joint_positions = positions + self.ik_required = False + + def set_target( + self, + head: Annotated[NDArray[np.float64], (4, 4)] | None = None, # 4x4 pose matrix + antennas: Annotated[NDArray[np.float64], (2,)] + | None = None, # [right_angle, left_angle] (in rads) + body_yaw: float | None = None, # Body yaw angle in radians + ) -> None: + """Set the target head pose and/or antenna positions and/or body_yaw.""" + if head is not None: + self.set_target_head_pose(head) + + if body_yaw is not None: + self.set_target_body_yaw(body_yaw) + + if antennas is not None: + self.set_target_antenna_joint_positions(antennas) + + def set_target_antenna_joint_positions( + self, + positions: Annotated[NDArray[np.float64], (2,)], + ) -> None: + """Set the antenna joint positions. + + Args: + positions (List[float]): A list of joint positions for the antenna. + + """ + self.target_antenna_joint_positions = positions + + def set_target_head_joint_current( + self, + current: Annotated[NDArray[np.float64], (7,)], + ) -> None: + """Set the head joint current. + + Args: + current (Annotated[NDArray[np.float64], (7,)]): A list of current values for the head motors. + + """ + self.target_head_joint_current = current + self.ik_required = False + + async def play_move( + self, + move: Move, + play_frequency: float = 100.0, + initial_goto_duration: float = 0.0, + ) -> None: + """Asynchronously play a Move. + + Args: + move (Move): The Move object to be played. + play_frequency (float): The frequency at which to evaluate the move (in Hz). + initial_goto_duration (float): Duration for an initial goto to the move's starting position. If 0.0, no initial goto is performed. + + """ + if initial_goto_duration > 0.0: + start_head_pose, start_antennas_positions, start_body_yaw = move.evaluate( + 0.0 + ) + await self.goto_target( + head=start_head_pose, + antennas=start_antennas_positions, + duration=initial_goto_duration, + body_yaw=start_body_yaw, + ) + sleep_period = 1.0 / play_frequency + + t0 = time.time() + while time.time() - t0 < move.duration: + t = time.time() - t0 + + head, antennas, body_yaw = move.evaluate(t) + if head is not None: + self.set_target_head_pose(head) + if body_yaw is not None: + self.set_target_body_yaw(body_yaw) + if antennas is not None: + self.set_target_antenna_joint_positions(antennas) + + elapsed = time.time() - t0 - t + if elapsed < sleep_period: + await asyncio.sleep(sleep_period - elapsed) + else: + await asyncio.sleep(0.001) + + async def goto_target( + self, + head: Annotated[NDArray[np.float64], (4, 4)] | None = None, # 4x4 pose matrix + antennas: Annotated[NDArray[np.float64], (2,)] + | None = None, # [right_angle, left_angle] (in rads) + duration: float = 0.5, # Duration in seconds for the movement, default is 0.5 seconds. + method: InterpolationTechnique = InterpolationTechnique.MIN_JERK, # can be "linear", "minjerk", "ease" or "cartoon", default is "minjerk" + body_yaw: float | None = 0.0, # Body yaw angle in radians + ) -> None: + """Asynchronously go to a target head pose and/or antennas position using task space interpolation, in "duration" seconds. + + Args: + head (np.ndarray | None): 4x4 pose matrix representing the target head pose. + antennas (np.ndarray | list[float] | None): 1D array with two elements representing the angles of the antennas in radians. + duration (float): Duration of the movement in seconds. + method (str): Interpolation method to use ("linear", "minjerk", "ease", "cartoon"). Default is "minjerk". + body_yaw (float | None): Body yaw angle in radians. + + Raises: + ValueError: If neither head nor antennas are provided, or if duration is not positive. + + """ + return await self.play_move( + move=GotoMove( + start_head_pose=self.get_present_head_pose(), + target_head_pose=head, + start_body_yaw=self.get_present_body_yaw(), + target_body_yaw=body_yaw, + start_antennas=np.array(self.get_present_antenna_joint_positions()), + target_antennas=np.array(antennas) if antennas is not None else None, + duration=duration, + method=method, + ) + ) + + async def goto_joint_positions( + self, + head_joint_positions: list[float] + | None = None, # [yaw, stewart_platform x 6] length 7 + antennas_joint_positions: list[float] + | None = None, # [right_angle, left_angle] length 2 + duration: float = 0.5, # Duration in seconds for the movement + method: InterpolationTechnique = InterpolationTechnique.MIN_JERK, # can be "linear", "minjerk", "ease" or "cartoon", default is "minjerk" + ) -> None: + """Asynchronously go to a target head joint positions and/or antennas joint positions using joint space interpolation, in "duration" seconds. + + Go to a target head joint positions and/or antennas joint positions using joint space interpolation, in "duration" seconds. + + Args: + head_joint_positions (Optional[List[float]]): List of head joint positions in radians (length 7). + antennas_joint_positions (Optional[List[float]]): List of antennas joint positions in radians (length 2). + duration (float): Duration of the movement in seconds. Default is 0.5 seconds. + method (str): Interpolation method to use ("linear", "minjerk", "ease", "cartoon"). Default is "minjerk". + + Raises: + ValueError: If neither head_joint_positions nor antennas_joint_positions are provided, or if duration is not positive. + + """ + if duration <= 0.0: + raise ValueError( + "Duration must be positive and non-zero. Use set_target() for immediate position setting." + ) + + start_head = np.array(self.get_present_head_joint_positions()) + start_antennas = np.array(self.get_present_antenna_joint_positions()) + + target_head = ( + np.array(head_joint_positions) + if head_joint_positions is not None + else start_head + ) + target_antennas = ( + np.array(antennas_joint_positions) + if antennas_joint_positions is not None + else start_antennas + ) + + t0 = time.time() + while time.time() - t0 < duration: + t = time.time() - t0 + + interp_time = time_trajectory(t / duration, method=method) + + head_joint = start_head + (target_head - start_head) * interp_time + antennas_joint = ( + start_antennas + (target_antennas - start_antennas) * interp_time + ) + + self.set_target_head_joint_positions(head_joint) + self.set_target_antenna_joint_positions(antennas_joint) + await asyncio.sleep(0.01) + + def set_recording_publisher(self, publisher: zenoh.Publisher) -> None: + """Set the publisher for recording data. + + Args: + publisher: A publisher object that will be used to publish recorded data. + + """ + self.recording_publisher = publisher + + def append_record(self, record: dict[str, Any]) -> None: + """Append a record to the recorded data. + + Args: + record (dict): A dictionary containing the record data to be appended. + + """ + if not self.is_recording: + return + # Double-check under lock to avoid race with stop_recording + with self._rec_lock: + if self.is_recording: + self.recorded_data.append(record) + + def start_recording(self) -> None: + """Start recording data.""" + with self._rec_lock: + self.recorded_data = [] + self.is_recording = True + + def stop_recording(self) -> None: + """Stop recording data and publish the recorded data.""" + # Swap buffer under lock so writers cannot touch the published list + with self._rec_lock: + self.is_recording = False + recorded_data, self.recorded_data = self.recorded_data, [] + # Publish outside the lock + if self.recording_publisher is not None: + self.recording_publisher.put(json.dumps(recorded_data)) + else: + self.logger.warning( + "stop_recording called but recording_publisher is not set; dropping data." + ) + + def get_present_head_joint_positions(self) -> Annotated[NDArray[np.float64], (7,)]: + """Return the present head joint positions. + + This method is a placeholder and should be overridden by subclasses. + """ + raise NotImplementedError( + "The method get_present_head_joint_positions should be overridden by subclasses." + ) + + def get_present_body_yaw(self) -> float: + """Return the present body yaw.""" + yaw: float = self.get_present_head_joint_positions()[0] + return yaw + + def get_present_head_pose(self) -> Annotated[NDArray[np.float64], (4, 4)]: + """Return the present head pose as a 4x4 matrix.""" + assert self.current_head_pose is not None, ( + "The current head pose is not set. Please call the update_head_kinematics_model method first." + ) + return self.current_head_pose + + def get_current_head_pose(self) -> Annotated[NDArray[np.float64], (4, 4)]: + """Return the present head pose as a 4x4 matrix.""" + return self.get_present_head_pose() + + def get_present_antenna_joint_positions( + self, + ) -> Annotated[NDArray[np.float64], (2,)]: + """Return the present antenna joint positions. + + This method is a placeholder and should be overridden by subclasses. + """ + raise NotImplementedError( + "The method get_present_antenna_joint_positions should be overridden by subclasses." + ) + + # Kinematics methods + def update_head_kinematics_model( + self, + head_joint_positions: Annotated[NDArray[np.float64], (7,)] | None = None, + antennas_joint_positions: Annotated[NDArray[np.float64], (2,)] | None = None, + ) -> None: + """Update the placo kinematics of the robot. + + Args: + head_joint_positions (List[float] | None): The joint positions of the head. + antennas_joint_positions (List[float] | None): The joint positions of the antennas. + + Returns: + None: This method does not return anything. + + This method updates the head kinematics model with the given joint positions. + - If the joint positions are not provided, it will use the current joint positions. + - If the head joint positions have not changed, it will return without recomputing the forward kinematics. + - If the head joint positions have changed, it will compute the forward kinematics to get the current head pose. + - If the forward kinematics fails, it will raise an assertion error. + - If the antennas joint positions are provided, it will update the current antenna joint positions. + + Note: + This method will update the `current_head_pose` and `current_head_joint_positions` + attributes of the backend instance with the computed values. And the `current_antenna_joint_positions` if provided. + + """ + if head_joint_positions is None: + head_joint_positions = self.get_present_head_joint_positions() + + # Compute the forward kinematics to get the current head pose + self.current_head_pose = self.head_kinematics.fk(head_joint_positions) + + # Check if the FK was successful + assert self.current_head_pose is not None, ( + "FK failed to compute the current head pose." + ) + + # Store the last head joint positions + self.current_head_joint_positions = head_joint_positions + + if antennas_joint_positions is not None: + self.current_antenna_joint_positions = antennas_joint_positions + + def set_automatic_body_yaw(self, body_yaw: bool) -> None: + """Set the automatic body yaw. + + Args: + body_yaw (bool): The yaw angle of the body. + + """ + self.head_kinematics.set_automatic_body_yaw(automatic_body_yaw=body_yaw) + + def get_urdf(self) -> str: + """Get the URDF representation of the robot.""" + urdf_path = Path(URDF_ROOT_PATH) / "robot.urdf" + + with open(urdf_path, "r") as f: + return f.read() + + # Multimedia methods + def play_sound(self, sound_file: str) -> None: + """Play a sound file from the assets directory. + + If the file is not found in the assets directory, try to load the path itself. + + Args: + sound_file (str): The name of the sound file to play (e.g., "wake_up.wav"). + + """ + self.audio.play_sound(sound_file, autoclean=True) + + # Basic move definitions + INIT_HEAD_POSE = np.eye(4) + + SLEEP_HEAD_JOINT_POSITIONS = [ + 0, + -0.9848156658225817, + 1.2624661884298831, + -0.24390294527381684, + 0.20555342557667577, + -1.2363885150358267, + 1.0032234352772091, + ] + + SLEEP_ANTENNAS_JOINT_POSITIONS = np.array((-3.05, 3.05)) + SLEEP_HEAD_POSE = np.array( + [ + [0.911, 0.004, 0.413, -0.021], + [-0.004, 1.0, -0.001, 0.001], + [-0.413, -0.001, 0.911, -0.044], + [0.0, 0.0, 0.0, 1.0], + ] + ) + + async def wake_up(self) -> None: + """Wake up the robot - go to the initial head position and play the wake up emote and sound.""" + await asyncio.sleep(0.1) + + _, _, magic_distance = distance_between_poses( + self.get_current_head_pose(), self.INIT_HEAD_POSE + ) + + await self.goto_target( + self.INIT_HEAD_POSE, + antennas=np.array((0.0, 0.0)), + duration=magic_distance * 20 / 1000, # ms_per_magic_mm = 10 + ) + await asyncio.sleep(0.1) + + # Toudoum + self.play_sound("wake_up.wav") + + # Roll 20° to the left + pose = self.INIT_HEAD_POSE.copy() + pose[:3, :3] = R.from_euler("xyz", [20, 0, 0], degrees=True).as_matrix() + await self.goto_target(pose, duration=0.2) + + # Go back to the initial position + await self.goto_target(self.INIT_HEAD_POSE, duration=0.2) + + async def goto_sleep(self) -> None: + """Put the robot to sleep by moving the head and antennas to a predefined sleep position. + + - If we are already very close to the sleep position, we do nothing. + - If we are far from the sleep position: + - If we are far from the initial position, we move there first. + - If we are close to the initial position, we move directly to the sleep position. + """ + # Magic units + _, _, dist_to_sleep_pose = distance_between_poses( + self.get_current_head_pose(), self.SLEEP_HEAD_POSE + ) + _, _, dist_to_init_pose = distance_between_poses( + self.get_current_head_pose(), self.INIT_HEAD_POSE + ) + sleep_time = 2.0 + + # Thresholds found empirically. + if dist_to_sleep_pose > 10: + if dist_to_init_pose > 30: + # Move to the initial position + await self.goto_target( + self.INIT_HEAD_POSE, antennas=np.array((0.0, 0.0)), duration=1 + ) + await asyncio.sleep(0.2) + + self.play_sound("go_sleep.wav") + + # Move to the sleep position + await self.goto_target( + self.SLEEP_HEAD_POSE, + antennas=self.SLEEP_ANTENNAS_JOINT_POSITIONS, + duration=2, + ) + else: + # The sound doesn't play fully if we don't wait enough + self.play_sound("go_sleep.wav") + sleep_time += 3 + + self._last_head_pose = self.SLEEP_HEAD_POSE + await asyncio.sleep(sleep_time) + + # Motor control modes + @abstractmethod + def get_motor_control_mode(self) -> MotorControlMode: + """Get the motor control mode.""" + pass + + @abstractmethod + def set_motor_control_mode(self, mode: MotorControlMode) -> None: + """Set the motor control mode.""" + pass + + @abstractmethod + def set_motor_torque_ids(self, ids: list[str], on: bool) -> None: + """Set the motor torque for specific motor names.""" + pass + + def get_present_passive_joint_positions(self) -> Optional[Dict[str, float]]: + """Get the present passive joint positions. + + Requires the Placo kinematics engine. + """ + # This is would be better, and fix mypy issues, but Placo is dynamically imported + # if not isinstance(self.head_kinematics, PlacoKinematics): + if self.kinematics_engine != "Placo": + return None + return { + "passive_1_x": self.head_kinematics.get_joint("passive_1_x"), # type: ignore [union-attr] + "passive_1_y": self.head_kinematics.get_joint("passive_1_y"), # type: ignore [union-attr] + "passive_1_z": self.head_kinematics.get_joint("passive_1_z"), # type: ignore [union-attr] + "passive_2_x": self.head_kinematics.get_joint("passive_2_x"), # type: ignore [union-attr] + "passive_2_y": self.head_kinematics.get_joint("passive_2_y"), # type: ignore [union-attr] + "passive_2_z": self.head_kinematics.get_joint("passive_2_z"), # type: ignore [union-attr] + "passive_3_x": self.head_kinematics.get_joint("passive_3_x"), # type: ignore [union-attr] + "passive_3_y": self.head_kinematics.get_joint("passive_3_y"), # type: ignore [union-attr] + "passive_3_z": self.head_kinematics.get_joint("passive_3_z"), # type: ignore [union-attr] + "passive_4_x": self.head_kinematics.get_joint("passive_4_x"), # type: ignore [union-attr] + "passive_4_y": self.head_kinematics.get_joint("passive_4_y"), # type: ignore [union-attr] + "passive_4_z": self.head_kinematics.get_joint("passive_4_z"), # type: ignore [union-attr] + "passive_5_x": self.head_kinematics.get_joint("passive_5_x"), # type: ignore [union-attr] + "passive_5_y": self.head_kinematics.get_joint("passive_5_y"), # type: ignore [union-attr] + "passive_5_z": self.head_kinematics.get_joint("passive_5_z"), # type: ignore [union-attr] + "passive_6_x": self.head_kinematics.get_joint("passive_6_x"), # type: ignore [union-attr] + "passive_6_y": self.head_kinematics.get_joint("passive_6_y"), # type: ignore [union-attr] + "passive_6_z": self.head_kinematics.get_joint("passive_6_z"), # type: ignore [union-attr] + "passive_7_x": self.head_kinematics.get_joint("passive_7_x"), # type: ignore [union-attr] + "passive_7_y": self.head_kinematics.get_joint("passive_7_y"), # type: ignore [union-attr] + "passive_7_z": self.head_kinematics.get_joint("passive_7_z"), # type: ignore [union-attr] + } diff --git a/reachy_mini/src/reachy_mini/daemon/backend/mujoco/__init__.py b/reachy_mini/src/reachy_mini/daemon/backend/mujoco/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..78ed8a96513559c50a3be08c238f0eeb401ad9cc --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/backend/mujoco/__init__.py @@ -0,0 +1,36 @@ +"""MuJoCo Backend for Reachy Mini Daemon.""" + +from dataclasses import dataclass + +try: + import mujoco # noqa: F401 + + from reachy_mini.daemon.backend.mujoco.backend import ( + MujocoBackend, + MujocoBackendStatus, + ) + +except ImportError: + + class MujocoMockupBackend: + """Mockup class to avoid import errors when MuJoCo is not installed.""" + + def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def] + """Raise ImportError when trying to instantiate the class.""" + raise ImportError( + "MuJoCo is not installed. MuJoCo backend is not available." + " To use MuJoCo backend, please install the 'mujoco' extra dependencies" + " with 'pip install reachy_mini[mujoco]'." + ) + + MujocoBackend = MujocoMockupBackend # type: ignore[assignment, misc] + + @dataclass + class MujocoMockupBackendStatus: + """Mockup class to avoid import errors when MuJoCo is not installed.""" + + pass + + MujocoBackendStatus = MujocoMockupBackendStatus # type: ignore[assignment, misc] + +__all__ = ["MujocoBackend", "MujocoBackendStatus"] diff --git a/reachy_mini/src/reachy_mini/daemon/backend/mujoco/backend.py b/reachy_mini/src/reachy_mini/daemon/backend/mujoco/backend.py new file mode 100644 index 0000000000000000000000000000000000000000..5df66a6be070da4f04e8b1db2a32c8ba2bf2b23b --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/backend/mujoco/backend.py @@ -0,0 +1,333 @@ +"""Mujoco Backend for Reachy Mini. + +This module provides the MujocoBackend class for simulating the Reachy Mini robot using the MuJoCo physics engine. + +It includes methods for running the simulation, getting joint positions, and controlling the robot's joints. + +""" + +import json +import time +from dataclasses import dataclass +from importlib.resources import files +from threading import Thread +from typing import Annotated + +import log_throttling +import mujoco +import mujoco.viewer +import numpy as np +import numpy.typing as npt + +import reachy_mini + +from ..abstract import Backend, MotorControlMode +from .utils import ( + get_actuator_names, + get_joint_addr_from_name, + get_joint_id_from_name, +) +from .video_udp import UDPJPEGFrameSender + + +class MujocoBackend(Backend): + """Simulated Reachy Mini using MuJoCo.""" + + def __init__( + self, + scene: str = "empty", + check_collision: bool = False, + kinematics_engine: str = "AnalyticalKinematics", + headless: bool = False, + ) -> None: + """Initialize the MujocoBackend with a specified scene. + + Args: + scene (str): The name of the scene to load. Default is "empty". + check_collision (bool): If True, enable collision checking. Default is False. + kinematics_engine (str): Kinematics engine to use. Defaults to "AnalyticalKinematics". + headless (bool): If True, run Mujoco in headless mode (no GUI). Default is False. + + """ + super().__init__( + check_collision=check_collision, kinematics_engine=kinematics_engine + ) + + self.headless = headless + + from reachy_mini.reachy_mini import ( + SLEEP_ANTENNAS_JOINT_POSITIONS, + SLEEP_HEAD_JOINT_POSITIONS, + ) + + # Real robot convention for the order of the antennas joints is [right, left], but in mujoco it's [left, right] + self._SLEEP_ANTENNAS_JOINT_POSITIONS = [ + SLEEP_ANTENNAS_JOINT_POSITIONS[1], + SLEEP_ANTENNAS_JOINT_POSITIONS[0], + ] + self._SLEEP_HEAD_JOINT_POSITIONS = SLEEP_HEAD_JOINT_POSITIONS + + mjcf_root_path = str( + files(reachy_mini).joinpath("descriptions/reachy_mini/mjcf/") + ) + self.model = mujoco.MjModel.from_xml_path( + f"{mjcf_root_path}/scenes/{scene}.xml" + ) + self.data = mujoco.MjData(self.model) + self.model.opt.timestep = 0.002 # s, simulation timestep, 500hz + self.decimation = 10 # -> 50hz control loop + self.rendering_timestep = 0.04 # s, rendering loop # 25Hz + + self.camera_id = mujoco.mj_name2id( + self.model, + mujoco.mjtObj.mjOBJ_CAMERA, + "eye_camera", + ) + + self.head_site_id = mujoco.mj_name2id( + self.model, + mujoco.mjtObj.mjOBJ_SITE, + "head", + ) + + self.current_head_pose = np.eye(4) + + self.joint_names = get_actuator_names(self.model) + + self.joint_ids = [ + get_joint_id_from_name(self.model, n) for n in self.joint_names + ] + self.joint_qpos_addr = [ + get_joint_addr_from_name(self.model, n) for n in self.joint_names + ] + + self.col_inds = [] + for i, type in enumerate(self.model.geom_contype): + if type != 0: + self.col_inds.append(i) + self.model.geom_contype[i] = 0 + self.model.geom_conaffinity[i] = 0 + + def rendering_loop(self) -> None: + """Offline Rendering loop for the Mujoco simulation. + + Capture the image from the virtual Reachy's camera and send it over UDP. + """ + streamer_udp = UDPJPEGFrameSender() + camera_size = (1280, 720) + offscreen_renderer = mujoco.Renderer( + self.model, height=camera_size[1], width=camera_size[0] + ) + while not self.should_stop.is_set(): + start_t = time.time() + offscreen_renderer.update_scene(self.data, self.camera_id) + im = offscreen_renderer.render() + streamer_udp.send_frame(im) + + took = time.time() - start_t + time.sleep(max(0, self.rendering_timestep - took)) + + def run(self) -> None: + """Run the Mujoco simulation with a viewer. + + This method initializes the viewer and enters the main simulation loop. + It updates the joint positions at a rate and publishes the joint positions. + """ + step = 1 + if not self.headless: + viewer = mujoco.viewer.launch_passive( + self.model, self.data, show_left_ui=False, show_right_ui=False + ) + with viewer.lock(): + viewer.cam.type = mujoco.mjtCamera.mjCAMERA_FREE + viewer.cam.distance = 0.8 # ≃ ||pos - lookat|| + viewer.cam.azimuth = 160 # degrees + viewer.cam.elevation = -20 # degrees + viewer.cam.lookat[:] = [0, 0, 0.15] + + # force one render with your new camera + mujoco.mj_step(self.model, self.data) + viewer.sync() + + # im = self.get_camera() + # self.streamer_udp.send_frame(im) + + self.data.qpos[self.joint_qpos_addr] = np.array( + self._SLEEP_HEAD_JOINT_POSITIONS + + self._SLEEP_ANTENNAS_JOINT_POSITIONS + ).reshape(-1, 1) + self.data.ctrl[:] = np.array( + self._SLEEP_HEAD_JOINT_POSITIONS + + self._SLEEP_ANTENNAS_JOINT_POSITIONS + ) + + # recompute all kinematics, collisions, etc. + mujoco.mj_forward(self.model, self.data) + + for i in range(100): + mujoco.mj_step(self.model, self.data) + + # enable collisions + for i in self.col_inds: + self.model.geom_contype[i] = 1 + self.model.geom_conaffinity[i] = 1 + + for i in range(100): + mujoco.mj_step(self.model, self.data) + + # one more frame so the viewer shows your startup pose + mujoco.mj_step(self.model, self.data) + if not self.headless: + viewer.sync() + + rendering_thread = Thread(target=self.rendering_loop, daemon=True) + rendering_thread.start() + + # Update the internal states of the IK and FK to the current configuration + # This is important to avoid jumps when starting the robot (beore wake-up) + self.head_kinematics.ik(self.get_mj_present_head_pose(), no_iterations=20) + self.head_kinematics.fk( + self.get_present_head_joint_positions(), no_iterations=20 + ) + + # 3) now enter your normal loop + while not self.should_stop.is_set(): + start_t = time.time() + + if step % self.decimation == 0: + # update the current states + self.current_head_joint_positions = ( + self.get_present_head_joint_positions() + ) + self.current_antenna_joint_positions = ( + self.get_present_antenna_joint_positions() + ) + # Update the Placo kinematics model to recompute passive joints + self.update_head_kinematics_model( + self.current_head_joint_positions, + self.current_antenna_joint_positions, + ) + self.current_head_pose = self.get_mj_present_head_pose() + + # Update the target head joint positions from IK if necessary + # - does nothing if the targets did not change + if self.ik_required: + try: + self.update_target_head_joints_from_ik( + self.target_head_pose, self.target_body_yaw + ) + except ValueError as e: + log_throttling.by_time(self.logger, interval=0.5).warning( + f"IK error: {e}" + ) + + if self.target_head_joint_positions is not None: + self.data.ctrl[:7] = self.target_head_joint_positions + if self.target_antenna_joint_positions is not None: + self.data.ctrl[-2:] = -self.target_antenna_joint_positions + + if ( + self.joint_positions_publisher is not None + and self.pose_publisher is not None + ): + if not self.is_shutting_down: + self.joint_positions_publisher.put( + json.dumps( + { + "head_joint_positions": self.current_head_joint_positions.tolist(), + "antennas_joint_positions": self.current_antenna_joint_positions.tolist(), + } + ).encode("utf-8") + ) + self.pose_publisher.put( + json.dumps( + { + "head_pose": self.get_present_head_pose().tolist(), + } + ).encode("utf-8") + ) + self.ready.set() + + if not self.headless: + viewer.sync() + + mujoco.mj_step(self.model, self.data) + + took = time.time() - start_t + time.sleep(max(0, self.model.opt.timestep - took)) + # print(f"Step {step}: took {took*1e6:.1f}us") + step += 1 + + if not self.headless: + viewer.close() + + def get_mj_present_head_pose(self) -> Annotated[npt.NDArray[np.float64], (4, 4)]: + """Get the current head pose from the Mujoco simulation. + + Returns: + np.ndarray: The current head pose as a 4x4 transformation matrix. + + """ + mj_current_head_pose = np.eye(4) + + mj_current_head_pose[:3, :3] = self.data.site_xmat[self.head_site_id].reshape( + 3, 3 + ) + mj_current_head_pose[:3, 3] = self.data.site_xpos[self.head_site_id] + mj_current_head_pose[2, 3] -= 0.177 + return mj_current_head_pose + + def close(self) -> None: + """Close the Mujoco backend.""" + # TODO Do something in mujoco here ? + pass + + def get_status(self) -> "MujocoBackendStatus": + """Get the status of the Mujoco backend. + + Returns: + dict: An empty dictionary as the Mujoco backend does not have a specific status to report. + + """ + return MujocoBackendStatus(motor_control_mode=self.get_motor_control_mode()) + + def get_present_head_joint_positions( + self, + ) -> Annotated[npt.NDArray[np.float64], (7,)]: + """Get the current joint positions of the head.""" + pos: npt.NDArray[np.float64] = self.data.qpos[ + self.joint_qpos_addr[:7] + ].flatten() + return pos + + def get_present_antenna_joint_positions( + self, + ) -> Annotated[npt.NDArray[np.float64], (2,)]: + """Get the current joint positions of the antennas.""" + pos: npt.NDArray[np.float64] = self.data.qpos[ + self.joint_qpos_addr[-2:] + ].flatten() + return -pos + + def get_motor_control_mode(self) -> MotorControlMode: + """Get the motor control mode.""" + return MotorControlMode.Enabled + + def set_motor_control_mode(self, mode: MotorControlMode) -> None: + """Set the motor control mode.""" + pass + + def set_motor_torque_ids(self, ids: list[str], on: bool) -> None: + """Set the motor torque state for specific motor names.""" + pass + + +@dataclass +class MujocoBackendStatus: + """Dataclass to represent the status of the Mujoco backend. + + Empty for now, as the Mujoco backend does not have a specific status to report. + """ + + motor_control_mode: MotorControlMode + error: str | None = None diff --git a/reachy_mini/src/reachy_mini/daemon/backend/mujoco/utils.py b/reachy_mini/src/reachy_mini/daemon/backend/mujoco/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..c85b764393a438ab4c7998446453e1609b6f56ce --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/backend/mujoco/utils.py @@ -0,0 +1,59 @@ +"""Mujoco utilities for Reachy Mini. + +This module provides utility functions for working with MuJoCo models, including +homogeneous transformation matrices, joint positions, and actuator names. +""" + +from typing import Annotated + +import mujoco +import numpy as np +import numpy.typing as npt +from mujoco._structs import MjData, MjModel +from scipy.spatial.transform import Rotation as R + + +def get_homogeneous_matrix_from_euler( + position: tuple[float, float, float] = (0, 0, 0), # (x, y, z) meters + euler_angles: tuple[float, float, float] = (0, 0, 0), # (roll, pitch, yaw) + degrees: bool = False, +) -> Annotated[npt.NDArray[np.float64], (4, 4)]: + """Return a homogeneous transformation matrix from position and Euler angles.""" + homogeneous_matrix = np.eye(4) + homogeneous_matrix[:3, :3] = R.from_euler( + "xyz", euler_angles, degrees=degrees + ).as_matrix() + homogeneous_matrix[:3, 3] = position + return homogeneous_matrix + + +def get_joint_qpos(model: MjModel, data: MjData, joint_name: str) -> float: + """Return the qpos (rad) of a specified joint in the model.""" + # Get the joint id + joint_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, joint_name) + if joint_id == -1: + raise ValueError(f"Joint '{joint_name}' not found.") + + # Get the address of the joint's qpos in the qpos array + qpos_addr = model.jnt_qposadr[joint_id] + + # Get the qpos value + qpos: float = data.qpos[qpos_addr] + return qpos + + +def get_joint_id_from_name(model: MjModel, name: str) -> int: + """Return the id of a specified joint.""" + return mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, name) # type: ignore + + +def get_joint_addr_from_name(model: MjModel, name: str) -> int: + """Return the address of a specified joint.""" + addr: int = model.joint(name).qposadr + return addr + + +def get_actuator_names(model: MjModel) -> list[str]: + """Return the list of the actuators names from the MuJoCo model.""" + actuator_names = [model.actuator(k).name for k in range(0, model.nu)] + return actuator_names diff --git a/reachy_mini/src/reachy_mini/daemon/backend/mujoco/video_udp.py b/reachy_mini/src/reachy_mini/daemon/backend/mujoco/video_udp.py new file mode 100644 index 0000000000000000000000000000000000000000..087ae9784de41b934f41b9ed2bbeadf391eacdd5 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/backend/mujoco/video_udp.py @@ -0,0 +1,53 @@ +"""UDP JPEG Frame Sender. + +This module provides a class to send JPEG frames over UDP. It encodes the frames as JPEG images and splits them into chunks to fit within the maximum packet size for UDP transmission. +""" + +import socket +import struct + +import cv2 +import numpy as np +import numpy.typing as npt + + +class UDPJPEGFrameSender: + """A class to send JPEG frames over UDP.""" + + def __init__( + self, + dest_ip: str = "127.0.0.1", + dest_port: int = 5005, + max_packet_size: int = 1400, + ) -> None: + """Initialize the UDPJPEGFrameSender. + + Args: + dest_ip (str): Destination IP address. + dest_port (int): Destination port number. + max_packet_size (int): Maximum size of each UDP packet. + + """ + self.addr = (dest_ip, dest_port) + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.max_packet_size = max_packet_size + + def send_frame(self, frame: npt.NDArray[np.uint8]) -> None: + """Send a frame as a JPEG image over UDP. + + Args: + frame (np.ndarray): The frame to be sent, in RGB format. + + """ + frame_cvt = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) + ret, jpeg_bytes = cv2.imencode( + ".jpg", frame_cvt, [int(cv2.IMWRITE_JPEG_QUALITY), 80] + ) + data = jpeg_bytes.tobytes() + total_size = len(data) + n_chunks = (total_size + self.max_packet_size - 1) // self.max_packet_size + self.sock.sendto(struct.pack("!II", n_chunks, total_size), self.addr) + for i in range(n_chunks): + start = i * self.max_packet_size + end = min(start + self.max_packet_size, total_size) + self.sock.sendto(data[start:end], self.addr) diff --git a/reachy_mini/src/reachy_mini/daemon/backend/robot/__init__.py b/reachy_mini/src/reachy_mini/daemon/backend/robot/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1b6ffe66ceea9f718065a88b9836bcdc80c7f144 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/backend/robot/__init__.py @@ -0,0 +1,8 @@ +"""Real robot backend for Reachy Mini.""" + +from reachy_mini.daemon.backend.robot.backend import ( + RobotBackend, + RobotBackendStatus, +) + +__all__ = ["RobotBackend", "RobotBackendStatus"] diff --git a/reachy_mini/src/reachy_mini/daemon/backend/robot/backend.py b/reachy_mini/src/reachy_mini/daemon/backend/robot/backend.py new file mode 100644 index 0000000000000000000000000000000000000000..03440f9746ef0d22cb454e8e9358aa627ac6071f --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/backend/robot/backend.py @@ -0,0 +1,590 @@ +"""Robot Backend for Reachy Mini. + +This module provides the `RobotBackend` class, which interfaces with the Reachy Mini motor controller to control the robot's movements and manage its status. +It handles the control loop, joint positions, torque enabling/disabling, and provides a status report of the robot's backend. +It uses the `ReachyMiniMotorController` to communicate with the robot's motors. +""" + +import json +import logging +import struct +import time +from dataclasses import dataclass +from datetime import timedelta +from multiprocessing import Event # It seems to be more accurate than threading.Event +from typing import Annotated, Any + +import log_throttling +import numpy as np +import numpy.typing as npt +from reachy_mini_motor_controller import ReachyMiniPyControlLoop + +from reachy_mini.utils.hardware_config.parser import parse_yaml_config + +from ..abstract import Backend, MotorControlMode + + +class RobotBackend(Backend): + """Real robot backend for Reachy Mini.""" + + def __init__( + self, + serialport: str, + log_level: str = "INFO", + check_collision: bool = False, + kinematics_engine: str = "AnalyticalKinematics", + hardware_error_check_frequency: float = 1.0, + hardware_config_filepath: str | None = None, + ): + """Initialize the RobotBackend. + + Args: + serialport (str): The serial port to which the Reachy Mini is connected. + log_level (str): The logging level for the backend. Default is "INFO". + check_collision (bool): If True, enable collision checking. Default is False. + kinematics_engine (str): Kinematics engine to use. Defaults to "AnalyticalKinematics". + hardware_error_check_frequency (float): Frequency in seconds to check for hardware errors. Default is 1.0. + hardware_config_filepath (str | None): Path to the hardware configuration YAML file. Default is None. + + Tries to connect to the Reachy Mini motor controller and initializes the control loop. + + """ + super().__init__( + check_collision=check_collision, kinematics_engine=kinematics_engine + ) + + self.logger = logging.getLogger(__name__) + self.logger.setLevel(log_level) + + self.control_loop_frequency = 50.0 # Hz + self.c: ReachyMiniPyControlLoop | None = ReachyMiniPyControlLoop( + serialport, + read_position_loop_period=timedelta( + seconds=1.0 / self.control_loop_frequency + ), + allowed_retries=5, + stats_pub_period=None, + ) + + self.name2id = self.c.get_motor_name_id() + if hardware_config_filepath is not None: + config = parse_yaml_config(hardware_config_filepath) + for motor_name, motor_conf in config.motors.items(): + if motor_conf.pid is not None: + motor_id = self.name2id[motor_name] + p, i, d = motor_conf.pid + self.logger.info( + f"Setting PID gains for motor '{motor_name}' (ID: {motor_id}): P={p}, I={i}, D={d}" + ) + self.c.async_write_pid_gains(motor_id, p, i, d) + + self.motor_control_mode = self._infer_control_mode() + self._torque_enabled = self.motor_control_mode != MotorControlMode.Disabled + self.logger.info(f"Motor control mode: {self.motor_control_mode}") + self.last_alive: float | None = None + + self._status = RobotBackendStatus( + motor_control_mode=self.motor_control_mode, + ready=False, + last_alive=None, + control_loop_stats={}, + ) + self._stats_record_period = 1.0 # seconds + self._stats: dict[str, Any] = { + "timestamps": [], + "nb_error": 0, + "record_period": self._stats_record_period, + } + + self._current_head_operation_mode = -1 # Default to torque control mode + self._current_antennas_operation_mode = -1 # Default to torque control mode + self.target_antenna_joint_current = None # Placeholder for antenna joint torque + self.target_head_joint_current = None # Placeholder for head joint torque + + self.hardware_error_check_frequency = hardware_error_check_frequency # seconds + + def run(self) -> None: + """Run the control loop for the robot backend. + + This method continuously updates the motor controller at a specified frequency. + It reads the joint positions, updates the motor controller, and publishes the joint positions. + It also handles errors and retries if the motor controller is not responding. + """ + assert self.c is not None, "Motor controller not initialized or already closed." + + period = 1.0 / self.control_loop_frequency # Control loop period in seconds + + self.retries = 5 + self.stats_record_t0 = time.time() + + self.last_hardware_error_check_time = time.time() + + next_call_event = Event() + + # Compute the forward kinematics to get the initial head pose + # IMPORTANT for wake_up + head_positions, _ = self.get_all_joint_positions() + # make sure to converge fully (a lot of iterations) + self.current_head_pose = self.head_kinematics.fk( + np.array(head_positions), + no_iterations=20, + ) + assert self.current_head_pose is not None + + self.head_kinematics.ik(self.current_head_pose, no_iterations=20) + + while not self.should_stop.is_set(): + start_t = time.time() + self._stats["timestamps"].append(time.time()) + self._update() + took = time.time() - start_t + + sleep_time = period - took + if sleep_time < 0: + self.logger.debug( + f"Control loop took too long: {took * 1000:.3f} ms, expected {period * 1000:.3f} ms" + ) + sleep_time = 0.001 + + next_call_event.clear() + next_call_event.wait(sleep_time) + + def _update(self) -> None: + assert self.c is not None, "Motor controller not initialized or already closed." + + if self._torque_enabled: + if self._current_head_operation_mode != 0: # if position control mode + if self.target_head_joint_positions is not None: + self.c.set_stewart_platform_position( + self.target_head_joint_positions[1:].tolist() + ) + self.c.set_body_rotation(self.target_head_joint_positions[0]) + else: # it's in torque control mode + if self.gravity_compensation_mode: + # This function will set the head_joint_current + # to the current necessary to compensate for gravity + self.compensate_head_gravity() + if self.target_head_joint_current is not None: + self.c.set_stewart_platform_goal_current( + np.round(self.target_head_joint_current[1:], 0) + .astype(int) + .tolist() + ) + # Body rotation torque control is not supported with feetech motors + # self.c.set_body_rotation_goal_current(int(self.target_head_joint_current[0])) + + if self._current_antennas_operation_mode != 0: # if position control mode + if self.target_antenna_joint_positions is not None: + self.c.set_antennas_positions( + self.target_antenna_joint_positions.tolist() + ) + # Antenna torque control is not supported with feetech motors + # else: + # if self.target_antenna_joint_current is not None: + # self.c.set_antennas_goal_current( + # np.round(self.target_antenna_joint_current, 0).astype(int).tolist() + # ) + + if ( + self.joint_positions_publisher is not None + and self.pose_publisher is not None + ): + try: + head_positions, antenna_positions = self.get_all_joint_positions() + + # Update the head kinematics model with the current head positions + self.update_head_kinematics_model( + np.array(head_positions), + np.array(antenna_positions), + ) + + # Update the target head joint positions from IK if necessary + # - does nothing if the targets did not change + if self.ik_required: + try: + self.update_target_head_joints_from_ik( + self.target_head_pose, self.target_body_yaw + ) + except ValueError as e: + log_throttling.by_time(self.logger, interval=0.5).warning( + f"IK error: {e}" + ) + + if not self.is_shutting_down: + self.joint_positions_publisher.put( + json.dumps( + { + "head_joint_positions": head_positions, + "antennas_joint_positions": antenna_positions, + } + ) + ) + self.pose_publisher.put( + json.dumps( + { + "head_pose": self.get_present_head_pose().tolist(), + } + ) + ) + + self.last_alive = time.time() + + self.ready.set() # Mark the backend as ready + except RuntimeError as e: + self._stats["nb_error"] += 1 + + assert self.last_alive is not None + + if self.last_alive + 1 < time.time(): + self.error = ( + "No response from the robot's motor for the last second." + ) + + self.logger.error( + "No response from the robot for the last second, stopping." + ) + raise e + + if time.time() - self.stats_record_t0 > self._stats_record_period: + dt = np.diff(self._stats["timestamps"]) + if len(dt) > 1: + self._status.control_loop_stats["mean_control_loop_frequency"] = ( + float(np.mean(1.0 / dt)) + ) + self._status.control_loop_stats["max_control_loop_interval"] = ( + float(np.max(dt)) + ) + self._status.control_loop_stats["nb_error"] = self._stats[ + "nb_error" + ] + + self._stats["timestamps"].clear() + self._stats["nb_error"] = 0 + self.stats_record_t0 = time.time() + + if ( + time.time() - self.last_hardware_error_check_time + > self.hardware_error_check_frequency + ): + hardware_errors = self.read_hardware_errors() + if hardware_errors: + for motor_name, errors in hardware_errors.items(): + self.logger.error( + f"Motor '{motor_name}' hardware errors: {errors}" + ) + self.last_hardware_error_check_time = time.time() + + def close(self) -> None: + """Close the motor controller connection.""" + if self.c is not None: + self.c.close() + self.c = None + + def get_status(self) -> "RobotBackendStatus": + """Get the current status of the robot backend.""" + self._status.error = self.error + self._status.motor_control_mode = self.motor_control_mode + return self._status + + def enable_motors(self) -> None: + """Enable the motors by turning the torque on.""" + assert self.c is not None, "Motor controller not initialized or already closed." + + self.c.enable_torque() + self._torque_enabled = True + + def disable_motors(self) -> None: + """Disable the motors by turning the torque off.""" + assert self.c is not None, "Motor controller not initialized or already closed." + + self.c.disable_torque() + self._torque_enabled = False + + def set_head_operation_mode(self, mode: int) -> None: + """Change the operation mode of the head motors. + + Args: + mode (int): The operation mode for the head motors. + + The operation modes can be: + 0: torque control + 3: position control + 5: current-based position control. + + Important: + This method does not work well with the current feetech motors (body rotation), as they do not support torque control. + So the method disables the antennas when in torque control mode. + The dynamixel motors used for the head do support torque control, so this method works as expected. + + Args: + mode (int): The operation mode for the head motors. + This could be a specific mode like position control, velocity control, or torque control. + + """ + assert self.c is not None, "Motor controller not initialized or already closed." + assert mode in [0, 3, 5], ( + "Invalid operation mode. Must be one of [0 (torque), 3 (position), 5 (current-limiting position)]." + f" Got {mode} instead" + ) + + # if motors are enabled, disable them before changing the mode + if self._torque_enabled: + self.c.enable_stewart_platform(False) + # set the new operation mode + self.c.set_stewart_platform_operating_mode(mode) + + if mode != 0: + # if the mode is not torque control, we need to set the head joint positions + # to the current positions to avoid sudden movements + motor_pos = self.c.get_last_position() + self.target_head_joint_positions = np.array( + [motor_pos.body_yaw] + motor_pos.stewart + ) + + self.c.set_stewart_platform_position( + self.target_head_joint_positions[1:].tolist() + ) + self.c.set_body_rotation(self.target_head_joint_positions[0]) + self.c.enable_body_rotation(True) + self.c.set_body_rotation_operating_mode(0) + else: + self.c.enable_body_rotation(False) + + if self._torque_enabled: + self.c.enable_stewart_platform(True) + + self._current_head_operation_mode = mode + + def set_antennas_operation_mode(self, mode: int) -> None: + """Change the operation mode of the antennas motors. + + Args: + mode (int): The operation mode for the antennas motors (0: torque control, 3: position control, 5: current-based position control). + + Important: + This method does not work well with the current feetech motors, as they do not support torque control. + So the method disables the antennas when in torque control mode. + + Args: + mode (int): The operation mode for the antennas motors. + This could be a specific mode like position control, velocity control, or torque control. + + """ + assert self.c is not None, "Motor controller not initialized or already closed." + assert mode in [0, 3, 5], ( + "Invalid operation mode. Must be one of [0 (torque), 3 (position), 5 (current-limiting position)]." + ) + + if self._current_antennas_operation_mode != mode: + if mode != 0: + # if the mode is not torque control, we need to set the head joint positions + # to the current positions to avoid sudden movements + self.target_antenna_joint_positions = np.array( + self.c.get_last_position().antennas + ) + self.c.set_antennas_positions( + self.target_antenna_joint_positions.tolist() + ) + self.c.enable_antennas(True) + else: + self.c.enable_antennas(False) + + self._current_antennas_operation_mode = mode + + def get_all_joint_positions(self) -> tuple[list[float], list[float]]: + """Get the current joint positions of the robot. + + Returns: + tuple: A tuple containing two lists - the first list is for the head joint positions, + and the second list is for the antenna joint positions. + + """ + assert self.c is not None, "Motor controller not initialized or already closed." + positions = self.c.get_last_position() + + yaw = positions.body_yaw + antennas = positions.antennas + dofs = positions.stewart + + return [yaw] + list(dofs), list(antennas) + + def get_present_head_joint_positions( + self, + ) -> Annotated[npt.NDArray[np.float64], (7,)]: + """Get the current joint positions of the head. + + Returns: + list: A list of joint positions for the head, including the body rotation. + + """ + return np.array(self.get_all_joint_positions()[0]) + + def get_present_antenna_joint_positions( + self, + ) -> Annotated[npt.NDArray[np.float64], (2,)]: + """Get the current joint positions of the antennas. + + Returns: + list: A list of joint positions for the antennas. + + """ + return np.array(self.get_all_joint_positions()[1]) + + def compensate_head_gravity(self) -> None: + """Calculate the currents necessary to compensate for gravity.""" + assert self.kinematics_engine == "Placo", ( + "Gravity compensation is only supported with the Placo kinematics engine." + ) + + # Even though in their docs dynamixes says that 1 count is 1 mA, in practice I've found it to be 3mA. + # I am not sure why this happens + # Another explanation is that our model is bad and the current is overestimated 3x (but I have not had these issues with other robots) + # So I am using a magic number to compensate for this. + # for currents under 30mA the constant is around 1 + from_Nm_to_mA = 1.47 / 0.52 * 1000 + # Conversion factor from Nm to mA for the Stewart platform motors + # The torque constant is not linear, so we need to use a correction factor + # This is a magic number that should be determined experimentally + # For currents under 30mA, the constant is around 4.0 + # Then it drops to 1.0 for currents above 1.5A + correction_factor = 4.0 + # Get the current head joint positions + head_joints = self.get_present_head_joint_positions() + gravity_torque = self.head_kinematics.compute_gravity_torque( # type: ignore [union-attr] + np.array(head_joints) + ) + # Convert the torque from Nm to mA + current = gravity_torque * from_Nm_to_mA / correction_factor + # Set the head joint current + self.set_target_head_joint_current(current) + + def get_motor_control_mode(self) -> MotorControlMode: + """Get the motor control mode.""" + return self.motor_control_mode + + def set_motor_control_mode(self, mode: MotorControlMode) -> None: + """Set the motor control mode.""" + # Check if the mode is already set + if mode == self.motor_control_mode: + return + + if mode == MotorControlMode.Enabled: + if self.motor_control_mode == MotorControlMode.GravityCompensation: + # First, make sure we switch to position control + self.disable_motors() + self.set_head_operation_mode(3) + self.set_antennas_operation_mode(3) + + self.gravity_compensation_mode = False + self.enable_motors() + + elif mode == MotorControlMode.Disabled: + self.gravity_compensation_mode = False + self.disable_motors() + + elif mode == MotorControlMode.GravityCompensation: + if self.kinematics_engine != "Placo": + raise RuntimeError( + "Gravity compensation mode is only supported with the Placo kinematics engine." + ) + + self.disable_motors() + self.set_head_operation_mode(0) + self.set_antennas_operation_mode(0) + self.gravity_compensation_mode = True + self.enable_motors() + + self.motor_control_mode = mode + + def set_motor_torque_ids(self, ids: list[str], on: bool) -> None: + """Set the torque state for specific motor names. + + Args: + ids (list[int]): List of motor IDs to set the torque state for. + on (bool): True to enable torque, False to disable. + + """ + assert self.c is not None, "Motor controller not initialized or already closed." + + assert ids is not None and len(ids) > 0, "IDs list cannot be empty or None." + + ids_int = [self.name2id[name] for name in ids] + + if on: + self.c.enable_torque_on_ids(ids_int) + else: + self.c.disable_torque_on_ids(ids_int) + + def _infer_control_mode(self) -> MotorControlMode: + assert self.c is not None, "Motor controller not initialized or already closed." + + torque = self.c.is_torque_enabled() + + if not torque: + return MotorControlMode.Disabled + + mode = self.c.get_stewart_platform_operating_mode() + if mode == 3: + return MotorControlMode.Enabled + elif mode == 1: + return MotorControlMode.GravityCompensation + else: + raise ValueError(f"Unknown motor control mode: {mode}") + + def read_hardware_errors(self) -> dict[str, list[str]]: + """Read hardware errors from the motor controller.""" + if self.c is None: + return {} + + def decode_hardware_error_byte(err_byte: int) -> list[str]: + # https://emanual.robotis.com/docs/en/dxl/x/xl330-m288/#hardware-error-status + bits_to_error = { + 0: "Input Voltage Error", + 2: "Overheating Error", + 4: "Electrical Shock Error", + 5: "Overload Error", + } + err_bits = [i for i in range(8) if (err_byte & (1 << i)) != 0] + return [bits_to_error[b] for b in err_bits if b in bits_to_error] + + def voltage_ok( + id: int, + allowed_max_voltage: float = 7.3, + ) -> bool: + assert self.c is not None, ( + "Motor controller not initialized or already closed." + ) + # https://emanual.robotis.com/docs/en/dxl/x/xl330-m288/#present-input-voltage + resp_bytes = self.c.async_read_raw_bytes(id, 144, 2) + resp = struct.unpack("h", bytes(resp_bytes))[0] + voltage: float = resp / 10.0 # in Volts + + return voltage <= allowed_max_voltage + + errors = {} + for name, id in self.c.get_motor_name_id().items(): + # https://emanual.robotis.com/docs/en/dxl/x/xl330-m288/#hardware-error-status + err_byte = self.c.async_read_raw_bytes(id, 70, 1) + assert len(err_byte) == 1 + err = decode_hardware_error_byte(err_byte[0]) + if err: + if "Input Voltage Error" in err: + if voltage_ok(id): + err.remove("Input Voltage Error") + + # To avoid logging empty errors like "Motor 1: []" + if len(err) > 0: + errors[name] = err + + return errors + + +@dataclass +class RobotBackendStatus: + """Status of the Robot Backend.""" + + ready: bool + motor_control_mode: MotorControlMode + last_alive: float | None + control_loop_stats: dict[str, Any] + error: str | None = None diff --git a/reachy_mini/src/reachy_mini/daemon/daemon.py b/reachy_mini/src/reachy_mini/daemon/daemon.py new file mode 100644 index 0000000000000000000000000000000000000000..96b642657653110187011ad13bf942d752e51e04 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/daemon.py @@ -0,0 +1,485 @@ +"""Daemon for Reachy Mini robot. + +This module provides a daemon that runs a backend for either a simulated Reachy Mini using Mujoco or a real Reachy Mini robot using a serial connection. +It includes methods to start, stop, and restart the daemon, as well as to check its status. +It also provides a command-line interface for easy interaction. +""" + +import asyncio +import json +import logging +import time +from dataclasses import asdict, dataclass +from enum import Enum +from importlib.metadata import PackageNotFoundError, version +from threading import Event, Thread +from typing import Any, Optional + +from reachy_mini.daemon.backend.abstract import MotorControlMode +from reachy_mini.daemon.utils import ( + convert_enum_to_dict, + find_serial_port, + get_ip_address, +) + +from ..io.zenoh_server import ZenohServer +from .backend.mujoco import MujocoBackend, MujocoBackendStatus +from .backend.robot import RobotBackend, RobotBackendStatus + + +class Daemon: + """Daemon for simulated or real Reachy Mini robot. + + Runs the server with the appropriate backend (Mujoco for simulation or RobotBackend for real hardware). + """ + + def __init__(self, log_level: str = "INFO", wireless_version: bool = False) -> None: + """Initialize the Reachy Mini daemon.""" + self.log_level = log_level + self.logger = logging.getLogger(__name__) + self.logger.setLevel(self.log_level) + + self.wireless_version = wireless_version + + self.backend: "RobotBackend | MujocoBackend | None" = None + # Get package version + try: + package_version = version("reachy_mini") + self.logger.info(f"Daemon version: {package_version}") + except PackageNotFoundError: + package_version = None + self.logger.warning("Could not determine daemon version") + + self._status = DaemonStatus( + state=DaemonState.NOT_INITIALIZED, + wireless_version=wireless_version, + simulation_enabled=None, + backend_status=None, + error=None, + wlan_ip=None, + version=package_version, + ) + self._thread_event_publish_status = Event() + + self._webrtc: Optional[Any] = ( + None # type GstWebRTC imported for wireless version only + ) + if wireless_version: + from reachy_mini.media.webrtc_daemon import GstWebRTC + + self._webrtc = GstWebRTC(log_level) + + async def start( + self, + sim: bool = False, + serialport: str = "auto", + scene: str = "empty", + localhost_only: bool = True, + wake_up_on_start: bool = True, + check_collision: bool = False, + kinematics_engine: str = "AnalyticalKinematics", + headless: bool = False, + hardware_config_filepath: str | None = None, + ) -> "DaemonState": + """Start the Reachy Mini daemon. + + Args: + sim (bool): If True, run in simulation mode using Mujoco. Defaults to False. + serialport (str): Serial port for real motors. Defaults to "auto", which will try to find the port automatically. + scene (str): Name of the scene to load in simulation mode ("empty" or "minimal"). Defaults to "empty". + localhost_only (bool): If True, restrict the server to localhost only clients. Defaults to True. + wake_up_on_start (bool): If True, wake up Reachy Mini on start. Defaults to True. + check_collision (bool): If True, enable collision checking. Defaults to False. + kinematics_engine (str): Kinematics engine to use. Defaults to "AnalyticalKinematics". + headless (bool): If True, run Mujoco in headless mode (no GUI). Defaults to False. + hardware_config_filepath (str | None): Path to the hardware configuration YAML file. Defaults to None. + + Returns: + DaemonState: The current state of the daemon after attempting to start it. + + """ + if self._status.state == DaemonState.RUNNING: + self.logger.warning("Daemon is already running.") + return self._status.state + + self.logger.info( + f"Daemon start parameters: sim={sim}, serialport={serialport}, scene={scene}, localhost_only={localhost_only}, wake_up_on_start={wake_up_on_start}, check_collision={check_collision}, kinematics_engine={kinematics_engine}, headless={headless}, hardware_config_filepath={hardware_config_filepath}" + ) + + self._status.simulation_enabled = sim + + if not localhost_only: + self._status.wlan_ip = get_ip_address() + + self._start_params = { + "sim": sim, + "serialport": serialport, + "headless": headless, + "scene": scene, + "localhost_only": localhost_only, + } + + self.logger.info("Starting Reachy Mini daemon...") + self._status.state = DaemonState.STARTING + + try: + self.backend = self._setup_backend( + wireless_version=self.wireless_version, + sim=sim, + serialport=serialport, + scene=scene, + check_collision=check_collision, + kinematics_engine=kinematics_engine, + headless=headless, + hardware_config_filepath=hardware_config_filepath, + ) + except Exception as e: + self._status.state = DaemonState.ERROR + self._status.error = str(e) + raise e + + self.server = ZenohServer(self.backend, localhost_only=localhost_only) + self.server.start() + + self._thread_publish_status = Thread(target=self._publish_status, daemon=True) + self._thread_publish_status.start() + + def backend_wrapped_run() -> None: + assert self.backend is not None, ( + "Backend should be initialized before running." + ) + + try: + self.backend.wrapped_run() + except Exception as e: + self.logger.error(f"Backend encountered an error: {e}") + self._status.state = DaemonState.ERROR + self._status.error = str(e) + self.server.stop() + self.backend = None + + self.backend_run_thread = Thread(target=backend_wrapped_run) + self.backend_run_thread.start() + + if not self.backend.ready.wait(timeout=2.0): + self.logger.error( + "Backend is not ready after 2 seconds. Some error occurred." + ) + self._status.state = DaemonState.ERROR + self._status.error = self.backend.error + return self._status.state + + if wake_up_on_start: + try: + self.logger.info("Waking up Reachy Mini...") + self.backend.set_motor_control_mode(MotorControlMode.Enabled) + await self.backend.wake_up() + except Exception as e: + self.logger.error(f"Error while waking up Reachy Mini: {e}") + self._status.state = DaemonState.ERROR + self._status.error = str(e) + return self._status.state + except KeyboardInterrupt: + self.logger.warning("Wake up interrupted by user.") + self._status.state = DaemonState.STOPPING + return self._status.state + + if self._webrtc: + await asyncio.sleep( + 0.2 + ) # Give some time for the backend to release the audio device + self._webrtc.start() + + self.logger.info("Daemon started successfully.") + self._status.state = DaemonState.RUNNING + return self._status.state + + async def stop(self, goto_sleep_on_stop: bool = True) -> "DaemonState": + """Stop the Reachy Mini daemon. + + Args: + goto_sleep_on_stop (bool): If True, put Reachy Mini to sleep on stop. Defaults to True. + + Returns: + DaemonState: The current state of the daemon after attempting to stop it. + + """ + if self._status.state == DaemonState.STOPPED: + self.logger.warning("Daemon is already stopped.") + return self._status.state + + if self.backend is None: + self.logger.info("Daemon backend is not initialized.") + self._status.state = DaemonState.STOPPED + return self._status.state + + try: + if self._status.state in (DaemonState.STOPPING, DaemonState.ERROR): + goto_sleep_on_stop = False + + self.logger.info("Stopping Reachy Mini daemon...") + self._status.state = DaemonState.STOPPING + self.backend.is_shutting_down = True + self._thread_event_publish_status.set() + self.server.stop() + + if self._webrtc: + self._webrtc.stop() + + if goto_sleep_on_stop: + try: + self.logger.info("Putting Reachy Mini to sleep...") + self.backend.set_motor_control_mode(MotorControlMode.Enabled) + await self.backend.goto_sleep() + self.backend.set_motor_control_mode(MotorControlMode.Disabled) + except Exception as e: + self.logger.error(f"Error while putting Reachy Mini to sleep: {e}") + self._status.state = DaemonState.ERROR + self._status.error = str(e) + except KeyboardInterrupt: + self.logger.warning("Sleep interrupted by user.") + self._status.state = DaemonState.STOPPING + + self.backend.should_stop.set() + self.backend_run_thread.join(timeout=5.0) + if self.backend_run_thread.is_alive(): + self.logger.warning("Backend did not stop in time, forcing shutdown.") + self._status.state = DaemonState.ERROR + + self.backend.close() + self.backend.ready.clear() + + if self._status.state != DaemonState.ERROR: + self.logger.info("Daemon stopped successfully.") + self._status.state = DaemonState.STOPPED + except Exception as e: + self.logger.error(f"Error while stopping the daemon: {e}") + self._status.state = DaemonState.ERROR + self._status.error = str(e) + except KeyboardInterrupt: + self.logger.warning("Daemon already stopping...") + + if self.backend is not None: + backend_status = self.backend.get_status() + if backend_status.error: + self._status.state = DaemonState.ERROR + + self.backend = None + + return self._status.state + + async def restart( + self, + sim: Optional[bool] = None, + serialport: Optional[str] = None, + scene: Optional[str] = None, + headless: Optional[bool] = None, + localhost_only: Optional[bool] = None, + wake_up_on_start: Optional[bool] = None, + goto_sleep_on_stop: Optional[bool] = None, + ) -> "DaemonState": + """Restart the Reachy Mini daemon. + + Args: + sim (bool): If True, run in simulation mode using Mujoco. Defaults to None (uses the previous value). + serialport (str): Serial port for real motors. Defaults to None (uses the previous value). + scene (str): Name of the scene to load in simulation mode ("empty" or "minimal"). Defaults to None (uses the previous value). + headless (bool): If True, run Mujoco in headless mode (no GUI). Defaults to None (uses the previous value). + localhost_only (bool): If True, restrict the server to localhost only clients. Defaults to None (uses the previous value). + wake_up_on_start (bool): If True, wake up Reachy Mini on start. Defaults to None (don't wake up). + goto_sleep_on_stop (bool): If True, put Reachy Mini to sleep on stop. Defaults to None (don't go to sleep). + + Returns: + DaemonState: The current state of the daemon after attempting to restart it. + + """ + if self._status.state == DaemonState.STOPPED: + self.logger.warning("Daemon is not running.") + return self._status.state + + if self._status.state in (DaemonState.RUNNING, DaemonState.ERROR): + self.logger.info("Restarting Reachy Mini daemon...") + + await self.stop( + goto_sleep_on_stop=goto_sleep_on_stop + if goto_sleep_on_stop is not None + else False + ) + params: dict[str, Any] = { + "sim": sim if sim is not None else self._start_params["sim"], + "serialport": serialport + if serialport is not None + else self._start_params["serialport"], + "scene": scene if scene is not None else self._start_params["scene"], + "headless": headless + if headless is not None + else self._start_params["headless"], + "localhost_only": localhost_only + if localhost_only is not None + else self._start_params["localhost_only"], + "wake_up_on_start": wake_up_on_start + if wake_up_on_start is not None + else False, + } + + return await self.start(**params) + + raise NotImplementedError( + "Restarting is only supported when the daemon is in RUNNING or ERROR state." + ) + + def status(self) -> "DaemonStatus": + """Get the current status of the Reachy Mini daemon.""" + if self.backend is not None: + self._status.backend_status = self.backend.get_status() + + assert self._status.backend_status is not None, ( + "Backend status should not be None after backend initialization." + ) + + if self._status.backend_status.error: + self._status.state = DaemonState.ERROR + self._status.error = self._status.backend_status.error + else: + self._status.backend_status = None + + return self._status + + def _publish_status(self) -> None: + self._thread_event_publish_status.clear() + while self._thread_event_publish_status.is_set() is False: + json_str = json.dumps( + asdict(self.status(), dict_factory=convert_enum_to_dict) + ) + self.server.pub_status.put(json_str) + time.sleep(1) + + async def run4ever( + self, + sim: bool = False, + serialport: str = "auto", + scene: str = "empty", + localhost_only: bool = True, + wake_up_on_start: bool = True, + goto_sleep_on_stop: bool = True, + check_collision: bool = False, + kinematics_engine: str = "AnalyticalKinematics", + headless: bool = False, + ) -> None: + """Run the Reachy Mini daemon indefinitely. + + First, it starts the daemon, then it keeps checking the status and allows for graceful shutdown on user interrupt (Ctrl+C). + + Args: + sim (bool): If True, run in simulation mode using Mujoco. Defaults to False. + serialport (str): Serial port for real motors. Defaults to "auto", which will try to find the port automatically. + scene (str): Name of the scene to load in simulation mode ("empty" or "minimal"). Defaults to "empty". + localhost_only (bool): If True, restrict the server to localhost only clients. Defaults to True. + wake_up_on_start (bool): If True, wake up Reachy Mini on start. Defaults to True. + goto_sleep_on_stop (bool): If True, put Reachy Mini to sleep on stop. Defaults to True + check_collision (bool): If True, enable collision checking. Defaults to False. + kinematics_engine (str): Kinematics engine to use. Defaults to "AnalyticalKinematics". + headless (bool): If True, run Mujoco in headless mode (no GUI). Defaults to False. + + """ + await self.start( + sim=sim, + serialport=serialport, + scene=scene, + localhost_only=localhost_only, + wake_up_on_start=wake_up_on_start, + check_collision=check_collision, + kinematics_engine=kinematics_engine, + headless=headless, + ) + + if self._status.state == DaemonState.RUNNING: + try: + self.logger.info("Daemon is running. Press Ctrl+C to stop.") + while self.backend_run_thread.is_alive(): + self.logger.info(f"Daemon status: {self.status()}") + for _ in range(10): + self.backend_run_thread.join(timeout=1.0) + else: + self.logger.error("Backend thread has stopped unexpectedly.") + self._status.state = DaemonState.ERROR + except KeyboardInterrupt: + self.logger.warning("Daemon interrupted by user.") + except Exception as e: + self.logger.error(f"An error occurred: {e}") + self._status.state = DaemonState.ERROR + self._status.error = str(e) + + await self.stop(goto_sleep_on_stop) + + def _setup_backend( + self, + wireless_version: bool, + sim: bool, + serialport: str, + scene: str, + check_collision: bool, + kinematics_engine: str, + headless: bool, + hardware_config_filepath: str | None = None, + ) -> "RobotBackend | MujocoBackend": + if sim: + return MujocoBackend( + scene=scene, + check_collision=check_collision, + kinematics_engine=kinematics_engine, + headless=headless, + ) + else: + if serialport == "auto": + ports = find_serial_port(wireless_version=wireless_version) + + if len(ports) == 0: + raise RuntimeError( + "No Reachy Mini serial port found. " + "Check USB connection and permissions. " + "Or directly specify the serial port using --serialport." + ) + elif len(ports) > 1: + raise RuntimeError( + f"Multiple Reachy Mini serial ports found {ports}." + "Please specify the serial port using --serialport." + ) + + serialport = ports[0] + self.logger.info(f"Found Reachy Mini serial port: {serialport}") + + self.logger.info( + f"Creating RobotBackend with parameters: serialport={serialport}, check_collision={check_collision}, kinematics_engine={kinematics_engine}" + ) + return RobotBackend( + serialport=serialport, + log_level=self.log_level, + check_collision=check_collision, + kinematics_engine=kinematics_engine, + hardware_config_filepath=hardware_config_filepath, + ) + + +class DaemonState(Enum): + """Enum representing the state of the Reachy Mini daemon.""" + + NOT_INITIALIZED = "not_initialized" + STARTING = "starting" + RUNNING = "running" + STOPPING = "stopping" + STOPPED = "stopped" + ERROR = "error" + + +@dataclass +class DaemonStatus: + """Dataclass representing the status of the Reachy Mini daemon.""" + + state: DaemonState + wireless_version: bool + simulation_enabled: Optional[bool] + backend_status: Optional[RobotBackendStatus | MujocoBackendStatus] + error: Optional[str] = None + wlan_ip: Optional[str] = None + version: Optional[str] = None diff --git a/reachy_mini/src/reachy_mini/daemon/utils.py b/reachy_mini/src/reachy_mini/daemon/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..56230067d1b324d76587e4712160b2f8b6337631 --- /dev/null +++ b/reachy_mini/src/reachy_mini/daemon/utils.py @@ -0,0 +1,115 @@ +"""Utilities for managing the Reachy Mini daemon.""" + +import os +import socket +import struct +import subprocess +import time +from enum import Enum +from typing import Any, List + +import psutil +import serial.tools.list_ports + + +def daemon_check(spawn_daemon: bool, use_sim: bool) -> None: + """Check if the Reachy Mini daemon is running and spawn it if necessary.""" + + def is_python_script_running( + script_name: str, + ) -> tuple[bool, int | None, bool | None]: + """Check if a specific Python script is running.""" + found_script = False + simluation_enabled = False + for proc in psutil.process_iter(["pid", "name", "cmdline"]): + try: + for cmd in proc.info["cmdline"]: + if script_name in cmd: + found_script = True + if "--sim" in cmd: + simluation_enabled = True + if found_script: + return True, proc.pid, simluation_enabled + except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): + continue + return False, None, None + + if spawn_daemon: + daemon_is_running, pid, sim = is_python_script_running("reachy-mini-daemon") + if daemon_is_running and sim == use_sim: + print( + f"Reachy Mini daemon is already running (PID: {pid}). " + "No need to spawn a new one." + ) + return + elif daemon_is_running and sim != use_sim: + print( + f"Reachy Mini daemon is already running (PID: {pid}) with a different configuration. " + ) + print("Killing the existing daemon...") + assert pid is not None, "PID should not be None if daemon is running" + os.kill(pid, 9) + time.sleep(1) + + print("Starting a new daemon...") + subprocess.Popen( + ["reachy-mini-daemon", "--sim"] if use_sim else ["reachy-mini-daemon"], + start_new_session=True, + ) + + +def find_serial_port( + wireless_version: bool = False, + vid: str = "1a86", + pid: str = "55d3", + pi_uart: str = "/dev/ttyAMA3", +) -> list[str]: + """Find the serial port for Reachy Mini based on VID and PID or the Raspberry Pi UART for the wireless version. + + Args: + wireless_version (bool): Whether to look for the wireless version using the Raspberry Pi UART. + vid (str): Vendor ID of the device. (eg. "1a86"). + pid (str): Product ID of the device. (eg. "55d3"). + pi_uart (str): Path to the Raspberry Pi UART device. (eg. "/dev/ttyAMA3"). + + """ + # If it's a wireless version, we should use the Raspberry Pi UART + if wireless_version: + return [pi_uart] if os.path.exists(pi_uart) else [] + + # If it's a lite version, we should find it using the VID and PID + ports = serial.tools.list_ports.comports() + + vid = vid.upper() + pid = pid.upper() + + return [p.device for p in ports if f"USB VID:PID={vid}:{pid}" in p.hwid] + + +def get_ip_address(ifname: str = "wlan0") -> str | None: + """Get the IP address of a specific network interface (Linux Only).""" + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + import fcntl + + return socket.inet_ntoa( + fcntl.ioctl( + s.fileno(), + 0x8915, # SIOCGIFADDR + struct.pack("256s", ifname[:15].encode("utf-8")), + )[20:24] + ) + except OSError: + print(f"Could not get IP address for interface {ifname}.") + return None + + +def convert_enum_to_dict(data: List[Any]) -> dict[str, Any]: + """Convert a dataclass containing Enums to a dictionary with enum values.""" + + def convert_value(obj: Any) -> Any: + if isinstance(obj, Enum): + return obj.value + return obj + + return dict((k, convert_value(v)) for k, v in data) diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.part new file mode 100644 index 0000000000000000000000000000000000000000..323829c404dac84610e29fae4f4079c973f4630e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "48f0e86376312f8ca242a082", + "fullConfiguration": "default", + "id": "MUIOPFRAXdyRYA5/y", + "isStandardContent": false, + "name": "5W_SPEAKER <1>", + "partId": "JFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.stl new file mode 100644 index 0000000000000000000000000000000000000000..00a29236bdb8101ddee079de562870f3a5877e12 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89c220ac5fa6dd559fcd2f3faccb7197904ab6b882ccf5d2ad04b17a09d58b98 +size 229884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.part new file mode 100644 index 0000000000000000000000000000000000000000..3e6670e8d45549d1de88eff9330188d29998fd6f --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "d5df0bcac25cddb763b3a090", + "fullConfiguration": "default", + "id": "MT+KnYpqaZ58+3raS", + "isStandardContent": false, + "name": "antenna <2>", + "partId": "JFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.stl new file mode 100644 index 0000000000000000000000000000000000000000..1dee4a7c0fd16b225385d5ef7866a802ea4ee18e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ebe995bfc23aa8f832e86065c364ddf5bf0c1341d6cd4da30790631c7e15a275 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..7b7ceb2108438e03d3e23bb4fd7e6bd75ffc9b68 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "M6OWFp5hfkfES9FmB", + "isStandardContent": false, + "name": "Antenna_body_3DPrint <2>", + "partId": "JF/", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..57603870b064c815155ec0a14b722b374291a492 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f760ace60b1a368ba7c51bcd01a152a85e66a587fb24d55886cb9d9ffb9008f +size 241784 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..01fa39d2ec059631dd9c404a337f35c189a554c1 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MHVB1f7lyvjCWrFJe", + "isStandardContent": false, + "name": "Antenna_Holder-L_3DPrint <1>", + "partId": "KFDB", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..661802d1420a882c69b935142c8bd2e6ad5b475b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2163af81f112d0e1503f284213e831ff7692960cbcb7085ad6db8b63912fd466 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..047b5202be64618854767faa97c9547622e8e4af --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MX6Uc6wQ4cFgySRks", + "isStandardContent": false, + "name": "Antenna_Holder-R_3DPrint <1>", + "partId": "JFv", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..2a3548a26c818890c82527ed4fa6f1a448678e4e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f516056c535ac6bc8ec94983e48945bfca75ccf17d058263bfe67c4883d8932 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..49e9dfb4a2f1f6ae62ded9bad7e1e89dafa13d46 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MObKCzX1Fco0wvr0/", + "isStandardContent": false, + "name": "Antenna_interface_3DPrint <2>", + "partId": "JF7", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..15b32f15011a3154fc5c832e7573d6dfac98b538 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:662384ed2de2c37fff6d5bab1ba0ccb76ee03f5d1680043d255e33e879b481bb +size 179984 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.part new file mode 100644 index 0000000000000000000000000000000000000000..6268a27d56b5bc11c338dd4130330ea77e290c13 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "ae2c63bc6f578a46d35cd365", + "fullConfiguration": "default", + "id": "MDupaBfND/yK9FERm", + "isStandardContent": false, + "name": "Arducam <1>", + "partId": "JGD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.stl new file mode 100644 index 0000000000000000000000000000000000000000..7badfd2fe38b5864a648f7736f64e70888077a9a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8916e1a5fe5ffd8c0c3eded5f173871be269a2c26a437db7f7039e6c8cc7a020 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arm.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arm.part new file mode 100644 index 0000000000000000000000000000000000000000..521486400deaaa9c9cbd828574baa9dcb29af98d --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arm.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MHbJVGQ/2CguoKbZz", + "isStandardContent": false, + "name": "Arm <1>", + "partId": "JsD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arm.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arm.stl new file mode 100644 index 0000000000000000000000000000000000000000..b104f0ad630bec3de1516e6148b4bde7ec9c7e60 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/arm.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1466fc2854bf4d3eb92b5f5f595e2c1a1dd90f8f9bbdcc581f88c541e72a47f +size 104784 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.part new file mode 100644 index 0000000000000000000000000000000000000000..afa468c7e48ae9fbd21eab01a9541462794d9df4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "Md1pPF2974d9JOL2l", + "isStandardContent": false, + "name": "B3B-EH <1>", + "partId": "JFr", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.stl new file mode 100644 index 0000000000000000000000000000000000000000..29565d9e384e88ae8aaaa9b10ff84fb12f89ba09 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:388ed3ff01359dac77cad8f1a14c4babeb4e2b72b5c1c60333fa2682bf62ac17 +size 9884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.part new file mode 100644 index 0000000000000000000000000000000000000000..a30748b802c7941da860393d9a0dc99cf1297c09 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "MMuPyh0yjSzJko9Po", + "isStandardContent": false, + "name": "B3B-EH_1 <1>", + "partId": "JFT", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.stl new file mode 100644 index 0000000000000000000000000000000000000000..268d4d96bd27d4134a27b0115589becd4a6e444b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a741e87c71a9ff662a24ab5d6c7b8397afc6a7f7506910992814506d98d8e21f +size 9884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/ball.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/ball.part new file mode 100644 index 0000000000000000000000000000000000000000..cdeff374fef867c1c0be03f0c6b79ccead7fb1d3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/ball.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "0aa833fd983f27ea7fb43256", + "fullConfiguration": "default", + "id": "Msm1EC3X/D1/s/Uus", + "isStandardContent": false, + "name": "Ball <13>", + "partId": "JSD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/ball.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/ball.stl new file mode 100644 index 0000000000000000000000000000000000000000..6261467e2f5ecd06c86600bdf01d22a1b4d70cab --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/ball.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa04fda74ce21c562e6ad5645c619c425ce2644f29463cef38ad791c3e98b1c7 +size 158484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.part new file mode 100644 index 0000000000000000000000000000000000000000..c80cc1b7772338e12004198fb2e655376f7c45ac --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "d5ff0fe74f14f26be2deb5d4", + "fullConfiguration": "default", + "id": "MYk5LvI8gIvlMtfS7", + "isStandardContent": false, + "name": "Bearing_85x110x13 <1>", + "partId": "JGD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.stl new file mode 100644 index 0000000000000000000000000000000000000000..751ac994ab783ba08d731006ca50d2c789252307 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d6052d367e0a9f36063a3be16c77e34d8c5da3bb001346a317b75f19b9e60fe +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.part new file mode 100644 index 0000000000000000000000000000000000000000..b5f2505e96232073a4b652b2eb2eddaa87272477 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "1aa49f5cc5d823754d8b1fec", + "fullConfiguration": "default", + "id": "MpioSzVOUQtkaeTVH", + "isStandardContent": false, + "name": "big_lens <1>", + "partId": "J0D", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.stl new file mode 100644 index 0000000000000000000000000000000000000000..5528ca0d5bf74e8e3d48709d244d9187ab36aadf --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28b05e56f4c9fcf6458ef7ae0a49b016251afbb463199095922eaac0d597bbe5 +size 266484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.part new file mode 100644 index 0000000000000000000000000000000000000000..d866fd19907b81ae2c610e1d13939d956425f95e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "f67f6ec9755019fa8d4cde38", + "fullConfiguration": "default", + "id": "M6vM68+58boAYt2AP", + "isStandardContent": false, + "name": "Big Lens D40 <1>", + "partId": "JFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.stl new file mode 100644 index 0000000000000000000000000000000000000000..afa5536066cdf16c9d355babcf7782f4a2a4a54b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4df711c8e29a677f62622d57c5cac01257ae9a44f46adb67fefb54b8fe52a6eb +size 151284 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..a35e3a2946f5fc2046131caa52616c4a53643654 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "M40W4a7sQuI8QEDbK", + "isStandardContent": false, + "name": "BODY-DOWN_3DPrint <1>", + "partId": "JFP", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..172d7baaebbd65b5cc0ca39e8f3a467201fde9e1 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3d46f953d49182f85fa818a5d3935c688afffdf4d7a0119aa58f9292a8e3707 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..07ac3aaa9b1993246e54ba9b5cdc8ac3ceb77db2 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MFPx9mgqcSNR4iAYO", + "isStandardContent": false, + "name": "BODY-FOOT_3DPrint <1>", + "partId": "JFH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..5f68209f5f49b37804f6f6bec23a243e5c4ece24 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eab9440d4d6745c99445dba3887f4668b48780e8a10aa1efc05e3f9481b40caf +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..17722be87830aed010dab466fc4555df2ba6847c --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MfqCGZgMWtuWpureN", + "isStandardContent": false, + "name": "BODY_TOP_3DPrint <1>", + "partId": "JFb", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..067b40f1f47f0bc3e905e17de3f529f3f3e4a6a3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b985a9288abfc9894335c609bf24943551ae185e855f40c9a9f89c6a7c0eb831 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..a967bb56a6d35d19dd106c2ecd4a0520416444a8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MttvYsoT0rlrLKDwS", + "isStandardContent": false, + "name": "BODY-TURNING_3DPrint <1>", + "partId": "JFL", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..0cd5f031f9086ea2d9661fb89e2e3a4064a279d3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0c9757573938050cb1c0a4c7fdf37d8bbb3f9cf28dc19444c3487c1c5765d264 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.part new file mode 100644 index 0000000000000000000000000000000000000000..001ff6567e8a116aafd456c3ecc575d61718947a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "MgqLgbONW+9OAHLGG", + "isStandardContent": false, + "name": "bottom_body <1>", + "partId": "RcDD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.stl new file mode 100644 index 0000000000000000000000000000000000000000..32350dd01a46e79c514d71bc8828e84f6729e3ed --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7b36963b7ae1cf06cc50aba61d5024df7f006274006671f378a0a52e29065eb +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.part new file mode 100644 index 0000000000000000000000000000000000000000..afd31549097f79cdc80dd406346fa098fd3d5720 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "MHzA6RZ/kEAMV93SN", + "isStandardContent": false, + "name": "BTS2_M2_6X8 <1>", + "partId": "JFL", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.stl new file mode 100644 index 0000000000000000000000000000000000000000..c9d6877ca329f3ed698cc3fbc48bda60958d1304 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:303a706276ef0a3dcf8b6deeabf73969d2c48cb6628209bf0fed825b622deccb +size 269184 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/README.m b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/README.m new file mode 100644 index 0000000000000000000000000000000000000000..edda0bc7176b6fcd4c13c398aa0216c36eaa9aaf --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/README.m @@ -0,0 +1 @@ +Created with: https://github.com/pollen-robotics/reachy_mini_stl_convexify \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl new file mode 100644 index 0000000000000000000000000000000000000000..b134982cae9842ee326de029634c65b0f1890489 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f92539090c8fbef3a292ffbdc6a1019828ad5e33a5b87354ad08032a59d0c35 +size 4884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl new file mode 100644 index 0000000000000000000000000000000000000000..dc98ea93cd56cbf43dc023e4f3df943f20c2220d --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9186fdc67813c3b7f3fba721cbfbb14d5e6f20bcabe1897d488913b6879bfd78 +size 4784 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl new file mode 100644 index 0000000000000000000000000000000000000000..592ecb1efa1423f521ef6f4ba8202982f42a1c5d --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2db1d2726afd373e145a7b3cb8340983eeff49c07f8e4057e2d4eec7f91c35df +size 4884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl new file mode 100644 index 0000000000000000000000000000000000000000..2bea29e74aa6e2c47e3e59f8fadd02cb9f36f1b5 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e7916bfcdccd254c51143774575c7a0924a1a1939fd9a4755ae3b8f2c920bdc +size 4884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl new file mode 100644 index 0000000000000000000000000000000000000000..728659d336df95aa543bf2e93753747d4aa6ed88 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94d9c386d10344ae4fa03baae3ea0ca935c8ab2a5d41352a4b4c59c3ac2fd9e1 +size 4884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl new file mode 100644 index 0000000000000000000000000000000000000000..d296a17e93a2f2ecc90374dd69931f453c29d241 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e893cc8cd9581722ffe7798031076190cdc2264edc70694d925be5cf326b8bc2 +size 4884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl new file mode 100644 index 0000000000000000000000000000000000000000..d990c5488dd499dd50f333409209da943c591a43 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ec16d901b544cd898eb1836d4f61fc16855919bd856c82f0fd23ac180e684af +size 4884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/head_one_3dprint_collider_0.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/head_one_3dprint_collider_0.stl new file mode 100644 index 0000000000000000000000000000000000000000..b5a036399c116ef5cf2413cecff5c2734e368e36 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/head_one_3dprint_collider_0.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ba0e5a4dc95869e16212e69fa3712ea7f021378cf76db0b1a8d2300eaab3c64 +size 6884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_0.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_0.stl new file mode 100644 index 0000000000000000000000000000000000000000..6e405fc6959d1daf7a57d2c089733783dcf06e0f --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_0.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c22bb171ab47155a4fe2946cd267f8e43cba901dd11d3106082bbe1848f90b4 +size 190084 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_1.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_1.stl new file mode 100644 index 0000000000000000000000000000000000000000..34019f999ae4a5fa23f8041ce2759f927def44c8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_1.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a2c6189ab48a1b296ab5e0695363ab20021154dc7823d3eef8a188b992c1682 +size 195784 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_2.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_2.stl new file mode 100644 index 0000000000000000000000000000000000000000..67603dad86fad7502cff1fe8bac2023d0263570c --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_2.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbdf0d34da912a29174148bd78b90e3541755f9bc20d2a5cc624e3565aef3d94 +size 78684 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_3.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_3.stl new file mode 100644 index 0000000000000000000000000000000000000000..37d6256085c7585cef1e375b23450dee51b551b0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_3.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e7c26eb2033477e711d6ea535b955a91f443b74d21a4d8e5ed1bfb72c10c401 +size 245084 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_0.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_0.stl new file mode 100644 index 0000000000000000000000000000000000000000..f0f3c8dae35837c47e7c630011c89b8330b6ef90 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_0.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27dcf3bcfc55a11f5fe3a6a5f01fe253fb5e9cf9d736aa9b83a44d286aeef38c +size 185384 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_1.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_1.stl new file mode 100644 index 0000000000000000000000000000000000000000..ce58be8bce5e0e9b3a9b5c91d76167ce12e4a511 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_1.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89940a91f8e1bf1d1b7c4844bc58a8a03f5c3983cfc174573e8f60f6a47c1109 +size 182484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_2.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_2.stl new file mode 100644 index 0000000000000000000000000000000000000000..8964aa9383d3a6f3c59f79527b4b9959ea4e8cc5 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_2.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ccf48cd480051da28caee941ad1e130f74cebfd2c474d5791d5e014e10fcdfd +size 219184 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/head_one_3dprint_collider_0.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/head_one_3dprint_collider_0.stl new file mode 100644 index 0000000000000000000000000000000000000000..1d636e5fc50d5c6b06349b81a41b6c60c2857ac4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/head_one_3dprint_collider_0.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a28add53d3bc49c5b7f6d9e8f8f0884bbfa1ad9fe81af5ca58f01d08a072ed9 +size 1359584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.part new file mode 100644 index 0000000000000000000000000000000000000000..420f5df50f4a772a4de847dc44aff9acc747e308 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "M0s224h4t0HqzV/u4", + "isStandardContent": false, + "name": "DC15_A01_CASE_B_DUMMY <1>", + "partId": "JFf", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.stl new file mode 100644 index 0000000000000000000000000000000000000000..be16e3d867aeec0cd64d95ff10324f7b57d0da17 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b108f9390168a9052b408b292e316112f28e11d5ca51e28a374f29ce9ef2790 +size 248884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.part new file mode 100644 index 0000000000000000000000000000000000000000..95fecb125aa4742c5d8b229958d10121baa801bc --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "MJyRwhvvOMia59Q6o", + "isStandardContent": false, + "name": "DC15_A01_CASE_F_DUMMY <1>", + "partId": "JFj", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.stl new file mode 100644 index 0000000000000000000000000000000000000000..366b36df275c4b23ffa21d18f7d21e3364059056 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6de99b6af2361d2fdb751bcb78768e7565bc5b40fbdd6cda3e2c92f277135d33 +size 314484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.part new file mode 100644 index 0000000000000000000000000000000000000000..c3f473599d4d0994ac8386e21336af3d76a7e60b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "M6qXbiravwBh/M2FZ", + "isStandardContent": false, + "name": "DC15_A01_CASE_M_DUMMY <1>", + "partId": "JFn", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.stl new file mode 100644 index 0000000000000000000000000000000000000000..409e7a8400b24fa00e323e2c9f73c22d78129a95 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:716c7f05cb780b5eb1dc7e614b8376e587683f2922fcb386d0b8152a73b5af68 +size 162184 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.part new file mode 100644 index 0000000000000000000000000000000000000000..5e29396352f910c9971633c0a317ebdaa3c1b4f3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "M/hbODfuW0gbGU1TK", + "isStandardContent": false, + "name": "DC15_A01_HORN_DUMMY <9>", + "partId": "JFX", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.stl new file mode 100644 index 0000000000000000000000000000000000000000..bee160568e7c9b9c01f7632a6807a5fd8aee982d --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1fb77ee29fb48c09c125ae3a3cd4641673a08f513d3a5002f1453580a41c4cb +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.part new file mode 100644 index 0000000000000000000000000000000000000000..76e2a26f2606b2474ade0b1c632c6fb11e02fd4f --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "MFvbXu4svYiIz5iLO", + "isStandardContent": false, + "name": "DC15_A01_LED_CAP2_DUMMY <1>", + "partId": "JFv", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.stl new file mode 100644 index 0000000000000000000000000000000000000000..b8ff0e55b8b8160e539b5756e3f6bd82e62be0e9 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c8ea014b723e253c28fa3bf5062c794b18470cd7b5d6b33e723a9638d974f25 +size 1684 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.part new file mode 100644 index 0000000000000000000000000000000000000000..c1c9d50416f6a11d24ed211237730d83d5bfb574 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.part @@ -0,0 +1,14 @@ +{ + "configuration": "List_RLLNj5hPLm22K3=Default", + "documentId": "4e2472e743f2deb9dbfd3f29", + "documentMicroversion": "9cbc0f0673222989756dc3bd", + "documentVersion": "ab0d611cff58eb03c4b43922", + "elementId": "cb09afde2287e85126e219d6", + "fullConfiguration": "List_RLLNj5hPLm22K3=Default", + "id": "MQEuvqp2Q/VgvHc2b", + "isStandardContent": false, + "name": "drive_palonier <1>", + "partId": "JFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.stl new file mode 100644 index 0000000000000000000000000000000000000000..655a93f74785a9815052b77e84598c7c67e47965 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:161932a6a7d146aaa0e1c469154f8d9ee40bca2ba32356c1646f67a2ec47bcd7 +size 102584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.part new file mode 100644 index 0000000000000000000000000000000000000000..fd4edf4fc3970c295370cdb595e0ba27176e6bff --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.part @@ -0,0 +1,14 @@ +{ + "configuration": "List_RLLNj5hPLm22K3=Simple_Axe", + "documentId": "4e2472e743f2deb9dbfd3f29", + "documentMicroversion": "562fbad41f5c94b4e8929753", + "documentVersion": "b2b50e6fca74f541285598d2", + "elementId": "cb09afde2287e85126e219d6", + "fullConfiguration": "List_RLLNj5hPLm22K3=Simple_Axe", + "id": "MBlf2CAGFrM+vvrAc", + "isStandardContent": false, + "name": "drive_palonier <1>", + "partId": "JFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.stl new file mode 100644 index 0000000000000000000000000000000000000000..655a93f74785a9815052b77e84598c7c67e47965 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:161932a6a7d146aaa0e1c469154f8d9ee40bca2ba32356c1646f67a2ec47bcd7 +size 102584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.part new file mode 100644 index 0000000000000000000000000000000000000000..12d313dd432d12d02611c71afb432833cc8292b8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "1aa49f5cc5d823754d8b1fec", + "fullConfiguration": "default", + "id": "MiwRHVEzZiAIrPHOH", + "isStandardContent": false, + "name": "eye_support <1>", + "partId": "JXD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.stl new file mode 100644 index 0000000000000000000000000000000000000000..2e3afdd84ad308bfa756e466dfd04145b0fbb220 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:532e98b07d4b276853ce92806e65f9c4a3fbe2d792e962316f2ed60f687417f0 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/foot.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/foot.part new file mode 100644 index 0000000000000000000000000000000000000000..79308404fa471c38713cbb0c878c2665d1069fa6 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/foot.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MtAQxXNWlY7iX7UeA", + "isStandardContent": false, + "name": "Foot <1>", + "partId": "RICD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/foot.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/foot.stl new file mode 100644 index 0000000000000000000000000000000000000000..cec7d18f440553e24839cb52eeff292455594487 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/foot.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:764a08b710160df9e80eb56cde1a68d93627e776a504e8089b8bbc4e46834c9d +size 104784 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..a5ca077d93b7b4394c1571a63d602b3cc8fdbb53 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MsCmmfoZrFsTVz4Vs", + "isStandardContent": false, + "name": "GLASSES-DOLDER_3DPrint <1>", + "partId": "JFf", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..66835911c2bc4fb5718399ca3faca5965ac7c845 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:77786d52ead05d3f8c181d0b1bfbe3eaa8f42e0ae81e31847129bb031cbfe6c5 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..d48bd915e6455adc54a9530abcc8c82c94fcd90f --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MDdoiC6yCX9ILARl+", + "isStandardContent": false, + "name": "HEAD-BACK_3DPrint <1>", + "partId": "JFr", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..fac35aaa3fa9f4797eee7212959b4a4443ad9897 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e6e60fd980a2a48209471a0ddaac905b5d95c7081646e29c5af15cf3f1a681f +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..e23c54fe13c525a19ddd0f292445b8d6912babf4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MsTE6+BbSl0w4pt9R", + "isStandardContent": false, + "name": "HEAD-FRONT_3DPrint <1>", + "partId": "JFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..2189569d0796578b42bab48195aa246933950ee6 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3474bd1025c6b037e42d6d51428a1370ef88674b9a3988cd6b34e0be0d0049c2 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.part new file mode 100644 index 0000000000000000000000000000000000000000..aed7780b5abda9ed7923ab691da9a6036f6c88e2 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "M9OOCqJWvxnZHaK2L", + "isStandardContent": false, + "name": "head_head_back <1>", + "partId": "JsH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.stl new file mode 100644 index 0000000000000000000000000000000000000000..7acf9ec2f4fc6695531c8ce3020ea7e1a95a89b6 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:106ab6a5983028815da362f680c050606277704e167c1840939ba69af2817fa7 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.part new file mode 100644 index 0000000000000000000000000000000000000000..77a97bea047d5c778a67fb2d3f26d05a0ad83e8e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "Men72YbmKf99vvpY3", + "isStandardContent": false, + "name": "head_interface <1>", + "partId": "R/ED", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.stl new file mode 100644 index 0000000000000000000000000000000000000000..c7afd7b911673120cd44c9ee77c6ad7ffd592286 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:463bfc9c01aa004dd4519919c315d06bb2eff75e54fe47ba93d30cc61637a548 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..29d998933e499638ac6e39bd0ecfb84dd411ee45 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MuZC9z8GQmMdOw95U", + "isStandardContent": false, + "name": "HEAD-MIC_3DPrint <1>", + "partId": "JFj", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..1c74e83391471f48e040a9b54a115aaced5b3f6b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ea18530c4b9305199577d5301583e73f8c8f42694c6e8c50c8103f147da1be8 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.part new file mode 100644 index 0000000000000000000000000000000000000000..fbf68c3c2fddb5fd97aaaa16de52890fc18967ab --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "M326QNbEXm/j3BFCs", + "isStandardContent": false, + "name": "head_shell_front <1>", + "partId": "JsD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.stl new file mode 100644 index 0000000000000000000000000000000000000000..765e9cb34ee98f6cd600fbc13e2fff11505f4ecc --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d99b397fea112fc6893f5ae4b49fa886595c692e61d533b80eddf40de7bfc477 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..0c203f785318385d2e482018b335c2cf12c8aa1e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MJpFg+P4UMBokBVex", + "isStandardContent": false, + "name": "LENS-CAP-D30_3DPrint <1>", + "partId": "JFn", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..bc190353185d9502e6f671a5cda9e0c58032d572 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:564787bc9073bc68c1598b4674ce751e7a7ed883d305a5cb947d3398360d3737 +size 94284 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..072d2e7861c20c77d66616b95c2be13376a18b41 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "MVC/sOmzNQLy4mD6b", + "isStandardContent": false, + "name": "LENS-CAP-D40_3DPrint <1>", + "partId": "JF3", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..d7cb1d4d52fb366632e58609b8b97eca254c81cb --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e5a6364fba94a5a82d8a6512a7e042ccc78a0766756b190af055b0f08ef56471 +size 93684 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.part new file mode 100644 index 0000000000000000000000000000000000000000..0b8ca9e141c664383be1c7b4e5738027600456a5 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "05dc7ef344fe4c18be495b6e", + "fullConfiguration": "default", + "id": "MvKFrBJz+CmxF4Ta4", + "isStandardContent": false, + "name": "M12 fisheye lens 1.8mm <2>", + "partId": "JGD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.stl new file mode 100644 index 0000000000000000000000000000000000000000..4ee95bc2115804d7426f64d015b8ab1eeb86858a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf2e973bd164cd66b747f16e0ad6c4aafc9492e0b053fd40c283f4beba1b6015 +size 259284 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.part new file mode 100644 index 0000000000000000000000000000000000000000..eb39b918145dc9a79ff57c92655dbcf582e511a3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "1aa49f5cc5d823754d8b1fec", + "fullConfiguration": "default", + "id": "M8ZONSAd4C6sMYKK/", + "isStandardContent": false, + "name": "M12_lens <1>", + "partId": "RZBD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.stl new file mode 100644 index 0000000000000000000000000000000000000000..dd67d13ea74c44329f3c19fb277741bd9df709f8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0225297313cb77de3d8d0efc2b83499fdab9448e479174a5ca83bef24479b85 +size 93684 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.part new file mode 100644 index 0000000000000000000000000000000000000000..37ecea4cb6d1ce978b06ac40a6b22c4d9267f05b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "M0rtL1h+tUfVmZG6t", + "isStandardContent": false, + "name": "Main Plate <1>", + "partId": "RjBD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.stl new file mode 100644 index 0000000000000000000000000000000000000000..648c6df7f68bcdc1bf0910ad51097a899575d9b2 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a900cdb05046319e1d6821350c785e2bc5a35f83a5392a01876b4cc90a9279eb +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.part new file mode 100644 index 0000000000000000000000000000000000000000..77cba6ea341cf82f6c09a7b04cdaf81e9eca5c10 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "Mxq3x/8HYdblICsdh", + "isStandardContent": false, + "name": "Mid Plate <1>", + "partId": "R9BD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.stl new file mode 100644 index 0000000000000000000000000000000000000000..17bcdb034acff48e5028b069e83e0f36a4dd4134 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf5afed640fabcd2093f495a1a5d2c71c421b253fb1d22a282d38b866ed3d0c6 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.part new file mode 100644 index 0000000000000000000000000000000000000000..ac721a20bbe4d363d9a76aaf7fa61f135a0cc482 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "Mw5N9cfkbCC/CpCKR", + "isStandardContent": false, + "name": "MP01062_STEWART_ARM_3 <1>", + "partId": "KFHB", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.stl new file mode 100644 index 0000000000000000000000000000000000000000..4fd08b227327003a45bf104d95377eb3c24602ac --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7b64f2de2a35b6feb9ed8ef728219f1a9600dfe6fcb70256a2e555cd6c49401e +size 155584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..16ce78dc2c61e1f70c7edeeb2a85841d152b7f98 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "M7r6qwCMs4B7OGi6t", + "isStandardContent": false, + "name": "NECK_REFERENCE_3DPrint <1>", + "partId": "JFz", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..fb2153b59a4f2e6b86642618500f39632333e233 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8de811dedf772b757b9b414f3af15154c97267050a84c21cd6be3e355fc23eb8 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.part new file mode 100644 index 0000000000000000000000000000000000000000..4034f3f6cad83d93c618705bbe191216bfd55432 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "MydIXO1yH59xsOSOQ", + "isStandardContent": false, + "name": "PHS_1_7X20_5_DC10 <1>", + "partId": "JFP", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.stl new file mode 100644 index 0000000000000000000000000000000000000000..a0f51417e2d4e782a557a9d604bb4698a14e129b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c3e9d4bddfe4a99c206feba0fe648c1e5caf0aefca6347c7a91ff8f425b58d35 +size 253184 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.part new file mode 100644 index 0000000000000000000000000000000000000000..04f5f1900e08385acbda7b363535343d9c0fb927 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "MyXqeYka8V5tcbv+v", + "isStandardContent": false, + "name": "PHS_1_7X20_5_DC10_1 <1>", + "partId": "JFb", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.stl new file mode 100644 index 0000000000000000000000000000000000000000..f58ca0991a755c8e6960a392c0c5dcf151207344 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9cd84a44f18b39aae56220bfcdfdbf8e39a809c57e4d07c3d7a718c7ab5669e +size 253184 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.part new file mode 100644 index 0000000000000000000000000000000000000000..c4fbc1e88f68eab945d05ad4fc6334cdb996ab6a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "M0HCg1i79OnE6gOgz", + "isStandardContent": false, + "name": "PHS_1_7X20_5_DC10_2 <1>", + "partId": "JFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.stl new file mode 100644 index 0000000000000000000000000000000000000000..9a284934b4a1faf77ea41e7d4581f7776624a515 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ceba1b5c64923e7b29c5a686d753748b8a99496890ebe850694cba50d306d690 +size 253184 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.part new file mode 100644 index 0000000000000000000000000000000000000000..8c06bdd03deaf955f57e8922c85cfe325257d0ed --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "2cfe27202252cfce42ed7ee4", + "fullConfiguration": "default", + "id": "MwHtRhbbnn9zJhJOY", + "isStandardContent": false, + "name": "PHS_1_7X20_5_DC10_3 <1>", + "partId": "JFH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.stl new file mode 100644 index 0000000000000000000000000000000000000000..e6535203c2c91a6b4920769a140c428760629940 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3b446022c08e14a7d7e18ddfc5a5e979347abe1f3165d7d161b630f107964b26 +size 253184 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.part new file mode 100644 index 0000000000000000000000000000000000000000..f85a0306ce25ade315501a3aecbf79f892f197f4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MwlYHRbOjWaQ7Zawb", + "isStandardContent": false, + "name": "Plateform <1>", + "partId": "J4D", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.stl new file mode 100644 index 0000000000000000000000000000000000000000..939d8dc9d7b223eed0817fbd6be09d81b140ac71 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:470e7d22f7218cd5e71866947887e2793d52b6301276e005e313e30a875637f7 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.part new file mode 100644 index 0000000000000000000000000000000000000000..f882825b8a1628740ffc7aa73466318ab9ba6353 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MO1xdetqkz/QRPtZr", + "isStandardContent": false, + "name": "PP00XXX_Stewart Rod <6>", + "partId": "RcCD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.stl new file mode 100644 index 0000000000000000000000000000000000000000..06bde5f4a1879cd3f19dd06b0adafec970f25a7e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:411e6736ad0961062f5bea0283762f654bb728fef310d0993f9f7634c8b5449f +size 28884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.part new file mode 100644 index 0000000000000000000000000000000000000000..c469af37e2d0078acf71e9716f6ed8bed4947419 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "M9NEGUdCOXFxFyRZI", + "isStandardContent": false, + "name": "PP01062_Stewart Arm <5>", + "partId": "JpD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.stl new file mode 100644 index 0000000000000000000000000000000000000000..3afe074da185977ec1f12a7e98e36d7674b458c8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ca4060f4c178a84d4ef862270aa95c40646f2fc77913ac38e1bed40fc1d883c +size 125184 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.part new file mode 100644 index 0000000000000000000000000000000000000000..7e0cd0650bca5e81cee765cdfd78aad42d3620bc --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MdkzMSXOA7GnM40pG", + "isStandardContent": false, + "name": "PP01063_Stewart Plateform <1>", + "partId": "J2D", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.stl new file mode 100644 index 0000000000000000000000000000000000000000..e27cf3db9d3bb0fe6b49bb668462f79f18822eb3 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0de1f6657863b4f31f0f2492efc158fddc720272f4a4e38af17f2c10642ffbca +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.part new file mode 100644 index 0000000000000000000000000000000000000000..4d7a2a307c71a17ea6ada95bd2bde3a79222ea36 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MwQmuwlK0NX0T4TgA", + "isStandardContent": false, + "name": "PP01064_Stewart Main Plate <1>", + "partId": "RBCD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.stl new file mode 100644 index 0000000000000000000000000000000000000000..328e8ca592e84394d2921b60a29b34c6546cee41 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63b53dfef166197bc6c1f4b9d797b9009672fb963b9a5b6e65acc9f16e1b6219 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.part new file mode 100644 index 0000000000000000000000000000000000000000..270b9c1937a7e503ad992715b06511ee1a53f9ed --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MzgaD5MojzhSvLjc9", + "isStandardContent": false, + "name": "PP01065_Stewart Side Plate <2>", + "partId": "RgBD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.stl new file mode 100644 index 0000000000000000000000000000000000000000..bee55789e54cda969a531ae7db6a0340163e4e7a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:999d01af4da296fa318009982fb2354c5d51eb7810737aef5affca8f3d83daca +size 293584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.part new file mode 100644 index 0000000000000000000000000000000000000000..dae987e01bf508c8410b443d2ff654b71b0e1566 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "Mj2rCiqdYnLvw/uK1", + "isStandardContent": false, + "name": "PP01066_Stewart Mid Plate <1>", + "partId": "RgCD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.stl new file mode 100644 index 0000000000000000000000000000000000000000..4a18b059711e1c5fc3196c6addabf201a669d65a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:486214efae3c0d3b72460ba09f0088d33a7ad841c10180b54108427278780789 +size 176784 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.part new file mode 100644 index 0000000000000000000000000000000000000000..15c8dbc294b98be512d0c8fcb9b4cb9ba8e8894a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "M1iw9QOQmsFr6efSd", + "isStandardContent": false, + "name": "PP01067_bottom_body <1>", + "partId": "RjDD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.stl new file mode 100644 index 0000000000000000000000000000000000000000..8ba8324b88df98dcdd465e3652dc1831af745adb --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca83667a9ff45433ca41b5e20edaabd38cb99f97d19a99576dfece8edf92d78c +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.part new file mode 100644 index 0000000000000000000000000000000000000000..93b4d715885817b5503d7a6123e2d621d46d758a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "MLhpIAfnvnDl50gJ1", + "isStandardContent": false, + "name": "PP01068_top_body <1>", + "partId": "RjDH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.stl new file mode 100644 index 0000000000000000000000000000000000000000..9e230bdd3aeb428a2897edcf7ab94dd8d066344b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:701c4ee80d16aa5257e706fa9cc0b8bbae2dd26138a6fd7860b99c7455ae3af7 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.part new file mode 100644 index 0000000000000000000000000000000000000000..eb09cbb58b7728ff272868beba06450637f77362 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "MbnmqHXEBd3bXe5NJ", + "isStandardContent": false, + "name": "PP01069_head_shell_front <1>", + "partId": "JsD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.stl new file mode 100644 index 0000000000000000000000000000000000000000..70ee36704a2e9869c5410d3120fbdffd2bab3aa6 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19ceb0df3c6655315ea012d4cb2622245d28eb302cbb690c859170ebd4b07425 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.part new file mode 100644 index 0000000000000000000000000000000000000000..7a9bfa9fea6b2a888bf4e8f16cb5335eb85a034c --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "MJZxED2VVtdkQeJoM", + "isStandardContent": false, + "name": "PP01070_head_head_back <1>", + "partId": "JsH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.stl new file mode 100644 index 0000000000000000000000000000000000000000..21b85657fc86cd8d0aed9dfb4bc363735c19ff3b --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27a4689edc4380df51b18ec336a80755b66a9b2cb7b4653f205d96d026a5a612 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.part new file mode 100644 index 0000000000000000000000000000000000000000..4969c1b39a66743411e6c2d1d0a167d7c2d2e120 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "MK6xlP0iZUknxGJ1B", + "isStandardContent": false, + "name": "PP01071_Turning bowl <1>", + "partId": "R1DD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.stl new file mode 100644 index 0000000000000000000000000000000000000000..864d7f877f3234fac9056ce915d64dd899bb0bee --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b146eebeeaac1be6fe652808db20f524e729011d3b8f82dc1a8cdc34922a2deb +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.part new file mode 100644 index 0000000000000000000000000000000000000000..4c48ab98e7540deb8a41bf445b7a80b5e27f4082 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "MmSemALQTmY3L94+u", + "isStandardContent": false, + "name": "PP01072_Turning End <1>", + "partId": "RlFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.stl new file mode 100644 index 0000000000000000000000000000000000000000..0e13f4bc5d3382938df9d2396f404e9032e189f5 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5a7353f73938b1023ca3dbbb4ad8a01faf5e144405ed342f535df16b004b418 +size 314484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.part new file mode 100644 index 0000000000000000000000000000000000000000..247efb33851e5e31ef47b1bee7bd0b0f804ac041 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "1aa49f5cc5d823754d8b1fec", + "fullConfiguration": "default", + "id": "Mc2vPy/hERQOFTVCl", + "isStandardContent": false, + "name": "PP01078_glasses <1>", + "partId": "JXD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.stl new file mode 100644 index 0000000000000000000000000000000000000000..1408f21c089be3d0264c476e257b79ca1541e5f4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a4b8b4ac202d582be3b2c3f4f9728ba582514625c3e27572262bbd7a2704b40 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.part new file mode 100644 index 0000000000000000000000000000000000000000..b66e78d8b3f5e72e5e129f6ee322b9e02f3f4302 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "1aa49f5cc5d823754d8b1fec", + "fullConfiguration": "default", + "id": "MZ30fBArLgpdr3sZr", + "isStandardContent": false, + "name": "PP01079_back_big_eye <1>", + "partId": "RJBD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.stl new file mode 100644 index 0000000000000000000000000000000000000000..7343b044e7938d61761001e9b41866f949d67343 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4081dc49bd47072d7cb11d725cb26a72d49af70a3fc0fc09d8b711bdbb1c98d1 +size 93684 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.part new file mode 100644 index 0000000000000000000000000000000000000000..d2386d8e648cf63b3fae83a2755b7a7ba8e8c4c0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "1aa49f5cc5d823754d8b1fec", + "fullConfiguration": "default", + "id": "M5wrNragj9mzp/cuf", + "isStandardContent": false, + "name": "PP01080_back_small_eye <1>", + "partId": "RNBD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.stl new file mode 100644 index 0000000000000000000000000000000000000000..7ce1913c31c92e6fa3fb95dce3978143030f0c71 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:734c337c5da05b7b1966fbc5b1a2daa64f5e8ddb885ecfae94dd0cf041ca2925 +size 50484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.part new file mode 100644 index 0000000000000000000000000000000000000000..0e49bdf2be8c70676127fbf5389c5dda42753860 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "ME3Sp1txkoCjeAr4W", + "isStandardContent": false, + "name": "PP01102_ArduCam_Carter <1>", + "partId": "KFLB", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.stl new file mode 100644 index 0000000000000000000000000000000000000000..866f890e8e519bdc0f08e10fe5d9f1a76e580522 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:edc115b09647cafaf2fd023cd940817b54c33ce04496e586fe9031bd7582c5c6 +size 109484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/rod.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/rod.part new file mode 100644 index 0000000000000000000000000000000000000000..03ff71e00212296f511feda97e8cca73babaa5b0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/rod.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MdJ+UkyUvvt4o0cNw", + "isStandardContent": false, + "name": "Rod <6>", + "partId": "R5BD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/rod.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/rod.stl new file mode 100644 index 0000000000000000000000000000000000000000..77d6b21aab89df33bd2a5eb442f1d9d7f3e77de0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/rod.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b1d0060be86f76bb7481fe3f9d6a02bf61386617ade8fb56cd8b5c449708be7 +size 28884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/shape.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/shape.part new file mode 100644 index 0000000000000000000000000000000000000000..81f2babe27f3286bf15f9b717d7b6e539fe75725 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/shape.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "0aa833fd983f27ea7fb43256", + "fullConfiguration": "default", + "id": "M53IEP0FWpyN7VrPP", + "isStandardContent": false, + "name": "Shape <12>", + "partId": "JHD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/shape.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/shape.stl new file mode 100644 index 0000000000000000000000000000000000000000..104739a309cb7e9da3f3022fff94584ef4893cf5 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/shape.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d24f09564c2713b74b392536023b4e055c013af91ee21252a8109ccd1327f8a +size 286284 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.part new file mode 100644 index 0000000000000000000000000000000000000000..11b71e68f3f345aa54435765fca4b18117149b75 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "f05b326e391ef37011cd1007", + "fullConfiguration": "default", + "id": "MZ6XefFx77VRcACDn", + "isStandardContent": false, + "name": "Side Plate <1>", + "partId": "RUBD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.stl new file mode 100644 index 0000000000000000000000000000000000000000..09b2c1b45ddf2c451b1e95e7bdd4f588139a7faa --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52878966da6e718df392da535a8d0b5a03b99b242e4e44d9b2303ddce969f7c9 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.part new file mode 100644 index 0000000000000000000000000000000000000000..6d8029c1ac9decf8459f1016f4daa8fbbded13cc --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "1aa49f5cc5d823754d8b1fec", + "fullConfiguration": "default", + "id": "M+k761oFhfeIyvr/G", + "isStandardContent": false, + "name": "small_lens <1>", + "partId": "J1D", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.stl new file mode 100644 index 0000000000000000000000000000000000000000..02df87e15a2ccfbbbb25da45eac50df2e7e8c0eb --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d284a1f2f79d7df815bcac24427b7167d0fba81bb125c00c7e451215047f71e +size 158484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.part new file mode 100644 index 0000000000000000000000000000000000000000..3d88ba9f73298b3d974f455671f78b836df1be85 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "f67f6ec9755019fa8d4cde38", + "fullConfiguration": "default", + "id": "MeOBTO0SVYe+Ls79P", + "isStandardContent": false, + "name": "Small Lens D30 <1>", + "partId": "JFH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.stl new file mode 100644 index 0000000000000000000000000000000000000000..8094f7e32450ded9ed331ccd7bbb17c5e4a806b0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c3f62174bc76b85b39e7835fc9e005fabde685677576c6c1e40753417fa922ec +size 158484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.part new file mode 100644 index 0000000000000000000000000000000000000000..d08be9b47acf91ee5d22bccd38e8c1fe8284a087 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "0c90fa98e702b6ba866efe06", + "fullConfiguration": "default", + "id": "MLAaNJd+l2AB7zwWF", + "isStandardContent": false, + "name": "stewart_link_ball <7>", + "partId": "JFD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.stl new file mode 100644 index 0000000000000000000000000000000000000000..1a9a1ea300afff8876d32f887b84d0d6784c54b6 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d24b6357fe780b9f54a550278fded8886524b732e2ec7765eeed1a8eee0e94bd +size 194484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.part new file mode 100644 index 0000000000000000000000000000000000000000..f6c45dff65f1e1ee06039c76d2a3bb0b6bf897b7 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "0c90fa98e702b6ba866efe06", + "fullConfiguration": "default", + "id": "Mzs67Fs/V5a1ifM8W", + "isStandardContent": false, + "name": "stewart_link_ball <10>", + "partId": "JGD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.stl new file mode 100644 index 0000000000000000000000000000000000000000..24023fd4e3c3ca9000ffbb92ce8b56021836b330 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25041196fb7b87a0118d1b283e97bcd56a961aafd08527f1408cc23077e77285 +size 194484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.part new file mode 100644 index 0000000000000000000000000000000000000000..e64de22e38d2d2ce466a6de4370365f6e33808d8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "0c90fa98e702b6ba866efe06", + "fullConfiguration": "default", + "id": "MHKZQKk3gjSPuG0gI", + "isStandardContent": false, + "name": "stewart_link_rod <6>", + "partId": "JFH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.stl new file mode 100644 index 0000000000000000000000000000000000000000..cea3397c14840081030e71bdd1935572930344fe --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecacaefa0d9407ee902fcddac86927a27b09a352c4539347dbe8dfcd827af986 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..08c274a4c5cd80ec13af03f40db911086b0db3bf --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "Mi3j82DWKTUoiYXon", + "isStandardContent": false, + "name": "STEWART_MAIN_PLATE_3DPrint <1>", + "partId": "JFT", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..f90d29504f1883cdb6bc5b71366e1d0068638c87 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9577be3c17eeb3447e5bb7e3a2ffab3f40d951b2b341ca25e06e74c35997780d +size 314484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.part new file mode 100644 index 0000000000000000000000000000000000000000..b5c08005958d4e04162360d109fa55660e0fa8d8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "7836ed39be931c6ece17e007", + "documentMicroversion": "22df16c0b36fccefd62a3ccb", + "elementId": "41e19b342cf83e0d866fde9b", + "fullConfiguration": "default", + "id": "M8OX4JdBklJa3ZAV2", + "isStandardContent": false, + "name": "STEWART_TRICAP_3DPrint <1>", + "partId": "JFX", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.stl new file mode 100644 index 0000000000000000000000000000000000000000..73766e4d18e34c5ccc941c369f9ba1a3949c3dce --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:44c9acd2445753459253e6a1a8cd8b5036e8d9d98becde750cdeb950a01500d4 +size 314484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.part new file mode 100644 index 0000000000000000000000000000000000000000..74857f2a9cc26c8648436c06107dd3b9198b06d1 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "MoUkZchlIKO7O02cZ", + "isStandardContent": false, + "name": "test_antenna <1>", + "partId": "RMCD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.stl new file mode 100644 index 0000000000000000000000000000000000000000..a16be17aeed6b22f7554c2ccd95623f805fcfdc4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2f1f31344e0b21ad6b433953b86713d3834e54c87e23e4f626e77e390bce6da +size 266484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.part new file mode 100644 index 0000000000000000000000000000000000000000..1ae8057428dff553b6b01d44638629bb882a5eab --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "MrCYnP6eA71aF9l+x", + "isStandardContent": false, + "name": "test_antenna_body <1>", + "partId": "RFCD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.stl new file mode 100644 index 0000000000000000000000000000000000000000..648959fd43206ee42bdc504730e2bbb6d3718c57 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f9dd0adbe7a9243b2a527d4c5cc0d960ae2e15148d3ab8882b8a2389864094d +size 314484 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.part new file mode 100644 index 0000000000000000000000000000000000000000..09d9a2c6d294b3ae46402001f84fab987429a9bd --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "Ma4FMD0Z/1T41GJcv", + "isStandardContent": false, + "name": "top_body <1>", + "partId": "RcDH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.stl new file mode 100644 index 0000000000000000000000000000000000000000..c8aeab9b0186ff0fec4b0fafea041297fc58b326 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e5c560740256a73f6dd3adeae424380fbf75acfe7056fdc1858a100cb7806fb1 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.part new file mode 100644 index 0000000000000000000000000000000000000000..a3e694b52b3a8e66e9404230e5cbd5ea4d2a8ac7 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "7031fc46a026e2d553617dca", + "elementId": "63ac215c84389096e60ba3ce", + "fullConfiguration": "default", + "id": "M8Ekuan84MeJgvaNm", + "isStandardContent": false, + "name": "Turning bowl <1>", + "partId": "RuDD", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.stl new file mode 100644 index 0000000000000000000000000000000000000000..9521ffb779dbc83c142c213851ba8e22bb5fadbd --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8af1cf9e3fb58111f59b95404a4b6e9f5edcc4cd23d0e5a3e74ad82bcce574c8 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.part new file mode 100644 index 0000000000000000000000000000000000000000..ecc0cc1664bd4dcda7fe4bc50f79285a03517c1e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.part @@ -0,0 +1,13 @@ +{ + "configuration": "default", + "documentId": "e305b26a84339af20c593973", + "documentMicroversion": "4913859d0d2ce0a13b3adb26", + "elementId": "022097d02976f241add4ce3a", + "fullConfiguration": "default", + "id": "MHLMmdBzC0KnRb5Hr", + "isStandardContent": false, + "name": "UC-A37_Rev.A.step <1>", + "partId": "KF7D", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.stl new file mode 100644 index 0000000000000000000000000000000000000000..47120af1c31a770be1c070c44baeffcf9f66e749 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f77f8ca32283c4d1953510273776dd7fdc2d3ae817be8f82750023e68a9cd3df +size 68784 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.part new file mode 100644 index 0000000000000000000000000000000000000000..a27769e55e1a621c39401c9aa2189a2c94fcb542 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.part @@ -0,0 +1,14 @@ +{ + "configuration": "List_RLLNj5hPLm22K3=Default", + "documentId": "4e2472e743f2deb9dbfd3f29", + "documentMicroversion": "9cbc0f0673222989756dc3bd", + "documentVersion": "ab0d611cff58eb03c4b43922", + "elementId": "cb09afde2287e85126e219d6", + "fullConfiguration": "List_RLLNj5hPLm22K3=Default", + "id": "MICc+zB1tkivCW+Y6", + "isStandardContent": false, + "name": "WJ-WK00-0122TOPCABINETCASE_95 <1>", + "partId": "JFT", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.stl new file mode 100644 index 0000000000000000000000000000000000000000..f3c50e4212a61ab269622111df8fa7a69199cb81 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a28441cb86868c45f3910d7e88a583b9b561f7abd061e4c1064abe8b18523513 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.part new file mode 100644 index 0000000000000000000000000000000000000000..b0a107caf01cdca78e1e2f28beed5c28d088b0e4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.part @@ -0,0 +1,14 @@ +{ + "configuration": "List_RLLNj5hPLm22K3=Simple_Axe", + "documentId": "4e2472e743f2deb9dbfd3f29", + "documentMicroversion": "562fbad41f5c94b4e8929753", + "documentVersion": "b2b50e6fca74f541285598d2", + "elementId": "cb09afde2287e85126e219d6", + "fullConfiguration": "List_RLLNj5hPLm22K3=Simple_Axe", + "id": "McPFfHZbW2/EPDp0S", + "isStandardContent": false, + "name": "WJ-WK00-0122TOPCABINETCASE_95 <1>", + "partId": "JFT", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.stl new file mode 100644 index 0000000000000000000000000000000000000000..2ee91f3dc788cbe6172d83f5ade0539245d84eed --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8eb77f6be288d16c44f0869824e53124b0fc05d70acf84f257ae0e91aa81bd04 +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.part new file mode 100644 index 0000000000000000000000000000000000000000..3c02cc5621688412646c78aa68a0c8eb360b71f9 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.part @@ -0,0 +1,14 @@ +{ + "configuration": "List_RLLNj5hPLm22K3=Default", + "documentId": "4e2472e743f2deb9dbfd3f29", + "documentMicroversion": "9cbc0f0673222989756dc3bd", + "documentVersion": "ab0d611cff58eb03c4b43922", + "elementId": "cb09afde2287e85126e219d6", + "fullConfiguration": "List_RLLNj5hPLm22K3=Default", + "id": "MX9cSWxeY0rpuKITc", + "isStandardContent": false, + "name": "WJ-WK00-0123MIDDLECASE_56 <1>", + "partId": "JFP", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.stl new file mode 100644 index 0000000000000000000000000000000000000000..eaaf8c5b50f7d96251041f901745f6ef8b761058 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4d233ef0122e27951d21461d8c30e90285708ede5672962e0340fe0185fc0ac +size 49684 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.part new file mode 100644 index 0000000000000000000000000000000000000000..bfdf0e9889107b6794bfaf91639ad28b772f3e21 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.part @@ -0,0 +1,14 @@ +{ + "configuration": "List_RLLNj5hPLm22K3=Simple_Axe", + "documentId": "4e2472e743f2deb9dbfd3f29", + "documentMicroversion": "562fbad41f5c94b4e8929753", + "documentVersion": "b2b50e6fca74f541285598d2", + "elementId": "cb09afde2287e85126e219d6", + "fullConfiguration": "List_RLLNj5hPLm22K3=Simple_Axe", + "id": "MJpNLRylDLT4+V3p5", + "isStandardContent": false, + "name": "WJ-WK00-0123MIDDLECASE_56 <1>", + "partId": "JFP", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.stl new file mode 100644 index 0000000000000000000000000000000000000000..4dce18fb456b8b3be8907532c1ac0f8442447b5d --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c459b2adcabec2a270ceec40a983cb9c640f01a9736992f276f8487f0d4ffb8 +size 49684 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.part new file mode 100644 index 0000000000000000000000000000000000000000..e03ef9ac01beddcec14720ed83198b121a23a7d0 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.part @@ -0,0 +1,14 @@ +{ + "configuration": "List_RLLNj5hPLm22K3=Default", + "documentId": "4e2472e743f2deb9dbfd3f29", + "documentMicroversion": "9cbc0f0673222989756dc3bd", + "documentVersion": "ab0d611cff58eb03c4b43922", + "elementId": "cb09afde2287e85126e219d6", + "fullConfiguration": "List_RLLNj5hPLm22K3=Default", + "id": "Mp+b1niKgywMWznYQ", + "isStandardContent": false, + "name": "WJ-WK00-0124BOTTOMCASE_45 <1>", + "partId": "JFH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.stl new file mode 100644 index 0000000000000000000000000000000000000000..2d0274d116f81dd6b0ba2f764a2327e6e785ea6f --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:651f10e580d0390ab84c1fbd3de339eabad094d5da678d4d62465abce8431178 +size 314584 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.part b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.part new file mode 100644 index 0000000000000000000000000000000000000000..dc46c65e95a8bd150c8ef6903a39c6a7be5da89a --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.part @@ -0,0 +1,14 @@ +{ + "configuration": "List_RLLNj5hPLm22K3=Simple_Axe", + "documentId": "4e2472e743f2deb9dbfd3f29", + "documentMicroversion": "562fbad41f5c94b4e8929753", + "documentVersion": "b2b50e6fca74f541285598d2", + "elementId": "cb09afde2287e85126e219d6", + "fullConfiguration": "List_RLLNj5hPLm22K3=Simple_Axe", + "id": "MGhQLzn6iUDbdNEjQ", + "isStandardContent": false, + "name": "WJ-WK00-0124BOTTOMCASE_45 <1>", + "partId": "JFH", + "suppressed": false, + "type": "Part" +} \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.stl b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.stl new file mode 100644 index 0000000000000000000000000000000000000000..2709632d96b4eeab9d6192666be9a32e45f9e066 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.stl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3b671571125f05c7069b1497e2c1b3f7db9ab579000e7c105b8f0a4b36808fe +size 104884 diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/config.json b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/config.json new file mode 100644 index 0000000000000000000000000000000000000000..10016f3b942b411477a38c0b2e81c94015eff08e --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/config.json @@ -0,0 +1,18 @@ +{ + "url": "https://cad.onshape.com/documents/7836ed39be931c6ece17e007/w/39d557f31a0ba179c9e7bd5b/e/c82436d68c7d00e142abc581", + "outputFormat": "urdf", + "robot_name": "robot", + "output_filename": "robot", + "ball_to_euler": true, + "ball_to_euler_order": "xyz", + "simplify_stls": true, + "max_stl_size": 0.3, + "joint_properties": { + "*": { + "max_velocity": 8 + }, + "passive*": { + "max_velocity": 1e8 + } + } +} diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot.urdf b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot.urdf new file mode 100644 index 0000000000000000000000000000000000000000..f141d8a4cc88feabc83536567620235346edb0b1 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot.urdf @@ -0,0 +1,3281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot.urdf.bak b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot.urdf.bak new file mode 100644 index 0000000000000000000000000000000000000000..65c5c15b36b9bf51cb60e1fce6515c11871da14f --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot.urdf.bak @@ -0,0 +1,3282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot_no_collision.urdf b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot_no_collision.urdf new file mode 100644 index 0000000000000000000000000000000000000000..4317f7e53fd0e09f5de2d30bf14c083549f22e84 --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot_no_collision.urdf @@ -0,0 +1,2316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot_simple_collision.urdf b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot_simple_collision.urdf new file mode 100644 index 0000000000000000000000000000000000000000..1326b3e7848b40c1ebad6fb7cabb703c42bc5e0d --- /dev/null +++ b/reachy_mini/src/reachy_mini/descriptions/reachy_mini/urdf/robot_simple_collision.urdf @@ -0,0 +1,2399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/reachy_mini/src/reachy_mini/io/__init__.py b/reachy_mini/src/reachy_mini/io/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e0888e2576d28a98185f8b32543808ab48c3965c --- /dev/null +++ b/reachy_mini/src/reachy_mini/io/__init__.py @@ -0,0 +1 @@ +"""IO module.""" diff --git a/reachy_mini/src/reachy_mini/io/abstract.py b/reachy_mini/src/reachy_mini/io/abstract.py new file mode 100644 index 0000000000000000000000000000000000000000..24b16ab743ef5a9f59d57769d4f4b995cfa7f191 --- /dev/null +++ b/reachy_mini/src/reachy_mini/io/abstract.py @@ -0,0 +1,70 @@ +"""Base classes for server and client implementations. + +These abstract classes define the interface for server and client components +in the Reachy Mini project. They provide methods for starting and stopping +the server, handling commands, and managing client connections. +""" + +from abc import ABC, abstractmethod +from threading import Event +from uuid import UUID + +from reachy_mini.io.protocol import AnyTaskRequest + + +class AbstractServer(ABC): + """Base class for server implementations.""" + + @abstractmethod + def start(self) -> None: + """Start the server.""" + pass + + @abstractmethod + def stop(self) -> None: + """Stop the server.""" + pass + + @abstractmethod + def command_received_event(self) -> Event: + """Wait for a new command and return it.""" + pass + + +class AbstractClient(ABC): + """Base class for client implementations.""" + + @abstractmethod + def wait_for_connection(self) -> None: + """Wait for the client to connect to the server.""" + pass + + @abstractmethod + def is_connected(self) -> bool: + """Check if the client is connected to the server.""" + pass + + @abstractmethod + def disconnect(self) -> None: + """Disconnect the client from the server.""" + pass + + @abstractmethod + def send_command(self, command: str) -> None: + """Send a command to the server.""" + pass + + @abstractmethod + def get_current_joints(self) -> tuple[list[float], list[float]]: + """Get the current joint positions.""" + pass + + @abstractmethod + def send_task_request(self, task_req: AnyTaskRequest) -> UUID: + """Send a task request to the server and return a unique task identifier.""" + pass + + @abstractmethod + def wait_for_task_completion(self, task_uid: UUID, timeout: float = 5.0) -> None: + """Wait for the specified task to complete.""" + pass diff --git a/reachy_mini/src/reachy_mini/io/protocol.py b/reachy_mini/src/reachy_mini/io/protocol.py new file mode 100644 index 0000000000000000000000000000000000000000..b1ecfdd2d36a953c026e6fe3839a796894309328 --- /dev/null +++ b/reachy_mini/src/reachy_mini/io/protocol.py @@ -0,0 +1,44 @@ +"""Protocol definitions for Reachy Mini client/server communication.""" + +from datetime import datetime +from uuid import UUID + +from pydantic import BaseModel + +from reachy_mini.utils.interpolation import InterpolationTechnique + + +class GotoTaskRequest(BaseModel): + """Class to represent a goto target task.""" + + head: list[float] | None # 4x4 flatten pose matrix + antennas: list[float] | None # [right_angle, left_angle] (in rads) + duration: float + method: InterpolationTechnique + body_yaw: float | None + + +class PlayMoveTaskRequest(BaseModel): + """Class to represent a play move task.""" + + move_name: str + + +AnyTaskRequest = GotoTaskRequest | PlayMoveTaskRequest + + +class TaskRequest(BaseModel): + """Class to represent any task request.""" + + uuid: UUID + req: AnyTaskRequest + timestamp: datetime + + +class TaskProgress(BaseModel): + """Class to represent task progress.""" + + uuid: UUID + finished: bool = False + error: str | None = None + timestamp: datetime diff --git a/reachy_mini/src/reachy_mini/io/zenoh_client.py b/reachy_mini/src/reachy_mini/io/zenoh_client.py new file mode 100644 index 0000000000000000000000000000000000000000..1668470bf0c8a9645e5234273f4c4526b96af140 --- /dev/null +++ b/reachy_mini/src/reachy_mini/io/zenoh_client.py @@ -0,0 +1,258 @@ +"""Zenoh client for Reachy Mini. + +This module implements a Zenoh client that allows communication with the Reachy Mini +robot. It subscribes to joint positions updates and allows sending commands to the robot. +""" + +import json +import threading +import time +from dataclasses import dataclass +from datetime import datetime +from typing import Any, Dict, List, Optional +from uuid import UUID, uuid4 + +import numpy as np +import numpy.typing as npt +import zenoh + +from reachy_mini.io.abstract import AbstractClient +from reachy_mini.io.protocol import AnyTaskRequest, TaskProgress, TaskRequest + + +class ZenohClient(AbstractClient): + """Zenoh client for Reachy Mini.""" + + def __init__(self, localhost_only: bool = True): + """Initialize the Zenoh client.""" + if localhost_only: + c = zenoh.Config.from_json5( + json.dumps( + { + "connect": { + "endpoints": { + "peer": ["tcp/localhost:7447"], + "router": [], + }, + }, + } + ) + ) + else: + c = zenoh.Config() + + self.joint_position_received = threading.Event() + self.head_pose_received = threading.Event() + self.status_received = threading.Event() + + self.session = zenoh.open(c) + self.cmd_pub = self.session.declare_publisher("reachy_mini/command") + + self.joint_sub = self.session.declare_subscriber( + "reachy_mini/joint_positions", + self._handle_joint_positions, + ) + + self.pose_sub = self.session.declare_subscriber( + "reachy_mini/head_pose", + self._handle_head_pose, + ) + + self.recording_sub = self.session.declare_subscriber( + "reachy_mini/recorded_data", + self._handle_recorded_data, + ) + + self.status_sub = self.session.declare_subscriber( + "reachy_mini/daemon_status", + self._handle_status, + ) + + self._last_head_joint_positions = None + self._last_antennas_joint_positions = None + self._last_head_pose: Optional[npt.NDArray[np.float64]] = None + self._recorded_data: Optional[ + List[Dict[str, float | List[float] | List[List[float]]]] + ] = None + self._recorded_data_ready = threading.Event() + self._is_alive = False + self._last_status: Dict[str, Any] = {} # contains a DaemonStatus + + self.tasks: dict[UUID, TaskState] = {} + self.task_request_pub = self.session.declare_publisher("reachy_mini/task") + self.task_progress_sub = self.session.declare_subscriber( + "reachy_mini/task_progress", + self._handle_task_progress, + ) + + def wait_for_connection(self, timeout: float = 5.0) -> None: + """Wait for the client to connect to the server. + + Args: + timeout (float): Maximum time to wait for the connection in seconds. + + Raises: + TimeoutError: If the connection is not established within the timeout period. + + """ + start = time.time() + while not self.joint_position_received.wait( + timeout=1.0 + ) or not self.head_pose_received.wait(timeout=1.0): + if time.time() - start > timeout: + self.disconnect() + raise TimeoutError( + "Timeout while waiting for connection with the server." + ) + print("Waiting for connection with the server...") + + self._is_alive = True + self._check_alive_evt = threading.Event() + threading.Thread(target=self.check_alive, daemon=True).start() + + def check_alive(self) -> None: + """Periodically check if the client is still connected to the server.""" + while True: + self._is_alive = self.is_connected() + self._check_alive_evt.set() + time.sleep(1.0) + + def is_connected(self) -> bool: + """Check if the client is connected to the server.""" + self.joint_position_received.clear() + self.head_pose_received.clear() + return self.joint_position_received.wait( + timeout=1.0 + ) and self.head_pose_received.wait(timeout=1.0) + + def disconnect(self) -> None: + """Disconnect the client from the server.""" + self.session.close() # type: ignore[no-untyped-call] + + def send_command(self, command: str) -> None: + """Send a command to the server.""" + if not self._is_alive: + raise ConnectionError("Lost connection with the server.") + + self.cmd_pub.put(command.encode("utf-8")) + + def _handle_joint_positions(self, sample: zenoh.Sample) -> None: + """Handle incoming joint positions.""" + if sample.payload: + positions = json.loads(sample.payload.to_string()) + self._last_head_joint_positions = positions.get("head_joint_positions") + self._last_antennas_joint_positions = positions.get( + "antennas_joint_positions" + ) + self.joint_position_received.set() + + def _handle_recorded_data(self, sample: zenoh.Sample) -> None: + """Handle incoming recorded data.""" + print("Received recorded data.") + if sample.payload: + data = json.loads(sample.payload.to_string()) + self._recorded_data = data + self._recorded_data_ready.set() + if self._recorded_data is not None: + print(f"Recorded data: {len(self._recorded_data)} frames received.") + + def _handle_status(self, sample: zenoh.Sample) -> None: + """Handle incoming status updates.""" + if sample.payload: + status = json.loads(sample.payload.to_string()) + self._last_status = status + self.status_received.set() + + def get_current_joints(self) -> tuple[list[float], list[float]]: + """Get the current joint positions.""" + assert ( + self._last_head_joint_positions is not None + and self._last_antennas_joint_positions is not None + ), "No joint positions received yet. Wait for the client to connect." + return ( + self._last_head_joint_positions.copy(), + self._last_antennas_joint_positions.copy(), + ) + + def wait_for_recorded_data(self, timeout: float = 5.0) -> bool: + """Block until the daemon publishes the frames (or timeout).""" + return self._recorded_data_ready.wait(timeout) + + def get_recorded_data( + self, wait: bool = True, timeout: float = 5.0 + ) -> Optional[List[Dict[str, float | List[float] | List[List[float]]]]]: + """Return the cached recording, optionally blocking until it arrives. + + Raises `TimeoutError` if nothing shows up in time. + """ + if wait and not self._recorded_data_ready.wait(timeout): + raise TimeoutError("Recording not received in time.") + self._recorded_data_ready.clear() # ready for next run + if self._recorded_data is not None: + return self._recorded_data.copy() + return None + + def get_status(self, wait: bool = True, timeout: float = 5.0) -> Dict[str, Any]: + """Get the last received status. Returns DaemonStatus as a dict.""" + if wait and not self.status_received.wait(timeout): + raise TimeoutError("Status not received in time.") + self.status_received.clear() # ready for next run + return self._last_status + + def _handle_head_pose(self, sample: zenoh.Sample) -> None: + """Handle incoming head pose.""" + if sample.payload: + pose = json.loads(sample.payload.to_string()) + self._last_head_pose = np.array(pose.get("head_pose")).reshape(4, 4) + self.head_pose_received.set() + + def get_current_head_pose(self) -> npt.NDArray[np.float64]: + """Get the current head pose.""" + assert self._last_head_pose is not None, "No head pose received yet." + return self._last_head_pose.copy() + + def send_task_request(self, task_req: AnyTaskRequest) -> UUID: + """Send a task request to the server.""" + if not self._is_alive: + raise ConnectionError("Lost connection with the server.") + + task = TaskRequest(uuid=uuid4(), req=task_req, timestamp=datetime.now()) + + self.tasks[task.uuid] = TaskState(event=threading.Event(), error=None) + + self.task_request_pub.put(task.model_dump_json()) + + return task.uuid + + def wait_for_task_completion(self, task_uid: UUID, timeout: float = 5.0) -> None: + """Wait for the specified task to complete.""" + if task_uid not in self.tasks: + raise ValueError("Task not found.") + + self.tasks[task_uid].event.wait(timeout) + + if not self.tasks[task_uid].event.is_set(): + raise TimeoutError("Task did not complete in time.") + if self.tasks[task_uid].error is not None: + raise Exception(f"Task failed with error: {self.tasks[task_uid].error}") + + del self.tasks[task_uid] + + def _handle_task_progress(self, sample: zenoh.Sample) -> None: + if sample.payload: + progress = TaskProgress.model_validate_json(sample.payload.to_string()) + assert progress.uuid in self.tasks, "Unknown task UUID." + + if progress.error: + self.tasks[progress.uuid].error = progress.error + + if progress.finished: + self.tasks[progress.uuid].event.set() + + +@dataclass +class TaskState: + """Represents the state of a task.""" + + event: threading.Event + error: str | None diff --git a/reachy_mini/src/reachy_mini/io/zenoh_server.py b/reachy_mini/src/reachy_mini/io/zenoh_server.py new file mode 100644 index 0000000000000000000000000000000000000000..42a96a3e78212070f9ba64986755420c0d6aaf9e --- /dev/null +++ b/reachy_mini/src/reachy_mini/io/zenoh_server.py @@ -0,0 +1,188 @@ +"""Zenoh server for Reachy Mini. + +This module implements a Zenoh server that allows communication with the Reachy Mini +robot. It handles commands for joint positions and torque settings, and publishes joint positions updates. + +It uses the Zenoh protocol for efficient data exchange and can be configured to run +either on localhost only or to accept connections from other hosts. +""" + +import asyncio +import json +import threading +from datetime import datetime + +import numpy as np +import zenoh + +from reachy_mini.daemon.backend.abstract import Backend, MotorControlMode +from reachy_mini.io.abstract import AbstractServer +from reachy_mini.io.protocol import ( + GotoTaskRequest, + PlayMoveTaskRequest, + TaskProgress, + TaskRequest, +) + + +class ZenohServer(AbstractServer): + """Zenoh server for Reachy Mini.""" + + def __init__(self, backend: Backend, localhost_only: bool = True): + """Initialize the Zenoh server.""" + self.localhost_only = localhost_only + self.backend = backend + + self._lock = threading.Lock() + self._cmd_event = threading.Event() + + def start(self) -> None: + """Start the Zenoh server.""" + if self.localhost_only: + c = zenoh.Config.from_json5( + json.dumps( + { + "listen": { + "endpoints": ["tcp/localhost:7447"], + }, + "scouting": { + "multicast": { + "enabled": False, + }, + "gossip": { + "enabled": False, + }, + }, + "connect": { + "endpoints": [ + "tcp/localhost:7447", + ], + }, + } + ) + ) + else: + c = zenoh.Config() + + self.session = zenoh.open(c) + self.sub = self.session.declare_subscriber( + "reachy_mini/command", + self._handle_command, + ) + self.pub = self.session.declare_publisher("reachy_mini/joint_positions") + self.pub_record = self.session.declare_publisher("reachy_mini/recorded_data") + self.backend.set_joint_positions_publisher(self.pub) + self.backend.set_recording_publisher(self.pub_record) + + self.pub_pose = self.session.declare_publisher("reachy_mini/head_pose") + self.backend.set_pose_publisher(self.pub_pose) + + self.task_req_sub = self.session.declare_subscriber( + "reachy_mini/task", + self._handle_task_request, + ) + self.task_progress_pub = self.session.declare_publisher( + "reachy_mini/task_progress" + ) + + self.pub_status = self.session.declare_publisher("reachy_mini/daemon_status") + + def stop(self) -> None: + """Stop the Zenoh server.""" + self.session.close() # type: ignore[no-untyped-call] + + def command_received_event(self) -> threading.Event: + """Wait for a new command and return it.""" + return self._cmd_event + + def _handle_command(self, sample: zenoh.Sample) -> None: + data = sample.payload.to_string() + command = json.loads(data) + with self._lock: + if "torque" in command: + if ( + command["ids"] is not None + ): # If specific motor IDs are provided, just set torque for those motors + self.backend.set_motor_torque_ids(command["ids"], command["torque"]) + else: + if command["torque"]: + self.backend.set_motor_control_mode(MotorControlMode.Enabled) + else: + self.backend.set_motor_control_mode(MotorControlMode.Disabled) + if "head_joint_positions" in command: + self.backend.set_target_head_joint_positions( + np.array(command["head_joint_positions"]) + ) + if "head_pose" in command: + self.backend.set_target_head_pose( + np.array(command["head_pose"]).reshape(4, 4) + ) + if "body_yaw" in command: + self.backend.set_target_body_yaw(command["body_yaw"]) + if "antennas_joint_positions" in command: + self.backend.set_target_antenna_joint_positions( + np.array(command["antennas_joint_positions"]), + ) + if "gravity_compensation" in command: + try: + if command["gravity_compensation"]: + self.backend.set_motor_control_mode( + MotorControlMode.GravityCompensation + ) + else: + self.backend.set_motor_control_mode(MotorControlMode.Enabled) + + except ValueError as e: + print(e) + if "automatic_body_yaw" in command: + self.backend.set_automatic_body_yaw(command["automatic_body_yaw"]) + + if "set_target_record" in command: + self.backend.append_record(command["set_target_record"]) + + if "start_recording" in command: + self.backend.start_recording() + if "stop_recording" in command: + self.backend.stop_recording() + self._cmd_event.set() + + def _handle_task_request(self, sample: zenoh.Sample) -> None: + task_req = TaskRequest.model_validate_json(sample.payload.to_string()) + + if isinstance(task_req.req, GotoTaskRequest): + req = task_req.req + + def task() -> None: + asyncio.run( + self.backend.goto_target( + head=np.array(req.head).reshape(4, 4) if req.head else None, + antennas=np.array(req.antennas) if req.antennas else None, + duration=req.duration, + method=req.method, + body_yaw=req.body_yaw, + ) + ) + elif isinstance(task_req.req, PlayMoveTaskRequest): + + def task() -> None: + print("PLAY MOVE") + + else: + assert False, f"Unknown task request type {task_req.req.__class__.__name__}" + + def wrapped_task() -> None: + error = None + try: + task() + except Exception as e: + error = str(e) + + progress = TaskProgress( + uuid=task_req.uuid, + finished=True, + error=error, + timestamp=datetime.now(), + ) + self.task_progress_pub.put(progress.model_dump_json()) + + threading.Thread(target=wrapped_task).start() diff --git a/reachy_mini/src/reachy_mini/kinematics/__init__.py b/reachy_mini/src/reachy_mini/kinematics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..176bfa7fcc543e97908ec851f7abcbfdffcccd3d --- /dev/null +++ b/reachy_mini/src/reachy_mini/kinematics/__init__.py @@ -0,0 +1,68 @@ +"""Try to import kinematics engines, and provide mockup classes if they are not available.""" + +from typing import Annotated + +import numpy as np +import numpy.typing as npt + +try: + from reachy_mini.kinematics.nn_kinematics import NNKinematics # noqa: F401 +except ImportError: + + class MockupNNKinematics: + """Mockup class for NNKinematics.""" + + def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def] + """Raise ImportError when trying to instantiate the class.""" + raise ImportError( + "NNKinematics could not be imported. Make sure you run pip install reachy_mini[nn_kinematics]." + ) + + def ik(self, *args, **kwargs) -> Annotated[npt.NDArray[np.float64], (7,)]: # type: ignore[no-untyped-def] + """Mockup method for ik.""" + raise ImportError( + "NNKinematics could not be imported. Make sure you run pip install reachy_mini[nn_kinematics]." + ) + + def fk(self, *args, **kwargs) -> Annotated[npt.NDArray[np.float64], (4, 4)]: # type: ignore[no-untyped-def] + """Mockup method for fk.""" + raise ImportError( + "NNKinematics could not be imported. Make sure you run pip install reachy_mini[nn_kinematics]." + ) + + NNKinematics = MockupNNKinematics # type: ignore[assignment, misc] + +try: + from reachy_mini.kinematics.placo_kinematics import PlacoKinematics # noqa: F401 +except ImportError: + + class MockupPlacoKinematics: + """Mockup class for PlacoKinematics.""" + + def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def] + """Raise ImportError when trying to instantiate the class.""" + raise ImportError( + "PlacoKinematics could not be imported. Make sure you run pip install reachy_mini[placo_kinematics]." + ) + + def ik(self, *args, **kwargs) -> Annotated[npt.NDArray[np.float64], (7,)]: # type: ignore[no-untyped-def] + """Mockup method for ik.""" + raise ImportError( + "PlacoKinematics could not be imported. Make sure you run pip install reachy_mini[placo_kinematics]." + ) + + def fk(self, *args, **kwargs) -> Annotated[npt.NDArray[np.float64], (4, 4)]: # type: ignore[no-untyped-def] + """Mockup method for fk.""" + raise ImportError( + "PlacoKinematics could not be imported. Make sure you run pip install reachy_mini[placo_kinematics]." + ) + + PlacoKinematics = MockupPlacoKinematics # type: ignore[assignment, misc] + + +from reachy_mini.kinematics.analytical_kinematics import ( # noqa: F401 + AnalyticalKinematics, +) + +AnyKinematics = NNKinematics | PlacoKinematics | AnalyticalKinematics +__all__ = ["NNKinematics", "PlacoKinematics", "AnalyticalKinematics"] diff --git a/reachy_mini/src/reachy_mini/kinematics/analytical_kinematics.py b/reachy_mini/src/reachy_mini/kinematics/analytical_kinematics.py new file mode 100644 index 0000000000000000000000000000000000000000..ca7674e8005f0061cc18a3d99c3e05b8b14e7502 --- /dev/null +++ b/reachy_mini/src/reachy_mini/kinematics/analytical_kinematics.py @@ -0,0 +1,152 @@ +"""An analytical kinematics engine for Reachy Mini, using Rust bindings. + +The inverse kinematics use an analytical method, while the forward kinematics +use a numerical method (Newton). +""" + +import json +import logging +from importlib.resources import files +from typing import Annotated + +import numpy as np +from numpy.typing import NDArray +from reachy_mini_rust_kinematics import ReachyMiniRustKinematics +from scipy.spatial.transform import Rotation as R + +import reachy_mini + +# Duplicated for now. +SLEEP_HEAD_POSE = np.array( + [ + [0.911, 0.004, 0.413, -0.021], + [-0.004, 1.0, -0.001, 0.001], + [-0.413, -0.001, 0.911, -0.044], + [0.0, 0.0, 0.0, 1.0], + ] +) + + +class AnalyticalKinematics: + """Reachy Mini Analytical Kinematics class, implemented in Rust with python bindings.""" + + def __init__( + self, + automatic_body_yaw: bool = True + ) -> None: + """Initialize.""" + assets_root_path: str = str(files(reachy_mini).joinpath("assets/")) + data_path = assets_root_path + "/kinematics_data.json" + data = json.load(open(data_path, "rb")) + + self.automatic_body_yaw = automatic_body_yaw + + self.head_z_offset = data["head_z_offset"] + + self.kin = ReachyMiniRustKinematics( + data["motor_arm_length"], data["rod_length"] + ) + + self.start_body_yaw = 0.0 + + self.motors = data["motors"] + for motor in self.motors: + self.kin.add_branch( + motor["branch_position"], + np.linalg.inv(motor["T_motor_world"]), # type: ignore[arg-type] + 1 if motor["solution"] else -1, + ) + + # TODO test with init head pose instead of sleep pose + sleep_head_pose = SLEEP_HEAD_POSE.copy() + sleep_head_pose[:3, 3][2] += self.head_z_offset + self.kin.reset_forward_kinematics(sleep_head_pose) # type: ignore[arg-type] + + self.logger = logging.getLogger(__name__) + # self.logger.setLevel(logging.WARNING) + + def ik( + self, + pose: Annotated[NDArray[np.float64], (4, 4)], + body_yaw: float = 0.0, + check_collision: bool = False, + no_iterations: int = 0, + ) -> Annotated[NDArray[np.float64], (7,)]: + """Compute the inverse kinematics for a given head pose. + + check_collision and no_iterations are not used by AnalyticalKinematics. We keep them for compatibility with the other kinematics engines + """ + _pose = pose.copy() + _pose[:3, 3][2] += self.head_z_offset + + reachy_joints = [] + if self.automatic_body_yaw: + # inverse kinematics solution that modulates the body yaw to + # stay within the mechanical limits (max_body_yaw) + # additionally it makes sure the the relative yaw between the body and the head + # stays within the mechanical limits (max_relative_yaw) + reachy_joints = self.kin.inverse_kinematics_safe(_pose, # type: ignore[arg-type] + body_yaw = body_yaw, + max_relative_yaw = np.deg2rad(65), + max_body_yaw = np.deg2rad(160)) + else: + # direct inverse kinematics solution with given body yaw + # it does not modify the body yaw + stewart_joints = self.kin.inverse_kinematics(_pose, body_yaw) # type: ignore[arg-type] + reachy_joints = [body_yaw] + stewart_joints + + return np.array(reachy_joints) + + def fk( + self, + joint_angles: Annotated[NDArray[np.float64], (7,)], + check_collision: bool = False, + no_iterations: int = 3, + ) -> Annotated[NDArray[np.float64], (4, 4)]: + """Compute the forward kinematics for a given set of joint angles. + + check_collision is not used by AnalyticalKinematics. + """ + body_yaw = joint_angles[0] + + _joint_angles = joint_angles[1:].tolist() + + if no_iterations < 1: + raise ValueError("no_iterations must be at least 1") + + T_world_platform = None + ok = False + while not ok: + for _ in range(no_iterations): + T_world_platform = np.array( + self.kin.forward_kinematics(_joint_angles, body_yaw) + ) + assert T_world_platform is not None + euler = R.from_matrix(T_world_platform[:3, :3]).as_euler( + "xyz", degrees=True + ) + # check that head is upright. Recompute with epsilon adjustments if not + if not (euler[0] > 90 or euler[0] < -90 or euler[1] > 90 or euler[1] < -90): + ok = True + else: + self.logger.warning("Head is not upright, recomputing FK") + body_yaw += 0.001 + _joint_angles = list(np.array(_joint_angles) + 0.001) + tmp = np.eye(4) + tmp[:3, 3][2] += self.head_z_offset + self.kin.reset_forward_kinematics(tmp) # type: ignore[arg-type] + + assert T_world_platform is not None + + T_world_platform[:3, 3][2] -= self.head_z_offset + + return T_world_platform + + def set_automatic_body_yaw(self, automatic_body_yaw: bool) -> None: + """Set the automatic body yaw. + + Args: + automatic_body_yaw (bool): Whether to enable automatic body yaw. + + """ + self.automatic_body_yaw = automatic_body_yaw \ No newline at end of file diff --git a/reachy_mini/src/reachy_mini/kinematics/nn_kinematics.py b/reachy_mini/src/reachy_mini/kinematics/nn_kinematics.py new file mode 100644 index 0000000000000000000000000000000000000000..3bab191285cdb016d4cd0a17540e9390a6266166 --- /dev/null +++ b/reachy_mini/src/reachy_mini/kinematics/nn_kinematics.py @@ -0,0 +1,111 @@ +"""Neural Network based FK/IK.""" + +import time +from typing import Annotated + +import numpy as np +import numpy.typing as npt +import onnxruntime +from scipy.spatial.transform import Rotation as R + + +class NNKinematics: + """Neural Network based FK/IK. Fitted from PlacoKinematics data.""" + + def __init__(self, models_root_path: str): + """Intialize.""" + self.fk_model_path = f"{models_root_path}/fknetwork.onnx" + self.ik_model_path = f"{models_root_path}/iknetwork.onnx" + self.fk_infer = OnnxInfer(self.fk_model_path) + self.ik_infer = OnnxInfer(self.ik_model_path) + + self.automatic_body_yaw = False # No used, kept for canaompatibility + + def ik( + self, + pose: Annotated[npt.NDArray[np.float64], (4, 4)], + body_yaw: float = 0.0, + check_collision: bool = False, + no_iterations: int = 0, + ) -> Annotated[npt.NDArray[np.float64], (7,)]: + """check_collision and no_iterations are not used by NNKinematics. + + We keep them for compatibility with the other kinematics engines + """ + x, y, z = pose[:3, 3][0], pose[:3, 3][1], pose[:3, 3][2] + roll, pitch, yaw = R.from_matrix(pose[:3, :3]).as_euler("xyz") + + yaw += body_yaw + input = np.array([x, y, z, roll, pitch, yaw]) + + joints = self.ik_infer.infer(input) + joints[0] += body_yaw + + return joints + + def fk( + self, + joint_angles: Annotated[npt.NDArray[np.float64], (7,)], + check_collision: bool = False, + no_iterations: int = 0, + ) -> Annotated[npt.NDArray[np.float64], (4, 4)]: + """check_collision and no_iterations are not used by NNKinematics. + + We keep them for compatibility with the other kinematics engines + """ + x, y, z, roll, pitch, yaw = self.fk_infer.infer(joint_angles) + pose = np.eye(4) + pose[:3, 3] = [x, y, z] + pose[:3, :3] = R.from_euler("xyz", [roll, pitch, yaw]).as_matrix() + return pose + + + def set_automatic_body_yaw(self, automatic_body_yaw: bool) -> None: + """Set the automatic body yaw. + + Args: + automatic_body_yaw (bool): Whether to enable automatic body yaw. + + """ + self.automatic_body_yaw = automatic_body_yaw + +class OnnxInfer: + """Infer an onnx model.""" + + def __init__(self, onnx_model_path: str) -> None: + """Initialize.""" + self.onnx_model_path = onnx_model_path + self.ort_session = onnxruntime.InferenceSession( + self.onnx_model_path, providers=["CPUExecutionProvider"] + ) + + def infer(self, input: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]: + """Run inference on the input.""" + outputs = self.ort_session.run(None, {"input": [input]}) + res: npt.NDArray[np.float64] = outputs[0][0] + return res + + + + +if __name__ == "__main__": + nn_kin = NNKinematics( + "assets/models", + ) + + times_fk: list[float] = [] + times_ik: list[float] = [] + for i in range(1000): + fk_input = np.random.random(7).astype(np.float64) + # ik_input = np.random.random(6).astype(np.float64) + + fk_s = time.time() + fk_output = nn_kin.fk(fk_input) + times_fk.append(time.time() - fk_s) + + # ik_s = time.time() + # ik_output = nn_kin.ik(ik_input) + # times_ik.append(time.time() - ik_s) + + print(f"Average FK inference time: {np.mean(times_fk) * 1e6} µs") + # print(f"Average IK inference time: {np.mean(times_ik) * 1e6} µs") diff --git a/reachy_mini/src/reachy_mini/kinematics/placo_kinematics.py b/reachy_mini/src/reachy_mini/kinematics/placo_kinematics.py new file mode 100644 index 0000000000000000000000000000000000000000..e842fbd4f2b3b6db76bfd58e42a1ca0faf39bcf6 --- /dev/null +++ b/reachy_mini/src/reachy_mini/kinematics/placo_kinematics.py @@ -0,0 +1,656 @@ +"""Placo Kinematics for Reachy Mini. + +This module provides the PlacoKinematics class for performing inverse and forward kinematics based on the Reachy Mini robot URDF using the Placo library. +""" + +import logging +from typing import Annotated, List, Optional + +import numpy as np +import numpy.typing as npt +import pinocchio as pin +import placo +from scipy.spatial.transform import Rotation as R + + +class PlacoKinematics: + """Placo Kinematics class for Reachy Mini. + + This class provides methods for inverse and forward kinematics using the Placo library and a URDF model of the Reachy Mini robot. + """ + + def __init__( + self, + urdf_path: str, + dt: float = 0.02, + automatic_body_yaw: bool = False, + check_collision: bool = False, + log_level: str = "INFO", + ) -> None: + """Initialize the PlacoKinematics class. + + Args: + urdf_path (str): Path to the URDF file of the Reachy Mini robot. + dt (float): Time step for the kinematics solver. Default is 0.02 seconds. + automatic_body_yaw (bool): If True, the body yaw will be used to compute the IK and FK. Default is False. + check_collision (bool): If True, checks for collisions after solving IK. (default: False) + log_level (str): Logging level for the kinematics computations. + + """ + self.fk_reached_tol = np.deg2rad( + 0.1 + ) # 0.1 degrees tolerance for the FK reached condition + + if not urdf_path.endswith(".urdf"): + urdf_path = f"{urdf_path}/{'robot_simple_collision.urdf' if check_collision else 'robot_no_collision.urdf'}" + + self.robot = placo.RobotWrapper( + urdf_path, placo.Flags.collision_as_visual + placo.Flags.ignore_collisions + ) + + flags = ( + 0 + if check_collision + else placo.Flags.ignore_collisions + placo.Flags.collision_as_visual + ) + self.robot_ik = placo.RobotWrapper(urdf_path, flags) + + self.ik_solver = placo.KinematicsSolver(self.robot_ik) + self.ik_solver.mask_fbase(True) + + self.fk_solver = placo.KinematicsSolver(self.robot) + self.fk_solver.mask_fbase(True) + + self.automatic_body_yaw = automatic_body_yaw + self.check_collision = check_collision + + self._logger = logging.getLogger(__name__) + self._logger.setLevel(log_level) + + # we could go to soft limits to avoid over-constraining the IK + # but the current implementation works robustly with hard limits + # so we keep the hard limits for now + constrant_type = "hard" # "hard" or "soft" + + # IK closing tasks + ik_closing_tasks = [] + for i in range(1, 6): + ik_closing_task = self.ik_solver.add_relative_position_task( + f"closing_{i}_1", f"closing_{i}_2", np.zeros(3) + ) + ik_closing_task.configure(f"closing_{i}", constrant_type, 1.0) + ik_closing_tasks.append(ik_closing_task) + + # FK closing tasks + fk_closing_tasks = [] + for i in range(1, 6): + fk_closing_task = self.fk_solver.add_relative_position_task( + f"closing_{i}_1", f"closing_{i}_2", np.zeros(3) + ) + fk_closing_task.configure(f"closing_{i}", constrant_type, 1.0) + fk_closing_tasks.append(fk_closing_task) + + # Add the constraint between the rotated torso and the head + # This will allow independent control of the torso and the head yaw + # until this constraint is reached + yaw_constraint = self.ik_solver.add_yaw_constraint( + "dummy_torso_yaw", "head", np.deg2rad(55.0) + ) + yaw_constraint.configure("rel_yaw", "hard") + + # Add the constraint to avoid the head from looking too far behind + # Mostly due to some numerical problems 180 is always a bit tricky + # Not really constraining because the this 180 pose is almost not + # reachable with the real robot anyway + yaw_constraint_abs = self.ik_solver.add_yaw_constraint( + "body_foot_3dprint", "head", np.deg2rad(179.0) + ) + yaw_constraint_abs.configure("abs_yaw", "hard") + + # Add a cone constraint for the head to not exceed a certain angle + # This is to avoid the head from looking too far up or down + self.fk_cone = self.ik_solver.add_cone_constraint( + "body_foot_3dprint", "head", np.deg2rad(35.0) + ) + self.fk_cone.configure("cone", "hard") + self.fk_yaw_constraint = self.fk_solver.add_yaw_constraint( + "dummy_torso_yaw", "head", np.deg2rad(55.0) + ) + self.fk_yaw_constraint.configure("rel_yaw", "hard") + + # Add a cone constraint for the head to not exceed a certain angle + # This is to avoid the head from looking too far up or down + fk_cone = self.fk_solver.add_cone_constraint( + "body_foot_3dprint", "head", np.deg2rad(35.0) + ) + fk_cone.configure("cone", "hard") + + # Z offset for the head to make it easier to compute the IK and FK + # This is the height of the head from the base of the robot + self.head_z_offset = 0.177 # offset for the head height + + # IK head task + self.head_starting_pose = np.eye(4) + self.head_starting_pose[:3, 3][2] = self.head_z_offset + self.head_frame = self.ik_solver.add_frame_task("head", self.head_starting_pose) + # equivalance to ~1cm = 1deg weights + # set to 5 to be higher than the 1.0 for the body yaw + self.head_frame.configure( + "head", + "soft", + 5.0, # in meters # 1m + 5.0, # in radians # 1rad + ) + + self.head_frame.T_world_frame = self.head_starting_pose + + # regularization + self.ik_yaw_joint_task = self.ik_solver.add_joints_task() + self.ik_yaw_joint_task.set_joints({"yaw_body": 0}) + if not self.automatic_body_yaw: + self.ik_yaw_joint_task.configure("joints", "soft", 5e-5) + else: + self.ik_yaw_joint_task.configure("joints", "soft", 3.0) + + # joint limit tasks (values form URDF) + self.ik_solver.enable_velocity_limits(True) + self.ik_solver.enable_joint_limits(True) + self.ik_solver.dt = dt + + # FK joint task + self.head_joints_task = self.fk_solver.add_joints_task() + self.head_joints_task.configure("joints", "soft", 5.0) + # joint limit tasks (values form URDF) + self.fk_solver.enable_velocity_limits(True) + self.fk_solver.enable_joint_limits(True) + self.fk_solver.dt = dt + + # Actuated DoFs + self.joints_names = [ + "yaw_body", + "stewart_1", + "stewart_2", + "stewart_3", + "stewart_4", + "stewart_5", + "stewart_6", + ] + + # Passive DoFs to eliminate with constraint jacobian + self.passive_joints_names = [ + "passive_1_x", + "passive_1_y", + "passive_2_x", + "passive_2_y", + "passive_3_x", + "passive_3_y", + "passive_4_x", + "passive_4_y", + "passive_5_x", + "passive_5_y", + "passive_6_x", + "passive_6_y", + "passive_7_x", + "passive_7_y", + "passive_7_z", + ] + + # Retrieving indexes in the jacobian + self.passives_idx = [ + self.robot.get_joint_v_offset(dof) for dof in self.passive_joints_names + ] + self.actives_idx = [ + self.robot.get_joint_v_offset(dof) + for dof in self.robot.joint_names() + if dof not in self.passive_joints_names + ] + self.actuated_idx = [ + self.robot.get_joint_v_offset(dof) + for dof in self.robot.joint_names() + if dof in self.joints_names + ] + + # actuated dof indexes in active dofs + self.actuated_idx_in_active = [ + i for i, idx in enumerate(self.actives_idx) if idx in self.actuated_idx + ] + + # set velocity limits to be artificially high + # to enable faster convergence of the IK/FK solver + max_vel = 13.0 # rad/s + for joint_name in self.joints_names: + if joint_name != "yaw_body": + self.robot.set_velocity_limit(joint_name, max_vel) + self.robot_ik.set_velocity_limit(joint_name, max_vel) + + self.robot.set_joint_limits("yaw_body", -2.8, 2.8) + self.robot_ik.set_joint_limits("yaw_body", -2.8, 2.8) + + # initial state + self._inital_q = self.robot.state.q.copy() + self._inital_qd = np.zeros_like(self.robot.state.qd) + self._inital_qdd = np.zeros_like(self.robot.state.qdd) + + # initial FK to set the head pose + for _ in range(10): + self.ik_solver.solve(True) # False to not update the kinematics + self.robot_ik.update_kinematics() + + # last good q to revert to in case of collision + self._inital_q = self.robot_ik.state.q.copy() + self._last_good_q = self.robot_ik.state.q.copy() + + # update the robot state to the initial state + self._update_state_to_initial(self.robot) # revert to the inital state + self.robot.update_kinematics() + + if self.check_collision: + ik_col = self.ik_solver.add_avoid_self_collisions_constraint() + ik_col.self_collisions_margin = 0.001 # 1mm + ik_col.self_collisions_trigger = 0.002 # 2mm + ik_col.configure("avoid_self_collisions", "hard") + + # setup the collision model + self.config_collision_model() + + def _update_state_to_initial(self, robot: placo.RobotWrapper) -> None: + """Update the robot state to the initial state. + + It does not call update_kinematics, so the robot state is not updated. + + Args: + robot (placo.RobotWrapper): The robot wrapper instance to update. + + """ + robot.state.q = self._inital_q + robot.state.qd = self._inital_qd + robot.state.qdd = self._inital_qdd + + def _pose_distance( + self, pose1: npt.NDArray[np.float64], pose2: npt.NDArray[np.float64] + ) -> tuple[float, float]: + """Compute the orientation distance between two poses. + + Args: + pose1 (np.ndarray): The first pose (4x4 homogeneous transformation matrix). + pose2 (np.ndarray): The second pose (4x4 homogeneous transformation matrix). + + Returns: + float: The Euler distance between the two poses. + + """ + euler1 = R.from_matrix(pose1[:3, :3]).as_euler("xyz") + euler2 = R.from_matrix(pose2[:3, :3]).as_euler("xyz") + p1 = pose1[:3, 3] + p2 = pose2[:3, 3] + return float(np.linalg.norm(euler1 - euler2)), float(np.linalg.norm(p1 - p2)) + + def _closed_loop_constraints_valid( + self, robot: placo.RobotWrapper, tol: float = 1e-2 + ) -> bool: + """Check if all closed-loop constraints are satisfied. + + Args: + robot (placo.RobotWrapper): The robot wrapper instance to check. + tol (float): The tolerance for checking constraints (default: 1e-2). + + Returns: + bool: True if all constraints are satisfied, False otherwise. + + """ + for i in range(1, 6): + pos1 = robot.get_T_world_frame(f"closing_{i}_1")[:3, 3] + pos2 = robot.get_T_world_frame(f"closing_{i}_2")[:3, 3] + if not np.allclose(pos1, pos2, atol=tol): + return False + return True + + def _get_joint_values(self, robot: placo.RobotWrapper) -> List[float]: + """Get the joint values from the robot state. + + Args: + robot (placo.RobotWrapper): The robot wrapper instance to get joint values from. + + Returns: + List[float]: A list of joint values. + + """ + joints = [] + for joint_name in self.joints_names: + joint = robot.get_joint(joint_name) + joints.append(joint) + return joints + + def ik( + self, + pose: npt.NDArray[np.float64], + body_yaw: float = 0.0, + no_iterations: int = 2, + ) -> Annotated[npt.NDArray[np.float64], (7,)] | None: + """Compute the inverse kinematics for the head for a given pose. + + Args: + pose (np.ndarray): A 4x4 homogeneous transformation matrix + representing the desired position and orientation of the head. + body_yaw (float): Body yaw angle in radians. + no_iterations (int): Number of iterations to perform (default: 2). The higher the value, the more accurate the solution. + + Returns: + List[float]: A list of joint angles for the head. + + """ + _pose = pose.copy() + # set the head pose + _pose[:3, 3][2] += self.head_z_offset # offset the height of the head + self.head_frame.T_world_frame = _pose + # update the body_yaw task + self.ik_yaw_joint_task.set_joints({"yaw_body": body_yaw}) + + # check the starting configuration + # if the poses are too far start from the initial configuration + _dist_o, _dist_p = self._pose_distance( + _pose, self.robot_ik.get_T_world_frame("head") + ) + # if distance too small 0.1mm and 0.1 deg and the QP has converged (almost 0 velocity) + _dist_by = np.abs(body_yaw - self.robot_ik.get_joint("yaw_body")) + if ( + _dist_p < 0.1e-4 + and _dist_o < np.deg2rad(0.01) + and _dist_by < np.deg2rad(0.01) + and np.linalg.norm(self.robot_ik.state.qd) < 1e-4 + ): + # no need to recalculate - return the current joint values + return np.array( + self._get_joint_values(self.robot_ik) + ) # no need to solve IK + if _dist_o >= np.pi: + # distance too big between the current and the target pose + # start the optim from zero position + # + # TO INVESTIGATE: Another way to do this would be not to start from 0 but + # to set the target pose not to the actual target but to some intermediate pose + self._update_state_to_initial(self.robot_ik) + self.robot_ik.update_kinematics() + self._logger.debug("IK: Poses too far, starting from initial configuration") + + done = True + # do the inital ik + for i in range(no_iterations): + try: + self.ik_solver.solve(True) # False to not update the kinematics + except Exception as e: + self._logger.debug(f"IK solver failed: {e}, retrying...") + done = False + break + self.robot_ik.update_kinematics() + + # if no problem in solving the IK check for constraint violation + if done and (not self._closed_loop_constraints_valid(self.robot_ik)): + self._logger.debug( + "IK: Not all equality constraints are satisfied in IK, retrying..." + ) + done = False + + # if there was an issue start from scratch + if not done: + # set the initial pose + self._update_state_to_initial(self.robot_ik) + self.robot_ik.update_kinematics() + + no_iterations += 2 # add a few more iterations + # do the inital ik with 10 iterations + for i in range(no_iterations): + try: + self.ik_solver.solve(True) # False to not update the kinematics + except Exception as e: + self._logger.warning(f"IK solver failed: {e}, no solution found!") + return None + self.robot_ik.update_kinematics() + + # Get the joint angles + return np.array(self._get_joint_values(self.robot_ik)) + + def fk( + self, + joints_angles: Annotated[npt.NDArray[np.float64], (7,)], + no_iterations: int = 2, + ) -> Optional[npt.NDArray[np.float64]]: + """Compute the forward kinematics for the head given joint angles. + + Args: + joints_angles (List[float]): A list of joint angles for the head. + no_iterations (int): The number of iterations to use for the FK solver. (default: 2), the higher the more accurate the result. + + Returns: + np.ndarray: A 4x4 homogeneous transformation matrix + + """ + # check if we're already there + _current_joints = self._get_joint_values(self.robot) + # if the joint angles are the same (tol 1e-4) and teh QP has converged (max speed is 1e-4rad/s) + # no need to compute the FK + if ( + np.linalg.norm(np.array(_current_joints) - np.array(joints_angles)) + < self.fk_reached_tol + and self.robot.state.qd.max() < 1e-4 + ): + # no need to compute FK + T_world_head: npt.NDArray[np.float64] = self.robot.get_T_world_frame("head") + T_world_head[:3, 3][2] -= ( + self.head_z_offset + ) # offset the height of the head + return T_world_head + + # update the main task + self.head_joints_task.set_joints( + { + "yaw_body": joints_angles[0], + "stewart_1": joints_angles[1], + "stewart_2": joints_angles[2], + "stewart_3": joints_angles[3], + "stewart_4": joints_angles[4], + "stewart_5": joints_angles[5], + "stewart_6": joints_angles[6], + } + ) + + done = True + # do the inital ik with 2 iterations + for i in range(no_iterations): + try: + self.fk_solver.solve(True) # False to not update the kinematics + except Exception as e: + self._logger.debug(f"FK solver failed: {e}, retrying...") + done = False + break + self.robot.update_kinematics() + + if done and (not self._closed_loop_constraints_valid(self.robot)): + self._logger.debug( + "FK: Not all equality constraints are satisfied in FK, retrying..." + ) + done = False + + if not done: + self._update_state_to_initial(self.robot) # revert to the previous state + self.robot.update_kinematics() + + no_iterations += 2 # add a few more iterations + # do the inital ik with 10 iterations + for i in range(no_iterations): + try: + self.fk_solver.solve(True) # False to not update the kinematics + except Exception as e: + self._logger.warning(f"FK solver failed: {e}, no solution found!") + return None + self.robot.update_kinematics() + + # Get the head frame transformation + T_world_head = self.robot.get_T_world_frame("head") + T_world_head[:3, 3][2] -= self.head_z_offset # offset the height of the head + + return T_world_head + + def config_collision_model(self) -> None: + """Configure the collision model for the robot. + + Add collision pairs between the torso and the head colliders. + """ + geom_model = self.robot_ik.collision_model + + id_torso_colliders = list(range(len(geom_model.geometryObjects) - 1)) + id_head_collider = len(geom_model.geometryObjects) - 1 + + for i in id_torso_colliders: + geom_model.addCollisionPair( + pin.CollisionPair(id_head_collider, i) + ) # torso with head colliders + + def compute_collision(self, margin: float = 0.005) -> bool: + """Compute the collision between the robot and the environment. + + Args: + margin (float): The margin to consider for collision detection (default: 5mm). + + Returns: + True if there is a collision, False otherwise. + + """ + collision_data = self.robot_ik.collision_model.createData() + data = self.robot_ik.model.createData() + + # pin.computeCollisions( + pin.computeDistances( + self.robot_ik.model, + data, + self.robot_ik.collision_model, + collision_data, + self.robot_ik.state.q, + ) + + # Iterate over all collision pairs + for distance_result in collision_data.distanceResults: + if distance_result.min_distance <= margin: + return True # Something is too close or colliding! + + return False # Safe + + def compute_jacobian( + self, q: Optional[npt.NDArray[np.float64]] = None + ) -> npt.NDArray[np.float64]: + """Compute the Jacobian of the head frame with respect to the actuated DoFs. + + The jacobian in local world aligned. + + Args: + q (np.ndarray, optional): Joint angles of the robot. If None, uses the current state of the robot. (default: None) + + Returns: + np.ndarray: The Jacobian matrix. + + """ + # If q is provided, use it to compute the forward kinematics + if q is not None: + self.fk(q, no_iterations=20) + + # Computing the platform Jacobian + # dx = Jp.dq + Jp: npt.NDArray[np.float64] = self.robot.frame_jacobian( + "head", "local_world_aligned" + ) + + # Computing the constraints Jacobian + # 0 = Jc.dq + constraints = [] + for i in range(1, 6): + Jc = self.robot.relative_position_jacobian( + f"closing_{i}_1", f"closing_{i}_2" + ) + constraints.append(Jc) + Jc = np.vstack(constraints) + + # Splitting jacobians as + # Jp_a.dq_a + Jp_p.dq_p = dx + Jp_a = Jp[:, self.actives_idx] + Jp_p = Jp[:, self.passives_idx] + # Jc_a.dq_a + Jc_p.dq_p = 0 + Jc_a = Jc[:, self.actives_idx] + Jc_p = Jc[:, self.passives_idx] + + # Computing effector jacobian under constraints + # Because constraint equation + # Jc_a.dq_a + Jc_p.dq_p = 0 + # can be written as: + # dq_p = - (Jc_p)^(⁻1) @ Jc_a @ dq_a + # Then we can substitute dq_p in the first equation and get + # This new jacobian + J: npt.NDArray[np.float64] = Jp_a - Jp_p @ np.linalg.inv(Jc_p) @ Jc_a + + return J[:, self.actuated_idx_in_active] + + def compute_gravity_torque( + self, q: Optional[npt.NDArray[np.float64]] = None + ) -> npt.NDArray[np.float64]: + """Compute the gravity torque vector for the actuated joints of the robot. + + This method uses the static gravity compensation torques from the robot's dictionary. + + Args: + q (np.ndarray, optional): Joint angles of the robot. If None, uses the current state of the robot. (default: None) + + Returns: + np.ndarray: The gravity torque vector. + + """ + # If q is provided, use it to compute the forward kinematics + if q is not None: + self.fk(q) + + # Get the static gravity compensation torques for all joints + # except the mobile base 6dofs + grav_torque_all_joints = np.array( + list( + self.robot.static_gravity_compensation_torques_dict( + "body_foot_3dprint" + ).values() + ) + ) + + # See the paper for more info (equations 4-9): + # https://hal.science/hal-03379538/file/BriotKhalil_SpringerEncyclRob_bookchapterPKMDyn.pdf#page=4 + # + # Basically to compute the actuated torques necessary to compensate the gravity, we need to compute the + # the equivalent wrench in the head frame that would be created if all the joints were actuated. + # wrench_eq = np.linalg.pinv(J_all_joints.T) @ torque_all_joints + # And then we can compute the actuated torques as: + # torque_actuated = J_actuated.T @ wrench_eq + J_all_joints: npt.NDArray[np.float64] = self.robot.frame_jacobian( + "head", "local_world_aligned" + )[:, 6:] # all joints except the mobile base 6dofs + J_actuated = self.compute_jacobian() + # using a single matrix G to compute the actuated torques + G = J_actuated.T @ np.linalg.pinv(J_all_joints.T) + + # torques of actuated joints + grav_torque_actuated: npt.NDArray[np.float64] = G @ grav_torque_all_joints + + # Compute the gravity torque + return grav_torque_actuated + + def set_automatic_body_yaw(self, automatic_body_yaw: bool) -> None: + """Set the automatic body yaw. + + Args: + automatic_body_yaw (bool): Whether to enable automatic body yaw. + + """ + self.automatic_body_yaw = automatic_body_yaw + + if not self.automatic_body_yaw: + self.ik_yaw_joint_task.configure("joints", "soft", 3.0) + else: + self.ik_yaw_joint_task.configure("joints", "soft", 5e-5) + + def get_joint(self, joint_name: str) -> float: + """Get the joint object by its name.""" + return float(self.robot.get_joint(joint_name)) diff --git a/reachy_mini/src/reachy_mini/media/__init__.py b/reachy_mini/src/reachy_mini/media/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..71432d90862359f05e8c978c2069a4f07eedc8b7 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/__init__.py @@ -0,0 +1 @@ +"""Media module.""" diff --git a/reachy_mini/src/reachy_mini/media/audio_base.py b/reachy_mini/src/reachy_mini/media/audio_base.py new file mode 100644 index 0000000000000000000000000000000000000000..4bea6c138e0c449c2eb3bed03b4e51b2393d428d --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/audio_base.py @@ -0,0 +1,102 @@ +"""Base classes for audio implementations. + +The audio implementations support various backends and provide a unified +interface for audio input/output. +""" + +import logging +from abc import ABC, abstractmethod +from typing import Optional + +import numpy as np +import numpy.typing as npt + +from reachy_mini.media.audio_control_utils import ReSpeaker, init_respeaker_usb + + +class AudioBase(ABC): + """Abstract class for opening and managing audio devices.""" + + SAMPLE_RATE = 16000 # respeaker samplerate + + def __init__(self, log_level: str = "INFO") -> None: + """Initialize the audio device.""" + self.logger = logging.getLogger(__name__) + self.logger.setLevel(log_level) + self._respeaker: Optional[ReSpeaker] = init_respeaker_usb() + + def __del__(self) -> None: + """Destructor to ensure resources are released.""" + if self._respeaker: + self._respeaker.close() + + @abstractmethod + def start_recording(self) -> None: + """Start recording audio.""" + pass + + @abstractmethod + def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]: + """Read audio data from the device. Returns the data or None if error.""" + pass + + def get_input_audio_samplerate(self) -> int: + """Get the input samplerate of the audio device.""" + return self.SAMPLE_RATE + + def get_output_audio_samplerate(self) -> int: + """Get the outputsamplerate of the audio device.""" + return self.SAMPLE_RATE + + @abstractmethod + def stop_recording(self) -> None: + """Close the audio device and release resources.""" + pass + + @abstractmethod + def start_playing(self) -> None: + """Start playing audio.""" + pass + + @abstractmethod + def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None: + """Push audio data to the output device.""" + pass + + @abstractmethod + def stop_playing(self) -> None: + """Stop playing audio and release resources.""" + pass + + @abstractmethod + def play_sound(self, sound_file: str) -> None: + """Play a sound file. + + Args: + sound_file (str): Path to the sound file to play. + + """ + pass + + def get_DoA(self) -> tuple[float, bool] | None: + """Get the Direction of Arrival (DoA) value from the ReSpeaker device. + + The spatial angle is given in radians: + 0 radians is left, π/2 radians is front/back, π radians is right. + + Note: The microphone array requires firmware version 2.1.0 or higher to support this feature. + The firmware is located in src/reachy_mini/assets/firmware/*.bin. + Refer to https://wiki.seeedstudio.com/respeaker_xvf3800_introduction/#update-firmware for the upgrade process. + + Returns: + tuple: A tuple containing the DoA value as a float (radians) and the speech detection as a bool, or None if the device is not found. + + """ + if not self._respeaker: + self.logger.warning("ReSpeaker device not found.") + return None + + result = self._respeaker.read("DOA_VALUE_RADIANS") + if result is None: + return None + return float(result[0]), bool(result[1]) diff --git a/reachy_mini/src/reachy_mini/media/audio_control_utils.py b/reachy_mini/src/reachy_mini/media/audio_control_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..97aed17cffd75566779dca393f2d5e819ac6c02b --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/audio_control_utils.py @@ -0,0 +1,428 @@ +"""Allows tuning of the XMOS XVF3800 chip. + +Example usage: + + # Read a parameter + python reachy_host.py AUDIO_MGR_OP_L + # Output: + # ReadCMD: cmdid: 143, resid: 35, response: array('B', [0, 8, 0]) + # AUDIO_MGR_OP_L: [0, 8, 0] + + # Write a parameter + python reachy_host.py AUDIO_MGR_OP_L --values 3 0 + # Output: + # Writing to AUDIO_MGR_OP_L with values: [3, 0] + # WriteCMD: cmdid: 15, resid: 35, payload: [3, 0] + # Write operation completed successfully + +More details about the parameters is available at: +https://www.xmos.com/documentation/XM-014888-PC/html/modules/fwk_xvf/doc/user_guide/AA_control_command_appendix.html +""" + +import argparse +import logging +import struct +import sys +import time +from typing import Any, Optional + +import usb.core +import usb.util +from libusb_package import get_libusb1_backend + +CONTROL_SUCCESS = 0 +SERVICER_COMMAND_RETRY = 64 + +# name, resid, cmdid, length, type +PARAMETERS = { + # APPLICATION_SERVICER_RESID commands + "VERSION": (48, 0, 3, "ro", "uint8"), + "BLD_MSG": (48, 1, 50, "ro", "char"), + "BLD_HOST": (48, 2, 30, "ro", "char"), + "BLD_REPO_HASH": (48, 3, 40, "ro", "char"), + "BLD_MODIFIED": (48, 4, 6, "ro", "char"), + "BOOT_STATUS": (48, 5, 3, "ro", "char"), + "TEST_CORE_BURN": (48, 6, 1, "rw", "uint8"), + "REBOOT": (48, 7, 1, "wo", "uint8"), + "USB_BIT_DEPTH": (48, 8, 2, "rw", "uint8"), + "SAVE_CONFIGURATION": (48, 9, 1, "wo", "uint8"), + "CLEAR_CONFIGURATION": (48, 10, 1, "wo", "uint8"), + # AEC_RESID commands + "SHF_BYPASS": (33, 70, 1, "rw", "uint8"), + "AEC_NUM_MICS": (33, 71, 1, "ro", "int32"), + "AEC_NUM_FARENDS": (33, 72, 1, "ro", "int32"), + "AEC_MIC_ARRAY_TYPE": (33, 73, 1, "ro", "int32"), + "AEC_MIC_ARRAY_GEO": (33, 74, 12, "ro", "float"), + "AEC_AZIMUTH_VALUES": (33, 75, 4, "ro", "radians"), + "TEST_AEC_DISABLE_CONTROL": (33, 76, 1, "wo", "uint32"), + "AEC_CURRENT_IDLE_TIME": (33, 77, 1, "ro", "uint32"), + "AEC_MIN_IDLE_TIME": (33, 78, 1, "ro", "uint32"), + "AEC_RESET_MIN_IDLE_TIME": (33, 79, 1, "wo", "uint32"), + "AEC_SPENERGY_VALUES": (33, 80, 4, "ro", "float"), + "AEC_FIXEDBEAMSAZIMUTH_VALUES": (33, 81, 2, "rw", "radians"), + "AEC_FIXEDBEAMSELEVATION_VALUES": (33, 82, 2, "rw", "radians"), + "AEC_FIXEDBEAMSGATING": (33, 83, 1, "rw", "uint8"), + "SPECIAL_CMD_AEC_FAR_MIC_INDEX": (33, 90, 2, "wo", "int32"), + "SPECIAL_CMD_AEC_FILTER_COEFF_START_OFFSET": (33, 91, 1, "rw", "int32"), + "SPECIAL_CMD_AEC_FILTER_COEFFS": (33, 92, 15, "rw", "float"), + "SPECIAL_CMD_AEC_FILTER_LENGTH": (33, 93, 1, "ro", "int32"), + "AEC_FILTER_CMD_ABORT": (33, 94, 1, "wo", "int32"), + "AEC_AECPATHCHANGE": (33, 0, 1, "ro", "int32"), + "AEC_HPFONOFF": (33, 1, 1, "rw", "int32"), + "AEC_AECSILENCELEVEL": (33, 2, 2, "rw", "float"), + "AEC_AECCONVERGED": (33, 3, 1, "ro", "int32"), + "AEC_AECEMPHASISONOFF": (33, 4, 1, "rw", "int32"), + "AEC_FAR_EXTGAIN": (33, 5, 1, "rw", "float"), + "AEC_PCD_COUPLINGI": (33, 6, 1, "rw", "float"), + "AEC_PCD_MINTHR": (33, 7, 1, "rw", "float"), + "AEC_PCD_MAXTHR": (33, 8, 1, "rw", "float"), + "AEC_RT60": (33, 9, 1, "ro", "float"), + "AEC_ASROUTONOFF": (33, 35, 1, "rw", "int32"), + "AEC_ASROUTGAIN": (33, 36, 1, "rw", "float"), + "AEC_FIXEDBEAMSONOFF": (33, 37, 1, "rw", "int32"), + "AEC_FIXEDBEAMNOISETHR": (33, 38, 2, "rw", "float"), + # AUDIO_MGR_RESID commands + "AUDIO_MGR_MIC_GAIN": (35, 0, 1, "rw", "float"), + "AUDIO_MGR_REF_GAIN": (35, 1, 1, "rw", "float"), + "AUDIO_MGR_CURRENT_IDLE_TIME": (35, 2, 1, "ro", "int32"), + "AUDIO_MGR_MIN_IDLE_TIME": (35, 3, 1, "ro", "int32"), + "AUDIO_MGR_RESET_MIN_IDLE_TIME": (35, 4, 1, "wo", "int32"), + "MAX_CONTROL_TIME": (35, 5, 1, "ro", "int32"), + "RESET_MAX_CONTROL_TIME": (35, 6, 1, "wo", "int32"), + "I2S_CURRENT_IDLE_TIME": (35, 7, 1, "ro", "int32"), + "I2S_MIN_IDLE_TIME": (35, 8, 1, "ro", "int32"), + "I2S_RESET_MIN_IDLE_TIME": (35, 9, 1, "wo", "int32"), + "I2S_INPUT_PACKED": (35, 10, 1, "rw", "uint8"), + "AUDIO_MGR_SELECTED_AZIMUTHS": (35, 11, 2, "ro", "radians"), + "AUDIO_MGR_SELECTED_CHANNELS": (35, 12, 2, "rw", "uint8"), + "AUDIO_MGR_OP_PACKED": (35, 13, 2, "rw", "uint8"), + "AUDIO_MGR_OP_UPSAMPLE": (35, 14, 2, "rw", "uint8"), + "AUDIO_MGR_OP_L": (35, 15, 2, "rw", "uint8"), + "AUDIO_MGR_OP_L_PK0": (35, 16, 2, "rw", "uint8"), + "AUDIO_MGR_OP_L_PK1": (35, 17, 2, "rw", "uint8"), + "AUDIO_MGR_OP_L_PK2": (35, 18, 2, "rw", "uint8"), + "AUDIO_MGR_OP_R": (35, 19, 2, "rw", "uint8"), + "AUDIO_MGR_OP_R_PK0": (35, 20, 2, "rw", "uint8"), + "AUDIO_MGR_OP_R_PK1": (35, 21, 2, "rw", "uint8"), + "AUDIO_MGR_OP_R_PK2": (35, 22, 2, "rw", "uint8"), + "AUDIO_MGR_OP_ALL": (35, 23, 12, "rw", "uint8"), + "I2S_INACTIVE": (35, 24, 1, "ro", "uint8"), + "AUDIO_MGR_FAR_END_DSP_ENABLE": (35, 25, 1, "rw", "uint8"), + "AUDIO_MGR_SYS_DELAY": (35, 26, 1, "rw", "int32"), + "I2S_DAC_DSP_ENABLE": (35, 27, 1, "rw", "uint8"), + # GPO_SERVICER_RESID commands + "GPO_READ_VALUES": (20, 0, 5, "ro", "uint8"), + "GPO_WRITE_VALUE": (20, 1, 2, "wo", "uint8"), + "GPO_PORT_PIN_INDEX": (20, 2, 2, "rw", "uint32"), + "GPO_PIN_VAL": (20, 3, 3, "wo", "uint8"), + "GPO_PIN_ACTIVE_LEVEL": (20, 4, 1, "rw", "uint32"), + "GPO_PIN_PWM_DUTY": (20, 5, 1, "rw", "uint8"), + "GPO_PIN_FLASH_MASK": (20, 6, 1, "rw", "uint32"), + "LED_EFFECT": (20, 12, 1, "rw", "uint8"), + "LED_BRIGHTNESS": (20, 13, 1, "rw", "uint8"), + "LED_GAMMIFY": (20, 14, 1, "rw", "uint8"), + "LED_SPEED": (20, 15, 1, "rw", "uint8"), + "LED_COLOR": (20, 16, 1, "rw", "uint32"), + "LED_DOA_COLOR": (20, 17, 2, "rw", "uint32"), + "DOA_VALUE": (20, 18, 2, "ro", "uint32"), + "DOA_VALUE_RADIANS": (20, 19, 2, "ro", "radians"), + # PP_RESID commands + "PP_CURRENT_IDLE_TIME": (17, 70, 1, "ro", "uint32"), + "PP_MIN_IDLE_TIME": (17, 71, 1, "ro", "uint32"), + "PP_RESET_MIN_IDLE_TIME": (17, 72, 1, "wo", "uint32"), + "SPECIAL_CMD_PP_NLMODEL_NROW_NCOL": (17, 90, 2, "ro", "int32"), + "SPECIAL_CMD_NLMODEL_START": (17, 91, 1, "wo", "int32"), + "SPECIAL_CMD_NLMODEL_COEFF_START_OFFSET": (17, 92, 1, "rw", "int32"), + "SPECIAL_CMD_PP_NLMODEL": (17, 93, 15, "rw", "float"), + "PP_NL_MODEL_CMD_ABORT": (17, 94, 1, "wo", "int32"), + "SPECIAL_CMD_PP_NLMODEL_BAND": (17, 95, 1, "rw", "uint8"), + "SPECIAL_CMD_PP_EQUALIZATION_NUM_BANDS": (17, 96, 1, "ro", "int32"), + "SPECIAL_CMD_EQUALIZATION_START": (17, 97, 1, "wo", "int32"), + "SPECIAL_CMD_EQUALIZATION_COEFF_START_OFFSET": (17, 98, 1, "rw", "int32"), + "SPECIAL_CMD_PP_EQUALIZATION": (17, 99, 15, "rw", "float"), + "PP_EQUALIZATION_CMD_ABORT": (17, 100, 1, "wo", "int32"), + "PP_AGCONOFF": (17, 10, 1, "rw", "int32"), + "PP_AGCMAXGAIN": (17, 11, 1, "rw", "float"), + "PP_AGCDESIREDLEVEL": (17, 12, 1, "rw", "float"), + "PP_AGCGAIN": (17, 13, 1, "rw", "float"), + "PP_AGCTIME": (17, 14, 1, "rw", "float"), + "PP_AGCFASTTIME": (17, 15, 1, "rw", "float"), + "PP_AGCALPHAFASTGAIN": (17, 16, 1, "rw", "float"), + "PP_AGCALPHASLOW": (17, 17, 1, "rw", "float"), + "PP_AGCALPHAFAST": (17, 18, 1, "rw", "float"), + "PP_LIMITONOFF": (17, 19, 1, "rw", "int32"), + "PP_LIMITPLIMIT": (17, 20, 1, "rw", "float"), + "PP_MIN_NS": (17, 21, 1, "rw", "float"), + "PP_MIN_NN": (17, 22, 1, "rw", "float"), + "PP_ECHOONOFF": (17, 23, 1, "rw", "int32"), + "PP_GAMMA_E": (17, 24, 1, "rw", "float"), + "PP_GAMMA_ETAIL": (17, 25, 1, "rw", "float"), + "PP_GAMMA_ENL": (17, 26, 1, "rw", "float"), + "PP_NLATTENONOFF": (17, 27, 1, "rw", "int32"), + "PP_NLAEC_MODE": (17, 28, 1, "rw", "int32"), + "PP_MGSCALE": (17, 29, 3, "rw", "float"), + "PP_FMIN_SPEINDEX": (17, 30, 1, "rw", "float"), + "PP_DTSENSITIVE": (17, 31, 1, "rw", "int32"), + "PP_ATTNS_MODE": (17, 32, 1, "rw", "int32"), + "PP_ATTNS_NOMINAL": (17, 33, 1, "rw", "float"), + "PP_ATTNS_SLOPE": (17, 34, 1, "rw", "float"), +} + + +class ReSpeaker: + """Class to interface with the ReSpeaker XVF3800 USB device.""" + + TIMEOUT = 100000 + + def __init__(self, dev: usb.core.Device) -> None: + """Initialize the ReSpeaker interface with the given USB device.""" + self.dev = dev + + def write(self, name: str, data_list: Any) -> None: + """Write data to a specified parameter on the ReSpeaker device.""" + try: + data = PARAMETERS[name] + except KeyError: + return + + if data[3] == "ro": + raise ValueError("{} is read-only".format(name)) + + if len(data_list) != data[2]: + raise ValueError("{} value count is not {}".format(name, data[2])) + + windex = data[0] # resid + wvalue = data[1] # cmdid + data_cnt = data[2] # cnt + data_type = data[4] # data type + payload = [] # type: ignore[var-annotated] + + if data_type == "float" or data_type == "radians": + for i in range(data_cnt): + payload += struct.pack(b"f", float(data_list[i])) + elif data_type == "char": + # For char arrays, convert string to bytes + payload = ( + bytearray(data_list, "utf-8") # type: ignore[assignment] + if isinstance(data_list, str) + else bytearray(data_list) + ) + elif data_type == "uint8": + for i in range(data_cnt): + payload += data_list[i].to_bytes(1, byteorder="little") + elif data_type == "uint32" or data_type == "int32": + for i in range(data_cnt): + payload += struct.pack( + b"I" if data_type == "uint32" else b"i", data_list[i] + ) + else: + # Default to int32 for other types + for i in range(data_cnt): + payload += struct.pack(b"i", data_list[i]) + + logging.debug( + "WriteCMD: cmdid: {}, resid: {}, payload: {}".format( + wvalue, windex, payload + ) + ) + + self.dev.ctrl_transfer( + usb.util.CTRL_OUT + | usb.util.CTRL_TYPE_VENDOR + | usb.util.CTRL_RECIPIENT_DEVICE, + 0, + wvalue, + windex, + payload, + self.TIMEOUT, + ) + + def read(self, name: str) -> Any: + """Read data from a specified parameter on the ReSpeaker device.""" + try: + data = PARAMETERS[name] + except KeyError: + return + + read_attempts = 1 + windex = data[0] # resid + wvalue = 0x80 | data[1] # cmdid + data_cnt = data[2] # cnt + data_type = data[4] # data type + if data_type == "uint8" or data_type == "char": + length = data_cnt + 1 # 1 byte for status + elif ( + data_type == "float" + or data_type == "radians" + or data_type == "uint32" + or data_type == "int32" + ): + length = data_cnt * 4 + 1 # 1 byte for status + + response = self.dev.ctrl_transfer( + usb.util.CTRL_IN + | usb.util.CTRL_TYPE_VENDOR + | usb.util.CTRL_RECIPIENT_DEVICE, + 0, + wvalue, + windex, + length, + self.TIMEOUT, + ) + while True: + if read_attempts > 100: + raise ValueError("Read attempt exceeds 100 times") + if response[0] == CONTROL_SUCCESS: + break + elif response[0] == SERVICER_COMMAND_RETRY: + read_attempts += 1 + response = self.dev.ctrl_transfer( + usb.util.CTRL_IN + | usb.util.CTRL_TYPE_VENDOR + | usb.util.CTRL_RECIPIENT_DEVICE, + 0, + wvalue, + windex, + length, + self.TIMEOUT, + ) + else: + raise ValueError("Unknown status code: {}".format(response[0])) + time.sleep(0.01) + + logging.info( + "ReadCMD: cmdid: {}, resid: {}, response: {}".format( + wvalue, windex, response + ) + ) + + if data_type == "uint8": + result = response.tolist() + elif data_type == "char": + # For char arrays, convert bytes to string + byte_data = response.tobytes() + # Remove status byte and null terminators + result = byte_data[1:].rstrip(b"\x00").decode("utf-8", errors="ignore") + elif data_type == "radians" or data_type == "float": + byte_data = response.tobytes() + match_str = "<" + for i in range(data_cnt): + match_str += "f" + result = struct.unpack(match_str, byte_data[1:]) + elif data_type == "uint32" or data_type == "int32": + result = response.tolist() + + return result + + def close(self) -> None: + """Close the interface.""" + usb.util.dispose_resources(self.dev) + + +def find(vid: int = 0x2886, pid: int = 0x001A) -> ReSpeaker | None: + """Find and return the ReSpeaker USB device with the given Vendor ID and Product ID.""" + dev = usb.core.find(idVendor=vid, idProduct=pid) + if not dev: + return None + + return ReSpeaker(dev) + + +def init_respeaker_usb() -> Optional[ReSpeaker]: + """Initialize the ReSpeaker USB device. Looks for both new and beta device IDs.""" + try: + dev = usb.core.find( + idVendor=0x38FB, idProduct=0x1001, backend=get_libusb1_backend() + ) + if dev is None: + dev = usb.core.find( + idVendor=0x2886, idProduct=0x001A, backend=get_libusb1_backend() + ) + if dev is None: + logging.error("No ReSpeaker USB device found !") + return None + else: + logging.warning("Old firmware detected on ReSpeaker USB device. Please update the firmware!") + return ReSpeaker(dev) + except usb.core.NoBackendError: + logging.error( + "No USB backend was found ! Make sure libusb_package is correctly installed with `pip install libusb_package`." + ) + return None + + +def main() -> None: + """Parse arguments and execute read/write commands.""" + parser = argparse.ArgumentParser( + description="Reachy Mini Audio Host Control Script" + ) + parser.add_argument( + "command", + choices=PARAMETERS.keys(), + help="Command to execute (e.g., VERSION, DOA_VALUE, etc.)", + ) + parser.add_argument( + "--vid", + type=lambda x: int(x, 0), + default=0x38FB, + help="Vendor ID (default: 0x38FB)", + ) + parser.add_argument( + "--pid", + type=lambda x: int(x, 0), + default=0x1001, + help="Product ID (default: 0x1001)", + ) + parser.add_argument( + "--values", + nargs="+", + type=float, + help="Values for write commands (only for write operations)", + ) + + args = parser.parse_args() + + dev = find(vid=args.vid, pid=args.pid) + if not dev: + print("No device found") + sys.exit(1) + + try: + if args.values: + if PARAMETERS[args.command][3] == "ro": + print(f"Error: {args.command} is read-only and cannot be written to") + sys.exit(1) + + if ( + PARAMETERS[args.command][4] != "float" + and PARAMETERS[args.command][4] != "radians" + ): + args.values = [int(v) for v in args.values] + + if PARAMETERS[args.command][2] != len(args.values): + print( + f"Error: {args.command} value count is {PARAMETERS[args.command][2]}, but {len(args.values)} values provided" + ) + sys.exit(1) + + print(f"Writing to {args.command} with values: {args.values}") + dev.write(args.command, args.values) + time.sleep(0.1) + print("Write operation completed successfully") + else: + if PARAMETERS[args.command][3] == "wo": + print(f"Error: {args.command} is write-only and cannot be read") + sys.exit(1) + + result = dev.read(args.command) + print(f"{args.command}: {result}") + + except Exception as e: + print(f"Error executing command {args.command}: {e}") + sys.exit(1) + finally: + dev.close() + + +if __name__ == "__main__": + main() diff --git a/reachy_mini/src/reachy_mini/media/audio_gstreamer.py b/reachy_mini/src/reachy_mini/media/audio_gstreamer.py new file mode 100644 index 0000000000000000000000000000000000000000..7a0f06158fb5dcf35af744e6055aaa338d1af4f2 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/audio_gstreamer.py @@ -0,0 +1,200 @@ +"""GStreamer camera backend. + +This module provides an implementation of the CameraBase class using GStreamer. +By default the module directly returns JPEG images as output by the camera. +""" + +from threading import Thread +from typing import Optional + +import numpy as np +import numpy.typing as npt + +try: + import gi +except ImportError as e: + raise ImportError( + "The 'gi' module is required for GStreamerCamera but could not be imported. \ + Please install the GStreamer backend: pip install .[gstreamer]." + ) from e + +gi.require_version("Gst", "1.0") +gi.require_version("GstApp", "1.0") + + +from gi.repository import GLib, Gst, GstApp # noqa: E402 + +from .audio_base import AudioBase # noqa: E402 + + +class GStreamerAudio(AudioBase): + """Audio implementation using GStreamer.""" + + def __init__(self, log_level: str = "INFO") -> None: + """Initialize the GStreamer audio.""" + super().__init__(log_level=log_level) + Gst.init(None) + self._loop = GLib.MainLoop() + self._thread_bus_calls = Thread(target=lambda: self._loop.run(), daemon=True) + self._thread_bus_calls.start() + + self._pipeline_record = Gst.Pipeline.new("audio_recorder") + self._appsink_audio: Optional[GstApp] = None + self._init_pipeline_record(self._pipeline_record) + self._bus_record = self._pipeline_record.get_bus() + self._bus_record.add_watch( + GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop + ) + + self._pipeline_playback = Gst.Pipeline.new("audio_player") + self._appsrc: Optional[GstApp] = None + self._init_pipeline_playback(self._pipeline_playback) + self._bus_playback = self._pipeline_playback.get_bus() + self._bus_playback.add_watch( + GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop + ) + + def _init_pipeline_record(self, pipeline: Gst.Pipeline) -> None: + self._appsink_audio = Gst.ElementFactory.make("appsink") + caps = Gst.Caps.from_string( + f"audio/x-raw,rate={self.SAMPLE_RATE},format=F32LE,layout=interleaved" + ) + self._appsink_audio.set_property("caps", caps) + self._appsink_audio.set_property("drop", True) # avoid overflow + self._appsink_audio.set_property("max-buffers", 500) + + autoaudiosrc = Gst.ElementFactory.make("autoaudiosrc") # use default mic + + queue = Gst.ElementFactory.make("queue") + audioconvert = Gst.ElementFactory.make("audioconvert") + audioresample = Gst.ElementFactory.make("audioresample") + + if not all( + [autoaudiosrc, queue, audioconvert, audioresample, self._appsink_audio] + ): + raise RuntimeError("Failed to create GStreamer elements") + + pipeline.add(autoaudiosrc) + pipeline.add(queue) + pipeline.add(audioconvert) + pipeline.add(audioresample) + pipeline.add(self._appsink_audio) + + autoaudiosrc.link(queue) + queue.link(audioconvert) + audioconvert.link(audioresample) + audioresample.link(self._appsink_audio) + + def __del__(self) -> None: + """Destructor to ensure gstreamer resources are released.""" + super().__del__() + self._loop.quit() + self._bus_record.remove_watch() + self._bus_playback.remove_watch() + + def _init_pipeline_playback(self, pipeline: Gst.Pipeline) -> None: + self._appsrc = Gst.ElementFactory.make("appsrc") + self._appsrc.set_property("format", Gst.Format.TIME) + self._appsrc.set_property("is-live", True) + caps = Gst.Caps.from_string( + f"audio/x-raw,format=F32LE,channels=1,rate={self.SAMPLE_RATE},layout=interleaved" + ) + self._appsrc.set_property("caps", caps) + + audioconvert = Gst.ElementFactory.make("audioconvert") + audioresample = Gst.ElementFactory.make("audioresample") + + queue = Gst.ElementFactory.make("queue") + audiosink = Gst.ElementFactory.make("autoaudiosink") # use default speaker + + pipeline.add(queue) + pipeline.add(audiosink) + pipeline.add(self._appsrc) + pipeline.add(audioconvert) + pipeline.add(audioresample) + + self._appsrc.link(queue) + queue.link(audioconvert) + audioconvert.link(audioresample) + audioresample.link(audiosink) + + def _on_bus_message(self, bus: Gst.Bus, msg: Gst.Message, loop) -> bool: # type: ignore[no-untyped-def] + t = msg.type + if t == Gst.MessageType.EOS: + self.logger.warning("End-of-stream") + return False + + elif t == Gst.MessageType.ERROR: + err, debug = msg.parse_error() + self.logger.error(f"Error: {err} {debug}") + return False + + return True + + def start_recording(self) -> None: + """Open the audio card using GStreamer.""" + self._pipeline_record.set_state(Gst.State.PLAYING) + + def _get_sample(self, appsink: GstApp.AppSink) -> Optional[bytes]: + sample = appsink.try_pull_sample(20_000_000) + if sample is None: + return None + data = None + if isinstance(sample, Gst.Sample): + buf = sample.get_buffer() + if buf is None: + self.logger.warning("Buffer is None") + + data = buf.extract_dup(0, buf.get_size()) + return data + + def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]: + """Read a sample from the audio card. Returns the sample or None if error. + + Returns: + Optional[npt.NDArray[np.float32]]: The captured sample in raw format, or None if error. + + """ + sample = self._get_sample(self._appsink_audio) + if sample is None: + return None + return np.frombuffer(sample, dtype=np.float32).reshape(-1, 2) + + def get_input_audio_samplerate(self) -> int: + """Get the input samplerate of the audio device.""" + return self.SAMPLE_RATE + + def get_output_audio_samplerate(self) -> int: + """Get the output samplerate of the audio device.""" + return self.SAMPLE_RATE + + def stop_recording(self) -> None: + """Release the camera resource.""" + self._pipeline_record.set_state(Gst.State.NULL) + + def start_playing(self) -> None: + """Open the audio output using GStreamer.""" + self._pipeline_playback.set_state(Gst.State.PLAYING) + + def stop_playing(self) -> None: + """Stop playing audio and release resources.""" + self._pipeline_playback.set_state(Gst.State.NULL) + + def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None: + """Push audio data to the output device.""" + if self._appsrc is not None: + buf = Gst.Buffer.new_wrapped(data.tobytes()) + self._appsrc.push_buffer(buf) + else: + self.logger.warning( + "AppSrc is not initialized. Call start_playing() first." + ) + + def play_sound(self, sound_file: str) -> None: + """Play a sound file. + + Args: + sound_file (str): Path to the sound file to play. + + """ + self.logger.warning("play_sound is not implemented for GStreamerAudio.") diff --git a/reachy_mini/src/reachy_mini/media/audio_sounddevice.py b/reachy_mini/src/reachy_mini/media/audio_sounddevice.py new file mode 100644 index 0000000000000000000000000000000000000000..e381c685cf2e4e7cbb6be071b6757fe14ed71af9 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/audio_sounddevice.py @@ -0,0 +1,242 @@ +"""Audio implementation using sounddevice backend.""" + +import os +import threading +from typing import Any, List, Optional + +import numpy as np +import numpy.typing as npt +import scipy +import sounddevice as sd +import soundfile as sf + +from reachy_mini.utils.constants import ASSETS_ROOT_PATH + +from .audio_base import AudioBase + + +class SoundDeviceAudio(AudioBase): + """Audio device implementation using sounddevice.""" + + def __init__( + self, + frames_per_buffer: int = 256, + log_level: str = "INFO", + ) -> None: + """Initialize the SoundDevice audio device.""" + super().__init__(log_level=log_level) + self.frames_per_buffer = frames_per_buffer + self.stream = None + self._output_stream = None + self._buffer: List[npt.NDArray[np.float32]] = [] + self._output_device_id = self._get_device_id( + ["Reachy Mini Audio", "respeaker"], device_io_type="output" + ) + self._input_device_id = self._get_device_id( + ["Reachy Mini Audio", "respeaker"], device_io_type="input" + ) + + def start_recording(self) -> None: + """Open the audio input stream, using ReSpeaker card if available.""" + self.stream = sd.InputStream( + blocksize=self.frames_per_buffer, + device=self._input_device_id, + callback=self._callback, + samplerate=self.get_input_audio_samplerate(), + ) + if self.stream is None: + raise RuntimeError("Failed to open SoundDevice audio stream.") + self._buffer.clear() + self.stream.start() + self.logger.info("SoundDevice audio stream opened.") + + def _callback( + self, + indata: npt.NDArray[np.float32], + frames: int, + time: int, + status: sd.CallbackFlags, + ) -> None: + if status: + self.logger.warning(f"SoundDevice status: {status}") + + self._buffer.append(indata.copy()) + + def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]: + """Read audio data from the buffer. Returns numpy array or None if empty.""" + if self._buffer and len(self._buffer) > 0: + data: npt.NDArray[np.float32] = np.concatenate(self._buffer, axis=0) + self._buffer.clear() + return data + self.logger.debug("No audio data available in buffer.") + return None + + def get_input_audio_samplerate(self) -> int: + """Get the input samplerate of the audio device.""" + return int( + sd.query_devices(self._input_device_id, "input")["default_samplerate"] + ) + + def get_output_audio_samplerate(self) -> int: + """Get the output samplerate of the audio device.""" + return int( + sd.query_devices(self._output_device_id, "output")["default_samplerate"] + ) + + def stop_recording(self) -> None: + """Close the audio stream and release resources.""" + if self.stream is not None: + self.stream.stop() + self.stream.close() + self.stream = None + self.logger.info("SoundDevice audio stream closed.") + + def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None: + """Push audio data to the output device.""" + if self._output_stream is not None: + if data.ndim > 1: # convert to mono + data = np.mean(data, axis=1) + self._output_stream.write(data) + else: + self.logger.warning( + "Output stream is not open. Call start_playing() first." + ) + + def start_playing(self) -> None: + """Open the audio output stream.""" + if self._output_stream is not None: + self.stop_playing() + self._output_stream = sd.OutputStream( + samplerate=self.get_output_audio_samplerate(), + device=self._output_device_id, + channels=1, + ) + if self._output_stream is None: + raise RuntimeError("Failed to open SoundDevice audio output stream.") + self._output_stream.start() + + def stop_playing(self) -> None: + """Close the audio output stream.""" + if self._output_stream is not None: + self._output_stream.stop() + self._output_stream.close() + self._output_stream = None + self.logger.info("SoundDevice audio output stream closed.") + + def play_sound(self, sound_file: str, autoclean: bool = False) -> None: + """Play a sound file. + + Args: + sound_file (str): Path to the sound file to play. May be given relative to the assets directory or as an absolute path. + autoclean (bool): If True, the audio device will be released after the sound is played. + + """ + if not os.path.exists(sound_file): + file_path = f"{ASSETS_ROOT_PATH}/{sound_file}" + if not os.path.exists(file_path): + raise FileNotFoundError( + f"Sound file {sound_file} not found in assets directory or given path." + ) + else: + file_path = sound_file + + data, samplerate_in = sf.read(file_path, dtype="float32") + samplerate_out = self.get_output_audio_samplerate() + + if samplerate_in != samplerate_out: + data = scipy.signal.resample( + data, int(len(data) * (samplerate_out / samplerate_in)) + ) + if data.ndim > 1: # convert to mono + data = np.mean(data, axis=1) + + self.logger.debug(f"Playing sound '{file_path}' at {samplerate_in} Hz") + + self.stop_playing() + start = 0 # current position in audio data + length = len(data) + + def callback( + outdata: npt.NDArray[np.float32], + frames: int, + time: Any, # cdata 'struct PaStreamCallbackTimeInfo * + status: sd.CallbackFlags, + ) -> None: + """Actual playback.""" + nonlocal start + + if status: + self.logger.warning(f"SoundDevice output status: {status}") + + end = start + frames + if end > length: + # Fill the output buffer with the audio data, or zeros if finished + outdata[: length - start, 0] = data[start:] + outdata[length - start :, 0] = 0 + raise sd.CallbackStop() + else: + outdata[:, 0] = data[start:end] + start = end + + stop_event = threading.Event() + + self._output_stream = sd.OutputStream( + samplerate=samplerate_out, + device=self._output_device_id, + channels=1, + callback=callback, + finished_callback=stop_event.set, # release the device when done + ) + if self._output_stream is None: + raise RuntimeError("Failed to open SoundDevice audio output stream.") + self._output_stream.start() + + if autoclean: + + def _clean_up_thread() -> None: + stop_event.wait() + self.stop_playing() + + threading.Thread( + target=_clean_up_thread, + daemon=True, + ).start() + + def _get_device_id( + self, names_contains: List[str], device_io_type: str = "output" + ) -> int: + """Return the output device id whose name contains the given strings (case-insensitive). + + Args: + names_contains (List[str]): List of strings that should be contained in the device name. + device_io_type (str): 'input' or 'output' to specify device type. + + If not found, return the default output device id. + + """ + devices = sd.query_devices() + + for idx, dev in enumerate(devices): + for name_contains in names_contains: + if ( + name_contains.lower() in dev["name"].lower() + and dev[f"max_{device_io_type}_channels"] > 0 + ): + return idx + # Return default output device if not found + self.logger.warning( + f"No {device_io_type} device found containing '{names_contains}', using default." + ) + return self._safe_query_device(device_io_type) + + def _safe_query_device(self, kind: str) -> int: + try: + return int(sd.query_devices(None, kind)["index"]) + except sd.PortAudioError: + return ( + int(sd.default.device[1]) + if kind == "input" + else int(sd.default.device[0]) + ) + except IndexError: + return 0 diff --git a/reachy_mini/src/reachy_mini/media/audio_utils.py b/reachy_mini/src/reachy_mini/media/audio_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..53dbbf17564d49efe626fb0b9f318f5b3ce58952 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/audio_utils.py @@ -0,0 +1,35 @@ +"""Utility functions for audio handling, specifically for detecting the ReSpeaker sound card.""" + +import logging +import subprocess + + +def get_respeaker_card_number() -> int: + """Return the card number of the ReSpeaker sound card, or 0 if not found.""" + try: + result = subprocess.run( + ["arecord", "-l"], capture_output=True, text=True, check=True + ) + output = result.stdout + + lines = output.split("\n") + for line in lines: + if "reachy mini audio" in line.lower() and "card" in line: + card_number = line.split(":")[0].split("card ")[1].strip() + logging.debug(f"Found Reachy Mini Audio sound card: {card_number}") + return int(card_number) + elif "respeaker" in line.lower() and "card" in line: + card_number = line.split(":")[0].split("card ")[1].strip() + logging.warning( + f"Found ReSpeaker sound card: {card_number}. Please update firmware!" + ) + return int(card_number) + + logging.warning( + "Reachy Mini Audio sound card not found. Returning default card" + ) + return 0 # default sound card + + except subprocess.CalledProcessError as e: + logging.error(f"Cannot find sound card: {e}") + return 0 diff --git a/reachy_mini/src/reachy_mini/media/camera_base.py b/reachy_mini/src/reachy_mini/media/camera_base.py new file mode 100644 index 0000000000000000000000000000000000000000..53b4a5b6252c4417aa1852c990d8197178d0af32 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/camera_base.py @@ -0,0 +1,100 @@ +"""Base classes for camera implementations. + +The camera implementations support various backends and provide a unified +interface for capturing images. +""" + +import logging +from abc import ABC, abstractmethod +from typing import Optional + +import numpy as np +import numpy.typing as npt + +from reachy_mini.media.camera_constants import ( + CameraResolution, + CameraSpecs, + MujocoCameraSpecs, +) + + +class CameraBase(ABC): + """Abstract class for opening and managing a camera.""" + + def __init__( + self, + log_level: str = "INFO", + ) -> None: + """Initialize the camera.""" + self.logger = logging.getLogger(__name__) + self.logger.setLevel(log_level) + self._resolution: Optional[CameraResolution] = None + self.camera_specs: Optional[CameraSpecs] = None + self.resized_K: Optional[npt.NDArray[np.float64]] = None + + @property + def resolution(self) -> tuple[int, int]: + """Get the current camera resolution as a tuple (width, height).""" + if self._resolution is None: + raise RuntimeError("Camera resolution is not set.") + return (self._resolution.value[0], self._resolution.value[1]) + + @property + def framerate(self) -> int: + """Get the current camera frames per second.""" + if self._resolution is None: + raise RuntimeError("Camera resolution is not set.") + return int(self._resolution.value[2]) + + @property + def K(self) -> Optional[npt.NDArray[np.float64]]: + """Get the camera intrinsic matrix for the current resolution.""" + return self.resized_K + + @property + def D(self) -> Optional[npt.NDArray[np.float64]]: + """Get the camera distortion coefficients.""" + if self.camera_specs is not None: + return self.camera_specs.D + return None + + def set_resolution(self, resolution: CameraResolution) -> None: + """Set the camera resolution.""" + if self.camera_specs is None: + raise RuntimeError( + "Camera specs not set. Open the camera before setting the resolution." + ) + + if isinstance(self.camera_specs, MujocoCameraSpecs): + raise RuntimeError( + "Cannot change resolution of Mujoco simulated camera for now." + ) + + if resolution not in self.camera_specs.available_resolutions: + raise ValueError( + f"Resolution not supported by the camera. Available resolutions are : {self.camera_specs.available_resolutions}" + ) + + w_ratio = resolution.value[0] / self.camera_specs.default_resolution.value[0] + h_ratio = resolution.value[1] / self.camera_specs.default_resolution.value[1] + self.resized_K = self.camera_specs.K.copy() + + self.resized_K[0, 0] *= w_ratio + self.resized_K[1, 1] *= h_ratio + self.resized_K[0, 2] *= w_ratio + self.resized_K[1, 2] *= h_ratio + + @abstractmethod + def open(self) -> None: + """Open the camera.""" + pass + + @abstractmethod + def read(self) -> Optional[npt.NDArray[np.uint8]]: + """Read an image from the camera. Returns the image or None if error.""" + pass + + @abstractmethod + def close(self) -> None: + """Close the camera and release resources.""" + pass diff --git a/reachy_mini/src/reachy_mini/media/camera_constants.py b/reachy_mini/src/reachy_mini/media/camera_constants.py new file mode 100644 index 0000000000000000000000000000000000000000..d3ba0f471e83def0c786ca18389ceac725809fe8 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/camera_constants.py @@ -0,0 +1,163 @@ +"""Camera constants for Reachy Mini.""" + +from dataclasses import dataclass, field +from enum import Enum +from typing import List + +import numpy as np +import numpy.typing as npt + + +class CameraResolution(Enum): + """Base class for camera resolutions.""" + + pass + + +class ArduCamResolution(CameraResolution): + """Camera resolutions. Arducam_12MP.""" + + R2304x1296 = (2304, 1296, 30) + R4608x2592 = (4608, 2592, 10) + R1920x1080 = (1920, 1080, 30) + R1600x1200 = (1600, 1200, 30) + R1280x720 = (1280, 720, 30) + + +class RPICameraResolution(CameraResolution): + """Camera resolutions. Raspberry Pi Camera. + + Camera supports higher resolutions but the h264 encoder won't follow. + """ + + R1920x1080 = (1920, 1080, 60) + R1600x1200 = (1600, 1200, 30) + R1536x864 = (1536, 864, 40) + R1280x720 = (1280, 720, 60) + + +class MujocoCameraResolution(CameraResolution): + """Camera resolutions for Mujoco simulated camera.""" + + R1280x720 = (1280, 720, 60) + + +@dataclass +class CameraSpecs: + """Base camera specifications.""" + + available_resolutions: List[CameraResolution] = field(default_factory=list) + default_resolution: CameraResolution = ArduCamResolution.R1280x720 + vid = 0 + pid = 0 + K: npt.NDArray[np.float64] = field(default_factory=lambda: np.eye(3)) + D: npt.NDArray[np.float64] = field(default_factory=lambda: np.zeros((5,))) + + +@dataclass +class ArducamSpecs(CameraSpecs): + """Arducam camera specifications.""" + + available_resolutions = [ + ArduCamResolution.R2304x1296, + ArduCamResolution.R4608x2592, + ArduCamResolution.R1920x1080, + ArduCamResolution.R1600x1200, + ArduCamResolution.R1280x720, + ] + default_resolution = ArduCamResolution.R1280x720 + vid = 0x0C45 + pid = 0x636D + K = np.array([[550.3564, 0.0, 638.0112], [0.0, 549.1653, 364.589], [0.0, 0.0, 1.0]]) + D = np.array([-0.0694, 0.1565, -0.0004, 0.0003, -0.0983]) + + +@dataclass +class ReachyMiniCamSpecs(CameraSpecs): + """Reachy Mini camera specifications.""" + + available_resolutions = [ + RPICameraResolution.R1920x1080, + RPICameraResolution.R1600x1200, + RPICameraResolution.R1536x864, + RPICameraResolution.R1280x720, + ] + default_resolution = RPICameraResolution.R1920x1080 + vid = 0x38FB + pid = 0x1002 + K = np.array( + [ + [821.515, 0.0, 962.241], + [0.0, 820.830, 542.459], + [0.0, 0.0, 1.0], + ] + ) + + D = np.array( + [ + -2.94475669e-02, + 6.00511974e-02, + 3.57813971e-06, + -2.96459394e-04, + -3.79243988e-02, + ] + ) + + +@dataclass +class OlderRPiCamSpecs(CameraSpecs): + """Older Raspberry Pi camera specifications.""" + + available_resolutions = [ + RPICameraResolution.R1920x1080, + RPICameraResolution.R1600x1200, + RPICameraResolution.R1536x864, + RPICameraResolution.R1280x720, + ] + default_resolution = RPICameraResolution.R1920x1080 + vid = 0x1BCF + pid = 0x28C4 + K = np.array( + [ + [821.51459423, 0.0, 962.24086301], + [0.0, 820.82987265, 542.45854246], + [0.0, 0.0, 1.0], + ] + ) + + D = np.array( + [ + -2.94475669e-02, + 6.00511974e-02, + 3.57813971e-06, + -2.96459394e-04, + -3.79243988e-02, + ] + ) + + +@dataclass +class MujocoCameraSpecs(CameraSpecs): + """Mujoco simulated camera specifications.""" + + available_resolutions = [ + MujocoCameraResolution.R1280x720, + ] + default_resolution = MujocoCameraResolution.R1280x720 + # ideal camera matrix + K = np.array( + [ + [ + MujocoCameraResolution.R1280x720.value[0], + 0.0, + MujocoCameraResolution.R1280x720.value[0] / 2, + ], + [ + 0.0, + MujocoCameraResolution.R1280x720.value[1], + MujocoCameraResolution.R1280x720.value[1] / 2, + ], + [0.0, 0.0, 1.0], + ] + ) + D = np.zeros((5,)) # no distortion diff --git a/reachy_mini/src/reachy_mini/media/camera_gstreamer.py b/reachy_mini/src/reachy_mini/media/camera_gstreamer.py new file mode 100644 index 0000000000000000000000000000000000000000..fc70a478c6a7e45dec2abc21c574c01fed1ff59c --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/camera_gstreamer.py @@ -0,0 +1,196 @@ +"""GStreamer camera backend. + +This module provides an implementation of the CameraBase class using GStreamer. +By default the module directly returns JPEG images as output by the camera. +""" + +from threading import Thread +from typing import Optional, cast + +import numpy as np +import numpy.typing as npt + +from reachy_mini.media.camera_constants import ( + ArducamSpecs, + CameraResolution, + CameraSpecs, + ReachyMiniCamSpecs, +) + +try: + import gi +except ImportError as e: + raise ImportError( + "The 'gi' module is required for GStreamerCamera but could not be imported. \ + Please install the GStreamer backend: pip install .[gstreamer]." + ) from e + +gi.require_version("Gst", "1.0") +gi.require_version("GstApp", "1.0") + + +from gi.repository import GLib, Gst, GstApp # noqa: E402 + +from .camera_base import CameraBase # noqa: E402 + + +class GStreamerCamera(CameraBase): + """Camera implementation using GStreamer.""" + + def __init__( + self, + log_level: str = "INFO", + ) -> None: + """Initialize the GStreamer camera.""" + super().__init__(log_level=log_level) + Gst.init(None) + self._loop = GLib.MainLoop() + self._thread_bus_calls: Optional[Thread] = None + + self.pipeline = Gst.Pipeline.new("camera_recorder") + + # TODO How do we hande video device not found ? + cam_path = self.get_video_device() + if self.camera_specs is None: + raise RuntimeError("Camera specs not set") + self._resolution = self.camera_specs.default_resolution + + if self._resolution is None: + raise RuntimeError("Failed to get default camera resolution.") + + # note for some applications the jpeg image could be directly used + self._appsink_video: GstApp = Gst.ElementFactory.make("appsink") + self.set_resolution(self._resolution) + self._appsink_video.set_property("drop", True) # avoid overflow + self._appsink_video.set_property("max-buffers", 1) # keep last image only + self.pipeline.add(self._appsink_video) + + # cam_path = self.get_video_device() + if cam_path == "": + self.logger.warning("Recording pipeline set without camera.") + self.pipeline.remove(self._appsink_video) + else: + camsrc = Gst.ElementFactory.make("v4l2src") + camsrc.set_property("device", cam_path) + self.pipeline.add(camsrc) + queue = Gst.ElementFactory.make("queue") + self.pipeline.add(queue) + # use vaapijpegdec or nvjpegdec for hardware acceleration + jpegdec = Gst.ElementFactory.make("jpegdec") + self.pipeline.add(jpegdec) + videoconvert = Gst.ElementFactory.make("videoconvert") + self.pipeline.add(videoconvert) + camsrc.link(queue) + queue.link(jpegdec) + jpegdec.link(videoconvert) + videoconvert.link(self._appsink_video) + + def _on_bus_message(self, bus: Gst.Bus, msg: Gst.Message, loop) -> bool: # type: ignore[no-untyped-def] + t = msg.type + if t == Gst.MessageType.EOS: + self.logger.warning("End-of-stream") + return False + + elif t == Gst.MessageType.ERROR: + err, debug = msg.parse_error() + self.logger.error(f"Error: {err} {debug}") + return False + + return True + + def _handle_bus_calls(self) -> None: + self.logger.debug("starting bus message loop") + bus = self.pipeline.get_bus() + bus.add_watch(GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop) + self._loop.run() + bus.remove_watch() + self.logger.debug("bus message loop stopped") + + def set_resolution(self, resolution: CameraResolution) -> None: + """Set the camera resolution.""" + super().set_resolution(resolution) + + # Check if pipeline is not playing before changing resolution + if self.pipeline.get_state(0).state == Gst.State.PLAYING: + raise RuntimeError( + "Cannot change resolution while the camera is streaming. Please close the camera first." + ) + + self._resolution = resolution + caps_video = Gst.Caps.from_string( + f"video/x-raw,format=BGR, width={self._resolution.value[0]},height={self._resolution.value[1]},framerate={self.framerate}/1" + ) + self._appsink_video.set_property("caps", caps_video) + + def open(self) -> None: + """Open the camera using GStreamer.""" + self.pipeline.set_state(Gst.State.PLAYING) + self._thread_bus_calls = Thread(target=self._handle_bus_calls, daemon=True) + self._thread_bus_calls.start() + + def _get_sample(self, appsink: GstApp.AppSink) -> Optional[bytes]: + sample = appsink.try_pull_sample(20_000_000) + if sample is None: + return None + data = None + if isinstance(sample, Gst.Sample): + buf = sample.get_buffer() + if buf is None: + self.logger.warning("Buffer is None") + + data = buf.extract_dup(0, buf.get_size()) + return data + + def read(self) -> Optional[npt.NDArray[np.uint8]]: + """Read a frame from the camera. Returns the frame or None if error. + + Returns: + Optional[npt.NDArray[np.uint8]]: The captured BGR frame as a NumPy array, or None if error. + + """ + data = self._get_sample(self._appsink_video) + if data is None: + return None + + arr = np.frombuffer(data, dtype=np.uint8).reshape( + (self.resolution[1], self.resolution[0], 3) + ) + return arr + + def close(self) -> None: + """Release the camera resource.""" + self._loop.quit() + self.pipeline.set_state(Gst.State.NULL) + + def get_video_device(self) -> str: + """Use Gst.DeviceMonitor to find the unix camera path /dev/videoX. + + Returns the device path (e.g., '/dev/video2'), or '' if not found. + """ + monitor = Gst.DeviceMonitor() + monitor.add_filter("Video/Source") + monitor.start() + + cam_names = ["Reachy", "Arducam_12MP"] + + devices = monitor.get_devices() + for cam_name in cam_names: + for device in devices: + name = device.get_display_name() + device_props = device.get_properties() + + if cam_name in name: + if device_props and device_props.has_field("api.v4l2.path"): + device_path = device_props.get_string("api.v4l2.path") + self.camera_specs = ( + cast(CameraSpecs, ArducamSpecs) + if cam_name == "Arducam_12MP" + else cast(CameraSpecs, ReachyMiniCamSpecs) + ) + self.resized_K = self.camera_specs.K + self.logger.debug(f"Found {cam_name} camera at {device_path}") + monitor.stop() + return str(device_path) + monitor.stop() + self.logger.warning("No camera found.") + return "" diff --git a/reachy_mini/src/reachy_mini/media/camera_opencv.py b/reachy_mini/src/reachy_mini/media/camera_opencv.py new file mode 100644 index 0000000000000000000000000000000000000000..a5c8d620bfd7768ed2f7bacdc9141c832d25501b --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/camera_opencv.py @@ -0,0 +1,79 @@ +"""OpenCv camera backend. + +This module provides an implementation of the CameraBase class using OpenCV. +""" + +from typing import Optional, cast + +import cv2 +import numpy as np +import numpy.typing as npt + +from reachy_mini.media.camera_constants import ( + CameraResolution, + CameraSpecs, + MujocoCameraSpecs, +) +from reachy_mini.media.camera_utils import find_camera + +from .camera_base import CameraBase + + +class OpenCVCamera(CameraBase): + """Camera implementation using OpenCV.""" + + def __init__( + self, + log_level: str = "INFO", + ) -> None: + """Initialize the OpenCV camera.""" + super().__init__(log_level=log_level) + self.cap: Optional[cv2.VideoCapture] = None + + def set_resolution(self, resolution: CameraResolution) -> None: + """Set the camera resolution.""" + super().set_resolution(resolution) + + self._resolution = resolution + if self.cap is not None: + self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self._resolution.value[0]) + self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self._resolution.value[1]) + + def open(self, udp_camera: Optional[str] = None) -> None: + """Open the camera using OpenCV VideoCapture.""" + if udp_camera: + self.cap = cv2.VideoCapture(udp_camera) + self.camera_specs = cast(CameraSpecs, MujocoCameraSpecs) + self._resolution = self.camera_specs.default_resolution + else: + self.cap, self.camera_specs = find_camera() + if self.cap is None or self.camera_specs is None: + raise RuntimeError("Camera not found") + + self._resolution = self.camera_specs.default_resolution + if self._resolution is None: + raise RuntimeError("Failed to get default camera resolution.") + + self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self._resolution.value[0]) + self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self._resolution.value[1]) + + self.resized_K = self.camera_specs.K + + if not self.cap.isOpened(): + raise RuntimeError("Failed to open camera") + + def read(self) -> Optional[npt.NDArray[np.uint8]]: + """Read a frame from the camera. Returns the frame or None if error.""" + if self.cap is None: + raise RuntimeError("Camera is not opened.") + ret, frame = self.cap.read() + if not ret: + return None + + return np.asarray(frame, dtype=np.uint8, copy=False) + + def close(self) -> None: + """Release the camera resource.""" + if self.cap is not None: + self.cap.release() + self.cap = None diff --git a/reachy_mini/src/reachy_mini/media/camera_utils.py b/reachy_mini/src/reachy_mini/media/camera_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..cfd1fc1161900cbf641c8e2d247fbebb2a0d2add --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/camera_utils.py @@ -0,0 +1,111 @@ +"""Camera utility for Reachy Mini.""" + +import platform +from typing import Optional, Tuple, cast + +import cv2 +from cv2_enumerate_cameras import enumerate_cameras + +from reachy_mini.media.camera_constants import ( + ArducamSpecs, + CameraSpecs, + OlderRPiCamSpecs, + ReachyMiniCamSpecs, +) + + +def find_camera( + apiPreference: int = cv2.CAP_ANY, no_cap: bool = False +) -> Tuple[Optional[cv2.VideoCapture], Optional[CameraSpecs]]: + """Find and return the Reachy Mini camera. + + Looks for the Reachy Mini camera first, then Arducam, then older Raspberry Pi Camera. Returns None if no camera is found. + + Args: + apiPreference (int): Preferred API backend for the camera. Default is cv2.CAP_ANY. + no_cap (bool): If True, close the camera after finding it. Default is False. + + Returns: + cv2.VideoCapture | None: A VideoCapture object if the camera is found and opened successfully, otherwise None. + + """ + cap = find_camera_by_vid_pid( + ReachyMiniCamSpecs.vid, ReachyMiniCamSpecs.pid, apiPreference + ) + if cap is not None: + fourcc = cv2.VideoWriter_fourcc("M", "J", "P", "G") # type: ignore + cap.set(cv2.CAP_PROP_FOURCC, fourcc) + if no_cap: + cap.release() + return cap, cast(CameraSpecs, ReachyMiniCamSpecs) + + cap = find_camera_by_vid_pid( + OlderRPiCamSpecs.vid, OlderRPiCamSpecs.pid, apiPreference + ) + if cap is not None: + fourcc = cv2.VideoWriter_fourcc("M", "J", "P", "G") # type: ignore + cap.set(cv2.CAP_PROP_FOURCC, fourcc) + if no_cap: + cap.release() + return cap, cast(CameraSpecs, OlderRPiCamSpecs) + + cap = find_camera_by_vid_pid(ArducamSpecs.vid, ArducamSpecs.pid, apiPreference) + if cap is not None: + if no_cap: + cap.release() + return cap, cast(CameraSpecs, ArducamSpecs) + + return None, None + + +def find_camera_by_vid_pid( + vid: int = ReachyMiniCamSpecs.vid, + pid: int = ReachyMiniCamSpecs.pid, + apiPreference: int = cv2.CAP_ANY, +) -> cv2.VideoCapture | None: + """Find and return a camera with the specified VID and PID. + + Args: + vid (int): Vendor ID of the camera. Default is ReachyMiniCamera + pid (int): Product ID of the camera. Default is ReachyMiniCamera + apiPreference (int): Preferred API backend for the camera. Default is cv2.CAP_ANY. + + Returns: + cv2.VideoCapture | None: A VideoCapture object if the camera is found and opened successfully, otherwise None. + + """ + if platform.system() == "Linux": + apiPreference = cv2.CAP_V4L2 + + selected_cap = None + for c in enumerate_cameras(apiPreference): + if c.vid == vid and c.pid == pid: + # the Arducam camera creates two /dev/videoX devices + # that enumerate_cameras cannot differentiate + try: + cap = cv2.VideoCapture(c.index, c.backend) + if cap.isOpened(): + selected_cap = cap + except Exception as e: + print(f"Error opening camera {c.index}: {e}") + return selected_cap + + +if __name__ == "__main__": + from reachy_mini.media.camera_constants import ArduCamResolution + + cam, _ = find_camera() + if cam is None: + exit("Camera not found") + + cam.set(cv2.CAP_PROP_FRAME_WIDTH, ArduCamResolution.R1280x720.value[0]) + cam.set(cv2.CAP_PROP_FRAME_HEIGHT, ArduCamResolution.R1280x720.value[1]) + + while True: + ret, frame = cam.read() + if not ret: + print("Failed to grab frame") + break + cv2.imshow("Camera Feed", frame) + if cv2.waitKey(1) & 0xFF == ord("q"): + break diff --git a/reachy_mini/src/reachy_mini/media/media_manager.py b/reachy_mini/src/reachy_mini/media/media_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..956edb3bc52419b1e273efc16ff8a399a63b5287 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/media_manager.py @@ -0,0 +1,235 @@ +"""Media Manager. + +Provides camera and audio access based on the selected backedn +""" + +import logging +from enum import Enum +from typing import Optional + +import numpy as np +import numpy.typing as npt + +from reachy_mini.media.audio_base import AudioBase +from reachy_mini.media.camera_base import CameraBase + +# actual backends are dynamically imported + + +class MediaBackend(Enum): + """Media backends.""" + + NO_MEDIA = "no_media" + DEFAULT = "default" + DEFAULT_NO_VIDEO = "default_no_video" + GSTREAMER = "gstreamer" + WEBRTC = "webrtc" + + +class MediaManager: + """Abstract class for opening and managing audio devices.""" + + def __init__( + self, + backend: MediaBackend = MediaBackend.DEFAULT, + log_level: str = "INFO", + use_sim: bool = False, + signalling_host: str = "localhost", + ) -> None: + """Initialize the audio device.""" + self.logger = logging.getLogger(__name__) + self.logger.setLevel(log_level) + self.backend = backend + self.camera: Optional[CameraBase] = None + self.audio: Optional[AudioBase] = None + + match backend: + case MediaBackend.NO_MEDIA: + self.logger.info("No media backend selected.") + case MediaBackend.DEFAULT: + self.logger.info("Using default media backend (OpenCV + SoundDevice).") + self._init_camera(use_sim, log_level) + self._init_audio(log_level) + case MediaBackend.DEFAULT_NO_VIDEO: + self.logger.info("Using default media backend (SoundDevice only).") + self._init_audio(log_level) + case MediaBackend.GSTREAMER: + self.logger.info("Using GStreamer media backend.") + self._init_camera(use_sim, log_level) + self._init_audio(log_level) + case MediaBackend.WEBRTC: + self.logger.info("Using WebRTC GStreamer backend.") + self._init_webrtc(log_level, signalling_host, 8443) + case _: + raise NotImplementedError(f"Media backend {backend} not implemented.") + + def close(self) -> None: + """Close the media manager and release resources.""" + if self.camera is not None: + self.camera.close() + if self.audio is not None: + self.audio.stop_recording() + self.audio.stop_playing() + + def __del__(self) -> None: + """Destructor to ensure resources are released.""" + self.close() + + def _init_camera( + self, + use_sim: bool, + log_level: str, + ) -> None: + """Initialize the camera.""" + self.logger.debug("Initializing camera...") + if self.backend == MediaBackend.DEFAULT: + self.logger.info("Using OpenCV camera backend.") + from reachy_mini.media.camera_opencv import OpenCVCamera + + self.camera = OpenCVCamera(log_level=log_level) + if use_sim: + self.camera.open(udp_camera="udp://@127.0.0.1:5005") + else: + self.camera.open() + elif self.backend == MediaBackend.GSTREAMER: + self.logger.info("Using GStreamer camera backend.") + from reachy_mini.media.camera_gstreamer import GStreamerCamera + + self.camera = GStreamerCamera(log_level=log_level) + self.camera.open() + # Todo: use simulation with gstreamer? + + else: + raise NotImplementedError(f"Camera backend {self.backend} not implemented.") + + def get_frame(self) -> Optional[npt.NDArray[np.uint8]]: + """Get a frame from the camera. + + Returns: + Optional[npt.NDArray[np.uint8]]: The captured BGR frame, or None if the camera is not available. + + """ + if self.camera is None: + self.logger.warning("Camera is not initialized.") + return None + return self.camera.read() + + def _init_audio(self, log_level: str) -> None: + """Initialize the audio system.""" + self.logger.debug("Initializing audio...") + if ( + self.backend == MediaBackend.DEFAULT + or self.backend == MediaBackend.DEFAULT_NO_VIDEO + ): + self.logger.info("Using SoundDevice audio backend.") + from reachy_mini.media.audio_sounddevice import SoundDeviceAudio + + self.audio = SoundDeviceAudio(log_level=log_level) + elif self.backend == MediaBackend.GSTREAMER: + self.logger.info("Using GStreamer audio backend.") + from reachy_mini.media.audio_gstreamer import GStreamerAudio + + self.audio = GStreamerAudio(log_level=log_level) + else: + raise NotImplementedError(f"Audio backend {self.backend} not implemented.") + + def _init_webrtc( + self, log_level: str, signalling_host: str, signalling_port: int + ) -> None: + """Initialize the WebRTC system (not implemented yet).""" + from gst_signalling.utils import find_producer_peer_id_by_name + + from reachy_mini.media.webrtc_client_gstreamer import GstWebRTCClient + + peer_id = find_producer_peer_id_by_name( + signalling_host, signalling_port, "reachymini" + ) + + webrtc_media: GstWebRTCClient = GstWebRTCClient( + log_level=log_level, + peer_id=peer_id, + signaling_host=signalling_host, + signaling_port=signalling_port, + ) + + self.camera = webrtc_media + self.audio = webrtc_media # GstWebRTCClient handles both audio and video + self.camera.open() + + def play_sound(self, sound_file: str) -> None: + """Play a sound file. + + Args: + sound_file (str): Path to the sound file to play. + + """ + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return + self.audio.play_sound(sound_file) + + def start_recording(self) -> None: + """Start recording audio.""" + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return + self.audio.start_recording() + + def get_audio_sample(self) -> Optional[bytes | npt.NDArray[np.float32]]: + """Get an audio sample from the audio device. + + Returns: + Optional[np.ndarray]: The recorded audio sample, or None if no data is available. + + """ + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return None + return self.audio.get_audio_sample() + + def get_input_audio_samplerate(self) -> int: + """Get the input samplerate of the audio device.""" + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return -1 + return self.audio.get_input_audio_samplerate() + + def get_output_audio_samplerate(self) -> int: + """Get the output samplerate of the audio device.""" + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return -1 + return self.audio.get_output_audio_samplerate() + + def stop_recording(self) -> None: + """Stop recording audio.""" + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return + self.audio.stop_recording() + + def start_playing(self) -> None: + """Start playing audio.""" + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return + self.audio.start_playing() + + def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None: + """Push audio data to the output device. + + Args: + data (npt.NDArray[np.float32]): The audio data to push to the output device (mono format). + + """ + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return + self.audio.push_audio_sample(data) + + def stop_playing(self) -> None: + """Stop playing audio.""" + if self.audio is None: + self.logger.warning("Audio system is not initialized.") + return + self.audio.stop_playing() diff --git a/reachy_mini/src/reachy_mini/media/webrtc_client_gstreamer.py b/reachy_mini/src/reachy_mini/media/webrtc_client_gstreamer.py new file mode 100644 index 0000000000000000000000000000000000000000..e67c5f05c1344f2d2a2b633ba3c28a2d7a098f24 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/webrtc_client_gstreamer.py @@ -0,0 +1,289 @@ +"""GStreamer WebRTC client implementation. + +The class is a client for the webrtc server hosted on the Reachy Mini Wireless robot. +""" + +from threading import Thread +from typing import Optional, cast + +import gi +import numpy as np +import numpy.typing as npt + +from reachy_mini.media.audio_base import AudioBase +from reachy_mini.media.camera_base import CameraBase +from reachy_mini.media.camera_constants import ( + CameraResolution, + CameraSpecs, + ReachyMiniCamSpecs, + RPICameraResolution, +) + +gi.require_version("Gst", "1.0") +gi.require_version("GstApp", "1.0") +from gi.repository import GLib, Gst, GstApp # noqa: E402, F401 + + +class GstWebRTCClient(CameraBase, AudioBase): + """GStreamer WebRTC client implementation.""" + + def __init__( + self, + log_level: str = "INFO", + peer_id: str = "", + signaling_host: str = "", + signaling_port: int = 8443, + ): + """Initialize the GStreamer WebRTC client.""" + super().__init__(log_level=log_level) + Gst.init(None) + self._loop = GLib.MainLoop() + self._thread_bus_calls = Thread(target=lambda: self._loop.run(), daemon=True) + self._thread_bus_calls.start() + + self._pipeline_record = Gst.Pipeline.new("audio_recorder") + self._bus_record = self._pipeline_record.get_bus() + self._bus_record.add_watch( + GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop + ) + + self._appsink_audio = Gst.ElementFactory.make("appsink") + caps = Gst.Caps.from_string( + f"audio/x-raw,rate={self.SAMPLE_RATE},format=F32LE,layout=interleaved" + ) + self._appsink_audio.set_property("caps", caps) + self._appsink_audio.set_property("drop", True) # avoid overflow + self._appsink_audio.set_property("max-buffers", 500) + self._pipeline_record.add(self._appsink_audio) + + self.camera_specs = cast(CameraSpecs, ReachyMiniCamSpecs) + self.set_resolution(RPICameraResolution.R1280x720) + + self._appsink_video = Gst.ElementFactory.make("appsink") + caps_video = Gst.Caps.from_string("video/x-raw,format=BGR") + self._appsink_video.set_property("caps", caps_video) + self._appsink_video.set_property("drop", True) # avoid overflow + self._appsink_video.set_property("max-buffers", 1) # keep last image only + self._pipeline_record.add(self._appsink_video) + + webrtcsrc = self._configure_webrtcsrc(signaling_host, signaling_port, peer_id) + self._pipeline_record.add(webrtcsrc) + + self._pipeline_playback = Gst.Pipeline.new("audio_player") + self._init_pipeline_playback( + self._pipeline_playback, signaling_host, signaling_port + ) + self._bus_playback = self._pipeline_playback.get_bus() + self._bus_playback.add_watch( + GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop + ) + + def __del__(self) -> None: + """Destructor to ensure gstreamer resources are released.""" + super().__del__() + self._loop.quit() + self._bus_record.remove_watch() + self._bus_playback.remove_watch() + + def set_resolution(self, resolution: CameraResolution) -> None: + """Set the camera resolution.""" + super().set_resolution(resolution) + self._resolution = resolution + + def _configure_webrtcsrc( + self, signaling_host: str, signaling_port: int, peer_id: str + ) -> Gst.Element: + source = Gst.ElementFactory.make("webrtcsrc") + if not source: + raise RuntimeError( + "Failed to create webrtcsrc element. Is the GStreamer webrtc rust plugin installed?" + ) + + source.connect("pad-added", self._webrtcsrc_pad_added_cb) + signaller = source.get_property("signaller") + signaller.set_property("producer-peer-id", peer_id) + signaller.set_property("uri", f"ws://{signaling_host}:{signaling_port}") + return source + + def _configure_webrtcbin(self, webrtcsrc: Gst.Element) -> None: + if isinstance(webrtcsrc, Gst.Bin): + webrtcbin_name = "webrtcbin0" + webrtcbin = webrtcsrc.get_by_name(webrtcbin_name) + assert webrtcbin is not None + # jitterbuffer has a default 200 ms buffer. Should be ok to lower this in localnetwork config + webrtcbin.set_property("latency", 100) + + def _webrtcsrc_pad_added_cb(self, webrtcsrc: Gst.Element, pad: Gst.Pad) -> None: + self._configure_webrtcbin(webrtcsrc) + if pad.get_name().startswith("video"): + queue = Gst.ElementFactory.make("queue") + + videoconvert = Gst.ElementFactory.make("videoconvert") + videoscale = Gst.ElementFactory.make("videoscale") + videorate = Gst.ElementFactory.make("videorate") + + self._pipeline_record.add(queue) + self._pipeline_record.add(videoconvert) + self._pipeline_record.add(videoscale) + self._pipeline_record.add(videorate) + pad.link(queue.get_static_pad("sink")) + + queue.link(videoconvert) + videoconvert.link(videoscale) + videoscale.link(videorate) + videorate.link(self._appsink_video) + + queue.sync_state_with_parent() + videoconvert.sync_state_with_parent() + videoscale.sync_state_with_parent() + videorate.sync_state_with_parent() + self._appsink_video.sync_state_with_parent() + + elif pad.get_name().startswith("audio"): + audioconvert = Gst.ElementFactory.make("audioconvert") + audioresample = Gst.ElementFactory.make("audioresample") + self._pipeline_record.add(audioconvert) + self._pipeline_record.add(audioresample) + + pad.link(audioconvert.get_static_pad("sink")) + audioconvert.link(audioresample) + audioresample.link(self._appsink_audio) + + self._appsink_audio.sync_state_with_parent() + audioconvert.sync_state_with_parent() + audioresample.sync_state_with_parent() + + def _on_bus_message(self, bus: Gst.Bus, msg: Gst.Message, loop) -> bool: # type: ignore[no-untyped-def] + t = msg.type + if t == Gst.MessageType.EOS: + self.logger.warning("End-of-stream") + return False + + elif t == Gst.MessageType.ERROR: + err, debug = msg.parse_error() + self.logger.error(f"Error: {err} {debug}") + return False + + return True + + def open(self) -> None: + """Open the video stream.""" + self._pipeline_record.set_state(Gst.State.PLAYING) + + def _get_sample(self, appsink: GstApp.AppSink) -> Optional[bytes]: + sample = appsink.try_pull_sample(20_000_000) + if sample is None: + return None + data = None + if isinstance(sample, Gst.Sample): + buf = sample.get_buffer() + if buf is None: + self.logger.warning("Buffer is None") + + data = buf.extract_dup(0, buf.get_size()) + return data + + def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]: + """Read a sample from the audio card. Returns the sample or None if error. + + Returns: + Optional[npt.NDArray[np.float32]]: The captured sample in raw format, or None if error. + + """ + sample = self._get_sample(self._appsink_audio) + if sample is None: + return None + return np.frombuffer(sample, dtype=np.float32).reshape(-1, 2) + + def read(self) -> Optional[npt.NDArray[np.uint8]]: + """Read a frame from the camera. Returns the frame or None if error. + + Returns: + Optional[npt.NDArray[np.uint8]]: The captured frame in BGR format, or None if error. + + """ + data = self._get_sample(self._appsink_video) + if data is None: + return None + + arr = np.frombuffer(data, dtype=np.uint8).reshape( + (self.resolution[1], self.resolution[0], 3) + ) + return arr + + def close(self) -> None: + """Stop the pipeline.""" + # self._loop.quit() + self._pipeline_record.set_state(Gst.State.NULL) + + def start_recording(self) -> None: + """Open the audio card using GStreamer.""" + pass # already started in open() + + def stop_recording(self) -> None: + """Release the camera resource.""" + pass # managed in close() + + def _init_pipeline_playback( + self, pipeline: Gst.Pipeline, signaling_host: str, signaling_port: int + ) -> None: + """Initialize the audio playback pipeline.""" + self._appsrc = Gst.ElementFactory.make("appsrc") + self._appsrc.set_property("format", Gst.Format.TIME) + self._appsrc.set_property("is-live", True) + caps = Gst.Caps.from_string( + f"audio/x-raw,format=F32LE,channels=1,rate={self.SAMPLE_RATE},layout=interleaved" + ) + self._appsrc.set_property("caps", caps) + audioconvert = Gst.ElementFactory.make("audioconvert") + audioresample = Gst.ElementFactory.make("audioresample") + opusenc = Gst.ElementFactory.make("opusenc") + queue = Gst.ElementFactory.make("queue") + rtpopuspay = Gst.ElementFactory.make("rtpopuspay") + udpsink = Gst.ElementFactory.make("udpsink") + + udpsink.set_property("host", signaling_host) + udpsink.set_property("port", 5000) + + pipeline.add(self._appsrc) + pipeline.add(audioconvert) + pipeline.add(audioresample) + pipeline.add(opusenc) + pipeline.add(queue) + pipeline.add(rtpopuspay) + pipeline.add(udpsink) + + self._appsrc.link(audioconvert) + audioconvert.link(audioresample) + audioresample.link(opusenc) + opusenc.link(queue) + queue.link(rtpopuspay) + rtpopuspay.link(udpsink) + + def start_playing(self) -> None: + """Open the audio output using GStreamer.""" + self._pipeline_playback.set_state(Gst.State.PLAYING) + + def stop_playing(self) -> None: + """Stop playing audio and release resources.""" + self._pipeline_playback.set_state(Gst.State.NULL) + + def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None: + """Push audio data to the output device.""" + if self._appsrc is not None: + buf = Gst.Buffer.new_wrapped(data.tobytes()) + self._appsrc.push_buffer(buf) + + else: + self.logger.warning( + "AppSrc is not initialized. Call start_playing() first." + ) + + def play_sound(self, sound_file: str) -> None: + """Play a sound file. + + Args: + sound_file (str): Path to the sound file to play. + + """ + self.logger.warning("Audio playback not implemented in WebRTC client.") diff --git a/reachy_mini/src/reachy_mini/media/webrtc_daemon.py b/reachy_mini/src/reachy_mini/media/webrtc_daemon.py new file mode 100644 index 0000000000000000000000000000000000000000..f718a9bd494f21348e88a61a043525e9a1589bc4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/media/webrtc_daemon.py @@ -0,0 +1,266 @@ +"""WebRTC daemon. + +Starts a gstreamer webrtc pipeline to stream video and audio. +""" + +import logging +from threading import Thread + +import gi + +from reachy_mini.media.audio_utils import get_respeaker_card_number +from reachy_mini.media.camera_constants import RPICameraResolution + +gi.require_version("Gst", "1.0") +gi.require_version("GstApp", "1.0") + +from gi.repository import GLib, Gst # noqa: E402 + + +class GstWebRTC: + """WebRTC pipeline using GStreamer.""" + + def __init__( + self, + log_level: str = "INFO", + resolution: RPICameraResolution = RPICameraResolution.R1280x720, + ) -> None: + """Initialize the GStreamer WebRTC pipeline.""" + self._logger = logging.getLogger(__name__) + self._logger.setLevel(log_level) + Gst.init(None) + self._loop = GLib.MainLoop() + self._thread_bus_calls = Thread(target=lambda: self._loop.run(), daemon=True) + self._thread_bus_calls.start() + self._resolution = resolution + + self._id_audio_card = get_respeaker_card_number() + + self._pipeline_sender = Gst.Pipeline.new("reachymini_webrtc_sender") + self._bus_sender = self._pipeline_sender.get_bus() + self._bus_sender.add_watch( + GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop + ) + + webrtcsink = self._configure_webrtc(self._pipeline_sender) + + self._configure_video(self._pipeline_sender, webrtcsink) + self._configure_audio(self._pipeline_sender, webrtcsink) + + self._pipeline_receiver = Gst.Pipeline.new("reachymini_webrtc_receiver") + self._bus_receiver = self._pipeline_receiver.get_bus() + self._bus_receiver.add_watch( + GLib.PRIORITY_DEFAULT, self._on_bus_message, self._loop + ) + self._configure_receiver(self._pipeline_receiver) + + def __del__(self) -> None: + """Destructor to ensure gstreamer resources are released.""" + self._loop.quit() + self._bus_sender.remove_watch() + self._bus_receiver.remove_watch() + + def _configure_webrtc(self, pipeline: Gst.Pipeline) -> Gst.Element: + self._logger.debug("Configuring WebRTC") + webrtcsink = Gst.ElementFactory.make("webrtcsink") + if not webrtcsink: + raise RuntimeError( + "Failed to create webrtcsink element. Is the GStreamer webrtc rust plugin installed?" + ) + + meta_structure = Gst.Structure.new_empty("meta") + meta_structure.set_value("name", "reachymini") + webrtcsink.set_property("meta", meta_structure) + webrtcsink.set_property("run-signalling-server", True) + + pipeline.add(webrtcsink) + + return webrtcsink + + def _configure_receiver(self, pipeline: Gst.Pipeline) -> None: + udpsrc = Gst.ElementFactory.make("udpsrc") + udpsrc.set_property("port", 5000) + caps = Gst.Caps.from_string( + "application/x-rtp,media=audio,encoding-name=OPUS,payload=96" + ) + capsfilter = Gst.ElementFactory.make("capsfilter") + capsfilter.set_property("caps", caps) + rtpjitterbuffer = Gst.ElementFactory.make("rtpjitterbuffer") + rtpjitterbuffer.set_property( + "latency", 200 + ) # configure latency depending on network conditions + rtpopusdepay = Gst.ElementFactory.make("rtpopusdepay") + opusdec = Gst.ElementFactory.make("opusdec") + queue = Gst.ElementFactory.make("queue") + audioconvert = Gst.ElementFactory.make("audioconvert") + audioresample = Gst.ElementFactory.make("audioresample") + alsasink = Gst.ElementFactory.make("alsasink") + alsasink.set_property("device", f"hw:{self._id_audio_card},0") + alsasink.set_property("sync", False) + + pipeline.add(udpsrc) + pipeline.add(capsfilter) + pipeline.add(rtpjitterbuffer) + pipeline.add(rtpopusdepay) + pipeline.add(opusdec) + pipeline.add(queue) + pipeline.add(audioconvert) + pipeline.add(audioresample) + pipeline.add(alsasink) + + udpsrc.link(capsfilter) + capsfilter.link(rtpjitterbuffer) + rtpjitterbuffer.link(rtpopusdepay) + rtpopusdepay.link(opusdec) + opusdec.link(queue) + queue.link(audioconvert) + audioconvert.link(audioresample) + audioresample.link(alsasink) + + @property + def resolution(self) -> tuple[int, int]: + """Get the current camera resolution as a tuple (width, height).""" + return (self._resolution.value[0], self._resolution.value[1]) + + @property + def framerate(self) -> int: + """Get the current camera framerate.""" + return self._resolution.value[2] + + def _configure_video(self, pipeline: Gst.Pipeline, webrtcsink: Gst.Element) -> None: + self._logger.debug("Configuring video") + libcamerasrc = Gst.ElementFactory.make("libcamerasrc") + + caps = Gst.Caps.from_string( + f"video/x-raw,width={self.resolution[0]},height={self.resolution[1]},framerate={self.framerate}/1,format=YUY2,colorimetry=bt709,interlace-mode=progressive" + ) + capsfilter = Gst.ElementFactory.make("capsfilter") + capsfilter.set_property("caps", caps) + queue = Gst.ElementFactory.make("queue") + v4l2h264enc = Gst.ElementFactory.make("v4l2h264enc") + extra_controls_structure = Gst.Structure.new_empty("extra-controls") + extra_controls_structure.set_value("repeat_sequence_header", 1) + extra_controls_structure.set_value("video_bitrate", 5_000_000) + v4l2h264enc.set_property("extra-controls", extra_controls_structure) + caps_h264 = Gst.Caps.from_string( + "video/x-h264,stream-format=byte-stream,alignment=au,level=(string)4" + ) + capsfilter_h264 = Gst.ElementFactory.make("capsfilter") + capsfilter_h264.set_property("caps", caps_h264) + + if not all( + [ + libcamerasrc, + capsfilter, + queue, + v4l2h264enc, + capsfilter_h264, + ] + ): + raise RuntimeError("Failed to create GStreamer video elements") + + pipeline.add(libcamerasrc) + pipeline.add(capsfilter) + pipeline.add(queue) + pipeline.add(v4l2h264enc) + pipeline.add(capsfilter_h264) + + libcamerasrc.link(capsfilter) + capsfilter.link(queue) + queue.link(v4l2h264enc) + v4l2h264enc.link(capsfilter_h264) + capsfilter_h264.link(webrtcsink) + + def _configure_audio(self, pipeline: Gst.Pipeline, webrtcsink: Gst.Element) -> None: + self._logger.debug("Configuring audio") + alsasrc = Gst.ElementFactory.make("alsasrc") + alsasrc.set_property("device", f"hw:{self._id_audio_card},0") + queue = Gst.ElementFactory.make("queue") + audioconvert = Gst.ElementFactory.make("audioconvert") + audioresample = Gst.ElementFactory.make("audioresample") + opusenc = Gst.ElementFactory.make("opusenc") + opusenc.set_property("audio-type", "restricted-lowdelay") + caps = Gst.Caps.from_string("audio/x-opus,channels=1,rate=48000") + capsfilter = Gst.ElementFactory.make("capsfilter") + capsfilter.set_property("caps", caps) + + if not all( + [ + alsasrc, + queue, + audioconvert, + audioresample, + opusenc, + capsfilter, + ] + ): + raise RuntimeError("Failed to create GStreamer audio elements") + + pipeline.add(alsasrc) + pipeline.add(queue) + pipeline.add(audioconvert) + pipeline.add(audioresample) + pipeline.add(opusenc) + pipeline.add(capsfilter) + + alsasrc.link(queue) + queue.link(audioconvert) + audioconvert.link(audioresample) + audioresample.link(opusenc) + opusenc.link(capsfilter) + capsfilter.link(webrtcsink) + + def _on_bus_message(self, bus: Gst.Bus, msg: Gst.Message, loop) -> bool: # type: ignore[no-untyped-def] + t = msg.type + if t == Gst.MessageType.EOS: + self._logger.warning("End-of-stream") + return False + + elif t == Gst.MessageType.ERROR: + err, debug = msg.parse_error() + self._logger.error(f"Error: {err} {debug}") + return False + + else: + # self._logger.warning(f"Unhandled message type: {t}") + pass + + return True + + def start(self) -> None: + """Start the WebRTC pipeline.""" + self._logger.debug("Starting WebRTC") + self._pipeline_sender.set_state(Gst.State.PLAYING) + self._pipeline_receiver.set_state(Gst.State.PLAYING) + + def pause(self) -> None: + """Pause the WebRTC pipeline.""" + self._logger.debug("Pausing WebRTC") + self._pipeline_sender.set_state(Gst.State.PAUSED) + self._pipeline_receiver.set_state(Gst.State.PAUSED) + + def stop(self) -> None: + """Stop the WebRTC pipeline.""" + self._logger.debug("Stopping WebRTC") + + self._pipeline_sender.set_state(Gst.State.NULL) + self._pipeline_receiver.set_state(Gst.State.NULL) + + +if __name__ == "__main__": + import time + + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + ) + + webrtc = GstWebRTC(log_level="DEBUG") + webrtc.start() + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + logging.info("User interrupted") + finally: + webrtc.stop() diff --git a/reachy_mini/src/reachy_mini/motion/__init__.py b/reachy_mini/src/reachy_mini/motion/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..79c18705f8b1f39b91c5e70d8a3e4996c42298c4 --- /dev/null +++ b/reachy_mini/src/reachy_mini/motion/__init__.py @@ -0,0 +1,4 @@ +"""Motion module for Reachy Mini. + +This module contains both utilities to create and play moves, as well as utilities to download datasets of recorded moves. +""" diff --git a/reachy_mini/src/reachy_mini/motion/goto.py b/reachy_mini/src/reachy_mini/motion/goto.py new file mode 100644 index 0000000000000000000000000000000000000000..ddb9e5cb721f940f5d40ef27fc430d3728f7499a --- /dev/null +++ b/reachy_mini/src/reachy_mini/motion/goto.py @@ -0,0 +1,71 @@ +"""A goto move to a target head pose and/or antennas position.""" + +import numpy as np +import numpy.typing as npt + +from reachy_mini.utils.interpolation import ( + InterpolationTechnique, + linear_pose_interpolation, + time_trajectory, +) + +from .move import Move + + +class GotoMove(Move): + """A goto move to a target head pose and/or antennas position.""" + + def __init__( + self, + start_head_pose: npt.NDArray[np.float64], + target_head_pose: npt.NDArray[np.float64] | None, + start_antennas: npt.NDArray[np.float64], + target_antennas: npt.NDArray[np.float64] | None, + start_body_yaw: float, + target_body_yaw: float | None, + duration: float, + method: InterpolationTechnique, + ): + """Set up the goto move.""" + self.start_head_pose = start_head_pose + self.target_head_pose = ( + target_head_pose if target_head_pose is not None else start_head_pose + ) + self.start_antennas = start_antennas + self.target_antennas = ( + target_antennas if target_antennas is not None else start_antennas + ) + self.start_body_yaw = start_body_yaw + self.target_body_yaw = ( + target_body_yaw if target_body_yaw is not None else start_body_yaw + ) + + self._duration = duration + self.method = method + + @property + def duration(self) -> float: + """Duration of the goto in seconds.""" + return self._duration + + def evaluate( + self, t: float + ) -> tuple[ + npt.NDArray[np.float64] | None, npt.NDArray[np.float64] | None, float | None + ]: + """Evaluate the goto at time t.""" + interp_time = time_trajectory(t / self.duration, method=self.method) + + interp_head_pose = linear_pose_interpolation( + self.start_head_pose, self.target_head_pose, interp_time + ) + interp_antennas_joint = ( + self.start_antennas + + (self.target_antennas - self.start_antennas) * interp_time + ) + interp_body_yaw_joint = ( + self.start_body_yaw + + (self.target_body_yaw - self.start_body_yaw) * interp_time + ) + + return interp_head_pose, interp_antennas_joint, interp_body_yaw_joint diff --git a/reachy_mini/src/reachy_mini/motion/move.py b/reachy_mini/src/reachy_mini/motion/move.py new file mode 100644 index 0000000000000000000000000000000000000000..f6481384afcd19b100a66d4173c358eb9046be33 --- /dev/null +++ b/reachy_mini/src/reachy_mini/motion/move.py @@ -0,0 +1,36 @@ +"""Module for defining motion moves on the ReachyMini robot.""" + +from abc import ABC, abstractmethod + +import numpy as np +import numpy.typing as npt + + +class Move(ABC): + """Abstract base class for defining a move on the ReachyMini robot.""" + + @property + @abstractmethod + def duration(self) -> float: + """Duration of the move in seconds.""" + pass + + @abstractmethod + def evaluate( + self, + t: float, + ) -> tuple[ + npt.NDArray[np.float64] | None, npt.NDArray[np.float64] | None, float | None + ]: + """Evaluate the move at time t, typically called at a high-frequency (eg. 100Hz). + + Arguments: + t: The time at which to evaluate the move (in seconds). It will always be between 0 and duration. + + Returns: + head: The head position (4x4 homogeneous matrix). + antennas: The antennas positions (rad). + body_yaw: The body yaw angle (rad). + + """ + pass diff --git a/reachy_mini/src/reachy_mini/motion/recorded_move.py b/reachy_mini/src/reachy_mini/motion/recorded_move.py new file mode 100644 index 0000000000000000000000000000000000000000..483040477141a1fc79580eac3a57e9fd86fcb151 --- /dev/null +++ b/reachy_mini/src/reachy_mini/motion/recorded_move.py @@ -0,0 +1,132 @@ +import bisect # noqa: D100 +import json +from glob import glob +from pathlib import Path +from typing import Any, Dict, List + +import numpy as np +import numpy.typing as npt +from huggingface_hub import snapshot_download + +from reachy_mini.motion.move import Move +from reachy_mini.utils.interpolation import linear_pose_interpolation + + +def lerp(v0: float, v1: float, alpha: float) -> float: + """Linear interpolation between two values.""" + return v0 + alpha * (v1 - v0) + + +class RecordedMove(Move): + """Represent a recorded move.""" + + def __init__(self, move: Dict[str, Any]) -> None: + """Initialize RecordedMove.""" + self.move = move + + self.description: str = self.move["description"] + self.timestamps: List[float] = self.move["time"] + self.trajectory: List[Dict[str, List[List[float]] | List[float] | float]] = ( + self.move["set_target_data"] + ) + + self.dt: float = (self.timestamps[-1] - self.timestamps[0]) / len( + self.timestamps + ) + + @property + def duration(self) -> float: + """Get the duration of the recorded move.""" + return len(self.trajectory) * self.dt + + def evaluate( + self, t: float + ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64], float]: + """Evaluate the move at time t. + + Returns: + head: The head position (4x4 homogeneous matrix). + antennas: The antennas positions (rad). + body_yaw: The body yaw angle (rad). + + """ + # Under is Remi's emotions code, adapted + if t >= self.timestamps[-1]: + raise Exception("Tried to evaluate recorded move beyond its duration.") + + # Locate the right interval in the recorded time array. + # 'index' is the insertion point which gives us the next timestamp. + index = bisect.bisect_right(self.timestamps, t) + # print(f"index: {index}, expected index: {t / self.dt:.0f}") + idx_prev = index - 1 if index > 0 else 0 + idx_next = index if index < len(self.timestamps) else idx_prev + + t_prev = self.timestamps[idx_prev] + t_next = self.timestamps[idx_next] + + # Avoid division by zero (if by any chance two timestamps are identical). + if t_next == t_prev: + alpha = 0.0 + else: + alpha = (t - t_prev) / (t_next - t_prev) + + head_prev = np.array(self.trajectory[idx_prev]["head"], dtype=np.float64) + head_next = np.array(self.trajectory[idx_next]["head"], dtype=np.float64) + antennas_prev: List[float] = self.trajectory[idx_prev]["antennas"] # type: ignore[assignment] + antennas_next: List[float] = self.trajectory[idx_next]["antennas"] # type: ignore[assignment] + body_yaw_prev: float = self.trajectory[idx_prev].get("body_yaw", 0.0) # type: ignore[assignment] + body_yaw_next: float = self.trajectory[idx_next].get("body_yaw", 0.0) # type: ignore[assignment] + # check_collision = self.trajectory[idx_prev].get("check_collision", False) + + # Interpolate to infer a better position at the current time. + # Joint interpolations are easy: + + antennas_joints = np.array( + [ + lerp(pos_prev, pos_next, alpha) + for pos_prev, pos_next in zip(antennas_prev, antennas_next) + ], + dtype=np.float64, + ) + + body_yaw = lerp(body_yaw_prev, body_yaw_next, alpha) + + # Head position interpolation is more complex: + head_pose = linear_pose_interpolation(head_prev, head_next, alpha) + + return head_pose, antennas_joints, body_yaw + + +class RecordedMoves: + """Load a library of recorded moves from a HuggingFace dataset.""" + + def __init__(self, hf_dataset_name: str): + """Initialize RecordedMoves.""" + self.hf_dataset_name = hf_dataset_name + self.local_path = snapshot_download(self.hf_dataset_name, repo_type="dataset") + self.moves: Dict[str, Any] = {} + + self.process() + + def process(self) -> None: + """Populate recorded moves and sounds.""" + move_paths_tmp = glob(f"{self.local_path}/*.json") + move_paths = [Path(move_path) for move_path in move_paths_tmp] + for move_path in move_paths: + move_name = move_path.stem + + move = json.load(open(move_path, "r")) + self.moves[move_name] = move + + def get(self, move_name: str) -> RecordedMove: + """Get a recorded move by name.""" + if move_name not in self.moves: + raise ValueError( + f"Move {move_name} not found in recorded moves library {self.hf_dataset_name}" + ) + + return RecordedMove(self.moves[move_name]) + + def list_moves(self) -> List[str]: + """List all moves in the loaded library.""" + return list(self.moves.keys()) diff --git a/reachy_mini/src/reachy_mini/reachy_mini.py b/reachy_mini/src/reachy_mini/reachy_mini.py new file mode 100644 index 0000000000000000000000000000000000000000..90293e57f7f177d9b20af53b89db5c1b6dfd4c10 --- /dev/null +++ b/reachy_mini/src/reachy_mini/reachy_mini.py @@ -0,0 +1,739 @@ +"""Reachy Mini class for controlling a simulated or real Reachy Mini robot. + +This class provides methods to control the head and antennas of the Reachy Mini robot, +set their target positions, and perform various behaviors such as waking up and going to sleep. + +It also includes methods for multimedia interactions like playing sounds and looking at specific points in the image frame or world coordinates. +""" + +import asyncio +import json +import logging +import time +from typing import Dict, List, Optional, Union + +import cv2 +import numpy as np +import numpy.typing as npt +from asgiref.sync import async_to_sync +from scipy.spatial.transform import Rotation as R + +from reachy_mini.daemon.utils import daemon_check +from reachy_mini.io.protocol import GotoTaskRequest +from reachy_mini.io.zenoh_client import ZenohClient +from reachy_mini.media.media_manager import MediaBackend, MediaManager +from reachy_mini.motion.move import Move +from reachy_mini.utils.interpolation import InterpolationTechnique, minimum_jerk + +# Behavior definitions +INIT_HEAD_POSE = np.eye(4) + +SLEEP_HEAD_JOINT_POSITIONS = [ + 0, + -0.9848156658225817, + 1.2624661884298831, + -0.24390294527381684, + 0.20555342557667577, + -1.2363885150358267, + 1.0032234352772091, +] + + +SLEEP_ANTENNAS_JOINT_POSITIONS = [-3.05, 3.05] +SLEEP_HEAD_POSE = np.array( + [ + [0.911, 0.004, 0.413, -0.021], + [-0.004, 1.0, -0.001, 0.001], + [-0.413, -0.001, 0.911, -0.044], + [0.0, 0.0, 0.0, 1.0], + ] +) + + +class ReachyMini: + """Reachy Mini class for controlling a simulated or real Reachy Mini robot. + + Args: + localhost_only (bool): If True, will only connect to localhost daemons, defaults to True. + spawn_daemon (bool): If True, will spawn a daemon to control the robot, defaults to False. + use_sim (bool): If True and spawn_daemon is True, will spawn a simulated robot, defaults to True. + + """ + + def __init__( + self, + localhost_only: bool = True, + spawn_daemon: bool = False, + use_sim: bool = False, + timeout: float = 5.0, + automatic_body_yaw: bool = True, + log_level: str = "INFO", + media_backend: str = "default", + ) -> None: + """Initialize the Reachy Mini robot. + + Args: + localhost_only (bool): If True, will only connect to localhost daemons, defaults to True. + spawn_daemon (bool): If True, will spawn a daemon to control the robot, defaults to False. + use_sim (bool): If True and spawn_daemon is True, will spawn a simulated robot, defaults to True. + timeout (float): Timeout for the client connection, defaults to 5.0 seconds. + automatic_body_yaw (bool): If True, the body yaw will be used to compute the IK and FK. Default is False. + log_level (str): Logging level, defaults to "INFO". + media_backend (str): Media backend to use, either "default" (OpenCV) or "gstreamer", defaults to "default". + + It will try to connect to the daemon, and if it fails, it will raise an exception. + + """ + self.logger = logging.getLogger(__name__) + self.logger.setLevel(log_level) + daemon_check(spawn_daemon, use_sim) + self.client = ZenohClient(localhost_only) + self.client.wait_for_connection(timeout=timeout) + self.set_automatic_body_yaw(automatic_body_yaw) + self._last_head_pose: Optional[npt.NDArray[np.float64]] = None + self.is_recording = False + + self.T_head_cam = np.eye(4) + self.T_head_cam[:3, 3][:] = [0.0437, 0, 0.0512] + self.T_head_cam[:3, :3] = np.array( + [ + [0, 0, 1], + [-1, 0, 0], + [0, -1, 0], + ] + ) + + self.media_manager = self._configure_mediamanager(media_backend, log_level) + + def __del__(self) -> None: + """Destroy the Reachy Mini instance. + + The client is disconnected explicitly to avoid a thread pending issue. + + """ + self.client.disconnect() + + def __enter__(self) -> "ReachyMini": + """Context manager entry point for Reachy Mini.""" + return self + + def __exit__(self, exc_type, exc_value, traceback) -> None: # type: ignore [no-untyped-def] + """Context manager exit point for Reachy Mini.""" + self.media_manager.close() + self.client.disconnect() + + @property + def media(self) -> MediaManager: + """Expose the MediaManager instance used by ReachyMini.""" + return self.media_manager + + def _configure_mediamanager( + self, media_backend: str, log_level: str + ) -> MediaManager: + if ( + self.client.get_status()["wireless_version"] + and media_backend != "gstreamer" + ): + self.logger.warning( + "Wireless version detected, media backend should be set to 'gstreamer'. Reverting to no_media" + ) + media_backend = "no_media" + + mbackend = MediaBackend.DEFAULT + match media_backend.lower(): + case "gstreamer": + if self.client.get_status()["wireless_version"]: + mbackend = MediaBackend.WEBRTC + else: + mbackend = MediaBackend.GSTREAMER + case "default": + mbackend = MediaBackend.DEFAULT + case "no_media": + mbackend = MediaBackend.NO_MEDIA + case "default_no_video": + mbackend = MediaBackend.DEFAULT_NO_VIDEO + case _: + raise ValueError( + f"Invalid media_backend '{media_backend}'. Supported values are 'default', 'gstreamer', 'no_media', 'default_no_video', and 'webrtc'." + ) + + return MediaManager( + use_sim=self.client.get_status()["simulation_enabled"], + backend=mbackend, + log_level=log_level, + signalling_host=self.client.get_status()["wlan_ip"], + ) + + def set_target( + self, + head: Optional[npt.NDArray[np.float64]] = None, # 4x4 pose matrix + antennas: Optional[ + Union[npt.NDArray[np.float64], List[float]] + ] = None, # [right_angle, left_angle] (in rads) + body_yaw: Optional[float] = None, # Body yaw angle in radians + ) -> None: + """Set the target pose of the head and/or the target position of the antennas. + + Args: + head (Optional[np.ndarray]): 4x4 pose matrix representing the head pose. + antennas (Optional[Union[np.ndarray, List[float]]]): 1D array with two elements representing the angles of the antennas in radians. + body_yaw (Optional[float]): Body yaw angle in radians. + + Raises: + ValueError: If neither head nor antennas are provided, or if the shape of head is not (4, 4), or if antennas is not a 1D array with two elements. + + """ + if head is None and antennas is None and body_yaw is None: + raise ValueError( + "At least one of head, antennas or body_yaw must be provided." + ) + + if head is not None and not head.shape == (4, 4): + raise ValueError(f"Head pose must be a 4x4 matrix, got shape {head.shape}.") + + if antennas is not None and not len(antennas) == 2: + raise ValueError( + "Antennas must be a list or 1D np array with two elements." + ) + + if body_yaw is not None and not isinstance(body_yaw, (int, float)): + raise ValueError("body_yaw must be a float.") + + if head is not None: + self.set_target_head_pose(head) + + if antennas is not None: + self.set_target_antenna_joint_positions(list(antennas)) + # self._set_joint_positions( + # antennas_joint_positions=list(antennas), + # ) + + if body_yaw is not None: + self.set_target_body_yaw(body_yaw) + + self._last_head_pose = head + + record: Dict[str, float | List[float] | List[List[float]]] = { + "time": time.time(), + "body_yaw": body_yaw if body_yaw is not None else 0.0, + } + if head is not None: + record["head"] = head.tolist() + if antennas is not None: + record["antennas"] = list(antennas) + if body_yaw is not None: + record["body_yaw"] = body_yaw + self._set_record_data(record) + + def goto_target( + self, + head: Optional[npt.NDArray[np.float64]] = None, # 4x4 pose matrix + antennas: Optional[ + Union[npt.NDArray[np.float64], List[float]] + ] = None, # [right_angle, left_angle] (in rads) + duration: float = 0.5, # Duration in seconds for the movement, default is 0.5 seconds. + method: InterpolationTechnique = InterpolationTechnique.MIN_JERK, # can be "linear", "minjerk", "ease" or "cartoon", default is "minjerk") + body_yaw: float | None = 0.0, # Body yaw angle in radians + ) -> None: + """Go to a target head pose and/or antennas position using task space interpolation, in "duration" seconds. + + Args: + head (Optional[np.ndarray]): 4x4 pose matrix representing the target head pose. + antennas (Optional[Union[np.ndarray, List[float]]]): 1D array with two elements representing the angles of the antennas in radians. + duration (float): Duration of the movement in seconds. + method (InterpolationTechnique): Interpolation method to use ("linear", "minjerk", "ease", "cartoon"). Default is "minjerk". + body_yaw (float | None): Body yaw angle in radians. Use None to keep the current yaw. + + Raises: + ValueError: If neither head nor antennas are provided, or if duration is not positive. + + """ + if head is None and antennas is None and body_yaw is None: + raise ValueError( + "At least one of head, antennas or body_yaw must be provided." + ) + + if duration <= 0.0: + raise ValueError( + "Duration must be positive and non-zero. Use set_target() for immediate position setting." + ) + + req = GotoTaskRequest( + head=np.array(head, dtype=np.float64).flatten().tolist() + if head is not None + else None, + antennas=np.array(antennas, dtype=np.float64).flatten().tolist() + if antennas is not None + else None, + duration=duration, + method=method, + body_yaw=body_yaw, + ) + + task_uid = self.client.send_task_request(req) + self.client.wait_for_task_completion(task_uid, timeout=duration + 1.0) + + def wake_up(self) -> None: + """Wake up the robot - go to the initial head position and play the wake up emote and sound.""" + self.goto_target(INIT_HEAD_POSE, antennas=[0.0, 0.0], duration=2) + time.sleep(0.1) + + # Toudoum + self.media.play_sound("wake_up.wav") + + # Roll 20° to the left + pose = INIT_HEAD_POSE.copy() + pose[:3, :3] = R.from_euler("xyz", [20, 0, 0], degrees=True).as_matrix() + self.goto_target(pose, duration=0.2) + + # Go back to the initial position + self.goto_target(INIT_HEAD_POSE, duration=0.2) + + def goto_sleep(self) -> None: + """Put the robot to sleep by moving the head and antennas to a predefined sleep position.""" + # Check if we are too far from the initial position + # Move to the initial position if necessary + current_positions, _ = self.get_current_joint_positions() + # init_positions = self.head_kinematics.ik(INIT_HEAD_POSE) + # Todo : get init position from the daemon? + init_positions = [ + 6.959852054044218e-07, + 0.5251518455536499, + -0.668710345667336, + 0.6067086443974802, + -0.606711497194891, + 0.6687148024583701, + -0.5251586523105128, + ] + dist = np.linalg.norm(np.array(current_positions) - np.array(init_positions)) + if dist > 0.2: + self.goto_target(INIT_HEAD_POSE, antennas=[0.0, 0.0], duration=1) + time.sleep(0.2) + + # Pfiou + self.media.play_sound("go_sleep.wav") + + # # Move to the sleep position + self.goto_target( + SLEEP_HEAD_POSE, antennas=SLEEP_ANTENNAS_JOINT_POSITIONS, duration=2 + ) + + self._last_head_pose = SLEEP_HEAD_POSE + time.sleep(2) + + def look_at_image( + self, u: int, v: int, duration: float = 1.0, perform_movement: bool = True + ) -> npt.NDArray[np.float64]: + """Make the robot head look at a point defined by a pixel position (u,v). + + # TODO image of reachy mini coordinate system + + Args: + u (int): Horizontal coordinate in image frame. + v (int): Vertical coordinate in image frame. + duration (float): Duration of the movement in seconds. If 0, the head will snap to the position immediately. + perform_movement (bool): If True, perform the movement. If False, only calculate and return the pose. + + Returns: + np.ndarray: The calculated head pose as a 4x4 matrix. + + Raises: + ValueError: If duration is negative. + + """ + if self.media_manager.camera is None: + raise RuntimeError("Camera is not initialized.") + + # TODO this is false for the raspicam for now + assert 0 < u < self.media_manager.camera.resolution[0], ( + f"u must be in [0, {self.media_manager.camera.resolution[0]}], got {u}." + ) + assert 0 < v < self.media_manager.camera.resolution[1], ( + f"v must be in [0, {self.media_manager.camera.resolution[1]}], got {v}." + ) + + if duration < 0: + raise ValueError("Duration can't be negative.") + + if self.media.camera is None or self.media.camera.camera_specs is None: + raise RuntimeError("Camera specs not set.") + + points = np.array([[[u, v]]], dtype=np.float32) + x_n, y_n = cv2.undistortPoints( + points, + self.media.camera.K, # type: ignore + self.media.camera.D, # type: ignore + )[0, 0] + + ray_cam = np.array([x_n, y_n, 1.0]) + ray_cam /= np.linalg.norm(ray_cam) + + T_world_head = self.get_current_head_pose() + T_world_cam = T_world_head @ self.T_head_cam + + R_wc = T_world_cam[:3, :3] + t_wc = T_world_cam[:3, 3] + + ray_world = R_wc @ ray_cam + + P_world = t_wc + ray_world + + return self.look_at_world( + x=P_world[0], + y=P_world[1], + z=P_world[2], + duration=duration, + perform_movement=perform_movement, + ) + + def look_at_world( + self, + x: float, + y: float, + z: float, + duration: float = 1.0, + perform_movement: bool = True, + ) -> npt.NDArray[np.float64]: + """Look at a specific point in 3D space in Reachy Mini's reference frame. + + TODO include image of reachy mini coordinate system + + Args: + x (float): X coordinate in meters. + y (float): Y coordinate in meters. + z (float): Z coordinate in meters. + duration (float): Duration of the movement in seconds. If 0, the head will snap to the position immediately. + perform_movement (bool): If True, perform the movement. If False, only calculate and return the pose. + + Returns: + np.ndarray: The calculated head pose as a 4x4 matrix. + + Raises: + ValueError: If duration is negative. + + """ + if duration < 0: + raise ValueError("Duration can't be negative.") + + # Head is at the origin, so vector from head to target position is directly the target position + # TODO FIX : Actually, the head frame is not the origin frame wrt the kinematics. Close enough for now. + target_position = np.array([x, y, z]) + target_vector = target_position / np.linalg.norm( + target_position + ) # normalize the vector + + # head_pointing straight vector + straight_head_vector = np.array([1, 0, 0]) + + # Calculate the rotation needed to align the head with the target vector + v1 = straight_head_vector + v2 = target_vector + axis = np.cross(v1, v2) + axis_norm = np.linalg.norm(axis) + if axis_norm < 1e-8: + # Vectors are (almost) parallel + if np.dot(v1, v2) > 0: + rot_mat = np.eye(3) + else: + # Opposite direction: rotate 180° around any perpendicular axis + perp = np.array([0, 1, 0]) if abs(v1[0]) < 0.9 else np.array([0, 0, 1]) + axis = np.cross(v1, perp) + axis /= np.linalg.norm(axis) + rot_mat = R.from_rotvec(np.pi * axis).as_matrix() + else: + axis = axis / axis_norm + angle = np.arccos(np.clip(np.dot(v1, v2), -1.0, 1.0)) + rotation_vector = angle * axis + rot_mat = R.from_rotvec(rotation_vector).as_matrix() + + target_head_pose = np.eye(4) + target_head_pose[:3, :3] = rot_mat + + # If perform_movement is True, execute the movement + if perform_movement: + # If duration is specified, use the goto_target method to move smoothly + # Otherwise, set the position immediately + if duration > 0: + self.goto_target(target_head_pose, duration=duration) + else: + self.set_target(target_head_pose) + + return target_head_pose + + def _goto_joint_positions( + self, + head_joint_positions: Optional[ + List[float] + ] = None, # [yaw, stewart_platform x 6] length 7 + antennas_joint_positions: Optional[ + List[float] + ] = None, # [right_angle, left_angle] length 2 + duration: float = 0.5, # Duration in seconds for the movement + ) -> None: + """Go to a target head joint positions and/or antennas joint positions using joint space interpolation, in "duration" seconds. + + [Internal] Go to a target head joint positions and/or antennas joint positions using joint space interpolation, in "duration" seconds. + + Args: + head_joint_positions (Optional[List[float]]): List of head joint positions in radians (length 7). + antennas_joint_positions (Optional[List[float]]): List of antennas joint positions in radians (length 2). + duration (float): Duration of the movement in seconds. Default is 0.5 seconds. + + Raises: + ValueError: If neither head_joint_positions nor antennas_joint_positions are provided, or if duration is not positive. + + """ + if duration <= 0.0: + raise ValueError( + "Duration must be positive and non-zero. Use set_target() for immediate position setting." + ) + + cur_head, cur_antennas = self.get_current_joint_positions() + current = cur_head + cur_antennas + + target = [] + if head_joint_positions is not None: + target.extend(head_joint_positions) + else: + target.extend(cur_head) + if antennas_joint_positions is not None: + target.extend(antennas_joint_positions) + else: + target.extend(cur_antennas) + + traj = minimum_jerk(np.array(current), np.array(target), duration) + + t0 = time.time() + while time.time() - t0 < duration: + t = time.time() - t0 + angles = traj(t) + + head_joint = angles[:7] # First 7 angles for the head + antennas_joint = angles[7:] + + self._set_joint_positions(list(head_joint), list(antennas_joint)) + time.sleep(0.01) + + def get_current_joint_positions(self) -> tuple[list[float], list[float]]: + """Get the current joint positions of the head and antennas. + + Get the current joint positions of the head and antennas (in rad) + + Returns: + tuple: A tuple containing two lists: + - List of head joint positions (rad) (length 7). + - List of antennas joint positions (rad) (length 2). + + """ + return self.client.get_current_joints() + + def get_present_antenna_joint_positions(self) -> list[float]: + """Get the present joint positions of the antennas. + + Get the present joint positions of the antennas (in rad) + + Returns: + list: A list of antennas joint positions (rad) (length 2). + + """ + return self.get_current_joint_positions()[1] + + def get_current_head_pose(self) -> npt.NDArray[np.float64]: + """Get the current head pose as a 4x4 matrix. + + Get the current head pose as a 4x4 matrix. + + Returns: + np.ndarray: A 4x4 matrix representing the current head pose. + + """ + return self.client.get_current_head_pose() + + def _set_joint_positions( + self, + head_joint_positions: list[float] | None = None, + antennas_joint_positions: list[float] | None = None, + ) -> None: + """Set the joint positions of the head and/or antennas. + + [Internal] Set the joint positions of the head and/or antennas. + + Args: + head_joint_positions (Optional[List[float]]): List of head joint positions in radians (length 7). + antennas_joint_positions (Optional[List[float]]): List of antennas joint positions in radians (length 2). + record (Optional[Dict]): If provided, the command will be logged with the given record data. + + """ + cmd = {} + + if head_joint_positions is not None: + assert len(head_joint_positions) == 7, ( + f"Head joint positions must have length 7, got {head_joint_positions}." + ) + cmd["head_joint_positions"] = list(head_joint_positions) + + if antennas_joint_positions is not None: + assert len(antennas_joint_positions) == 2, "Antennas must have length 2." + cmd["antennas_joint_positions"] = list(antennas_joint_positions) + + if not cmd: + raise ValueError( + "At least one of head_joint_positions or antennas must be provided." + ) + + self.client.send_command(json.dumps(cmd)) + + def set_target_head_pose(self, pose: npt.NDArray[np.float64]) -> None: + """Set the head pose to a specific 4x4 matrix. + + Args: + pose (np.ndarray): A 4x4 matrix representing the desired head pose. + body_yaw (float): The yaw angle of the body, used to adjust the head pose. + + Raises: + ValueError: If the shape of the pose is not (4, 4). + + """ + cmd = {} + + if pose is not None: + assert pose.shape == (4, 4), ( + f"Head pose should be a 4x4 matrix, got {pose.shape}." + ) + cmd["head_pose"] = pose.tolist() + else: + raise ValueError("Pose must be provided as a 4x4 matrix.") + + self.client.send_command(json.dumps(cmd)) + + def set_target_antenna_joint_positions(self, antennas: List[float]) -> None: + """Set the target joint positions of the antennas.""" + cmd = {"antennas_joint_positions": antennas} + self.client.send_command(json.dumps(cmd)) + + def set_target_body_yaw(self, body_yaw: float) -> None: + """Set the target body yaw. + + Args: + body_yaw (float): The yaw angle of the body in radians. + + """ + cmd = {"body_yaw": body_yaw} + self.client.send_command(json.dumps(cmd)) + + def start_recording(self) -> None: + """Start recording data.""" + self.client.send_command(json.dumps({"start_recording": True})) + self.is_recording = True + + def stop_recording( + self, + ) -> Optional[List[Dict[str, float | List[float] | List[List[float]]]]]: + """Stop recording data and return the recorded data.""" + self.client.send_command(json.dumps({"stop_recording": True})) + self.is_recording = False + if not self.client.wait_for_recorded_data(timeout=5): + raise RuntimeError("Daemon did not provide recorded data in time!") + recorded_data = self.client.get_recorded_data(wait=False) + + return recorded_data + + def _set_record_data( + self, record: Dict[str, float | List[float] | List[List[float]]] + ) -> None: + """Set the record data to be logged by the backend. + + Args: + record (Dict): The record data to be logged. + + """ + if not isinstance(record, dict): + raise ValueError("Record must be a dictionary.") + + # Send the record data to the backend + self.client.send_command(json.dumps({"set_target_record": record})) + + def enable_motors(self, ids: List[str] | None = None) -> None: + """Enable the motors. + + Args: + ids (List[str] | None): List of motor names to enable. If None, all motors will be enabled. + + """ + self._set_torque(True, ids=ids) + + def disable_motors(self, ids: List[str] | None = None) -> None: + """Disable the motors. + + Args: + ids (List[str] | None): List of motor names to disable. If None, all motors will be disabled. + + """ + self._set_torque(False, ids=ids) + + def _set_torque(self, on: bool, ids: List[str] | None = None) -> None: + self.client.send_command(json.dumps({"torque": on, "ids": ids})) + + def enable_gravity_compensation(self) -> None: + """Enable gravity compensation for the head motors.""" + self.client.send_command(json.dumps({"gravity_compensation": True})) + + def disable_gravity_compensation(self) -> None: + """Disable gravity compensation for the head motors.""" + self.client.send_command(json.dumps({"gravity_compensation": False})) + + def set_automatic_body_yaw(self, body_yaw: float) -> None: + """Set the automatic body yaw. + + Args: + body_yaw (float): The yaw angle of the body in radians. + + """ + self.client.send_command(json.dumps({"automatic_body_yaw": body_yaw})) + + async def async_play_move( + self, + move: Move, + play_frequency: float = 100.0, + initial_goto_duration: float = 0.0, + ) -> None: + """Asynchronously play a Move. + + Args: + move (Move): The Move object to be played. + play_frequency (float): The frequency at which to evaluate the move (in Hz). + initial_goto_duration (float): Duration for the initial goto to the starting position of the move (in seconds). If 0, no initial goto is performed. + + """ + if initial_goto_duration > 0.0: + start_head_pose, start_antennas_positions, start_body_yaw = move.evaluate( + 0.0 + ) + self.goto_target( + head=start_head_pose, + antennas=start_antennas_positions, + duration=initial_goto_duration, + body_yaw=start_body_yaw, + ) + + sleep_period = 1.0 / play_frequency + + t0 = time.time() + while time.time() - t0 < move.duration: + t = min(time.time() - t0, move.duration - 1e-2) + + head, antennas, body_yaw = move.evaluate(t) + if head is not None: + self.set_target_head_pose(head) + if body_yaw is not None: + self.set_target_body_yaw(body_yaw) + if antennas is not None: + self.set_target_antenna_joint_positions(list(antennas)) + + elapsed = time.time() - t0 - t + if elapsed < sleep_period: + await asyncio.sleep(sleep_period - elapsed) + else: + await asyncio.sleep(0.001) + + play_move = async_to_sync(async_play_move) diff --git a/reachy_mini/src/reachy_mini/utils/__init__.py b/reachy_mini/src/reachy_mini/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1166e2b99f48c75aa932fa76d9eae93593634f13 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/__init__.py @@ -0,0 +1,46 @@ +"""Utility functions for Reachy Mini. + +These functions provide various utilities such as creating head poses, performing minimum jerk interpolation, +checking if the Reachy Mini daemon is running, and performing linear pose interpolation. + +""" + +import numpy as np +import numpy.typing as npt +from scipy.spatial.transform import Rotation as R + + +def create_head_pose( + x: float = 0, + y: float = 0, + z: float = 0, + roll: float = 0, + pitch: float = 0, + yaw: float = 0, + mm: bool = False, + degrees: bool = True, +) -> npt.NDArray[np.float64]: + """Create a homogeneous transformation matrix representing a pose in 6D space (position and orientation). + + Args: + x (float): X coordinate of the position. + y (float): Y coordinate of the position. + z (float): Z coordinate of the position. + roll (float): Roll angle + pitch (float): Pitch angle + yaw (float): Yaw angle + mm (bool): If True, convert position from millimeters to meters. + degrees (bool): If True, interpret roll, pitch, and yaw as degrees; otherwise as radians. + + Returns: + np.ndarray: A 4x4 homogeneous transformation matrix representing the pose. + + """ + pose = np.eye(4) + rot = R.from_euler("xyz", [roll, pitch, yaw], degrees=degrees).as_matrix() + pose[:3, :3] = rot + pose[:, 3] = [x, y, z, 1] + if mm: + pose[:3, 3] /= 1000 + + return pose diff --git a/reachy_mini/src/reachy_mini/utils/constants.py b/reachy_mini/src/reachy_mini/utils/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..ce102daf8c50cbe908dce6fd110997deb8a90554 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/constants.py @@ -0,0 +1,9 @@ +"""Utility constants for the reachy_mini package.""" + +from importlib.resources import files + +import reachy_mini + +URDF_ROOT_PATH: str = str(files(reachy_mini).joinpath("descriptions/reachy_mini/urdf")) +ASSETS_ROOT_PATH: str = str(files(reachy_mini).joinpath("assets/")) +MODELS_ROOT_PATH: str = str(files(reachy_mini).joinpath("assets/models")) diff --git a/reachy_mini/src/reachy_mini/utils/hardware_config/__init__.py b/reachy_mini/src/reachy_mini/utils/hardware_config/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..89a11e958559e3f72f4b4469884b00af9fe5d450 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/hardware_config/__init__.py @@ -0,0 +1 @@ +"""Hardware configuration utilities.""" diff --git a/reachy_mini/src/reachy_mini/utils/hardware_config/parser.py b/reachy_mini/src/reachy_mini/utils/hardware_config/parser.py new file mode 100644 index 0000000000000000000000000000000000000000..e370c9ee12e1c87da10af3b5d5edd52015346127 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/hardware_config/parser.py @@ -0,0 +1,63 @@ +"""Module to parse Reachy Mini hardware configuration from a YAML file.""" + +from dataclasses import dataclass + +import yaml + + +@dataclass +class MotorConfig: + """Motor configuration.""" + + id: int + offset: int + angle_limit_min: int + angle_limit_max: int + return_delay_time: int + shutdown_error: int + pid: tuple[int, int, int] | None = None + + +@dataclass +class SerialConfig: + """Serial configuration.""" + + baudrate: int + + +@dataclass +class ReachyMiniConfig: + """Reachy Mini configuration.""" + + version: str + serial: SerialConfig + motors: dict[str, MotorConfig] + + +def parse_yaml_config(filename: str) -> ReachyMiniConfig: + """Parse the YAML configuration file and return a ReachyMiniConfig.""" + with open(filename, "r") as file: + conf = yaml.load(file, Loader=yaml.FullLoader) + + version = conf["version"] + + motor_ids = {} + for motor in conf["motors"]: + for name, params in motor.items(): + motor_ids[name] = MotorConfig( + id=params["id"], + offset=params["offset"], + angle_limit_min=params["lower_limit"], + angle_limit_max=params["upper_limit"], + return_delay_time=params["return_delay_time"], + shutdown_error=params["shutdown_error"], + pid=params.get("pid"), + ) + + serial = SerialConfig(baudrate=conf["serial"]["baudrate"]) + + return ReachyMiniConfig( + version=version, + serial=serial, + motors=motor_ids, + ) diff --git a/reachy_mini/src/reachy_mini/utils/interpolation.py b/reachy_mini/src/reachy_mini/utils/interpolation.py new file mode 100644 index 0000000000000000000000000000000000000000..1c39c031e5ddb9c00d6c7fb0003ce3cf3bd41457 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/interpolation.py @@ -0,0 +1,227 @@ +"""Interpolation utilities for Reachy Mini.""" + +from enum import Enum +from typing import Callable, Optional, Tuple + +import numpy as np +import numpy.typing as npt +from scipy.spatial.transform import Rotation as R + +InterpolationFunc = Callable[[float], npt.NDArray[np.float64]] + + +def minimum_jerk( + starting_position: npt.NDArray[np.float64], + goal_position: npt.NDArray[np.float64], + duration: float, + starting_velocity: Optional[npt.NDArray[np.float64]] = None, + starting_acceleration: Optional[npt.NDArray[np.float64]] = None, + final_velocity: Optional[npt.NDArray[np.float64]] = None, + final_acceleration: Optional[npt.NDArray[np.float64]] = None, +) -> InterpolationFunc: + """Compute the mimimum jerk interpolation function from starting position to goal position.""" + if starting_velocity is None: + starting_velocity = np.zeros(starting_position.shape) + if starting_acceleration is None: + starting_acceleration = np.zeros(starting_position.shape) + if final_velocity is None: + final_velocity = np.zeros(goal_position.shape) + if final_acceleration is None: + final_acceleration = np.zeros(goal_position.shape) + + a0 = starting_position + a1 = starting_velocity + a2 = starting_acceleration / 2 + + d1, d2, d3, d4, d5 = [duration**i for i in range(1, 6)] + + A = np.array(((d3, d4, d5), (3 * d2, 4 * d3, 5 * d4), (6 * d1, 12 * d2, 20 * d3))) + B = np.array( + ( + goal_position - a0 - (a1 * d1) - (a2 * d2), + final_velocity - a1 - (2 * a2 * d1), + final_acceleration - (2 * a2), + ) + ) + X = np.linalg.solve(A, B) + + coeffs = [a0, a1, a2, X[0], X[1], X[2]] + + def f(t: float) -> npt.NDArray[np.float64]: + if t > duration: + return goal_position + return np.sum([c * t**i for i, c in enumerate(coeffs)], axis=0) # type: ignore[no-any-return] + + return f + + +def linear_pose_interpolation( + start_pose: npt.NDArray[np.float64], target_pose: npt.NDArray[np.float64], t: float +) -> npt.NDArray[np.float64]: + """Linearly interpolate between two poses in 6D space.""" + # Extract rotations + rot_start = R.from_matrix(start_pose[:3, :3]) + rot_end = R.from_matrix(target_pose[:3, :3]) + + # Compute relative rotation q_rel such that rot_start * q_rel = rot_end + q_rel = rot_start.inv() * rot_end + # Convert to rotation vector (axis-angle) + rotvec_rel = q_rel.as_rotvec() + # Scale the rotation vector by t (allows t<0 or >1 for overshoot) + rot_interp = (rot_start * R.from_rotvec(rotvec_rel * t)).as_matrix() + + # Extract translations + pos_start = start_pose[:3, 3] + pos_end = target_pose[:3, 3] + # Linear interpolation/extrapolation on translation + pos_interp = pos_start + (pos_end - pos_start) * t + + # Compose homogeneous transformation + interp_pose = np.eye(4) + interp_pose[:3, :3] = rot_interp + interp_pose[:3, 3] = pos_interp + + return interp_pose + + +class InterpolationTechnique(str, Enum): + """Enumeration of interpolation techniques.""" + + LINEAR = "linear" + MIN_JERK = "minjerk" + EASE_IN_OUT = "ease_in_out" + CARTOON = "cartoon" + + +def time_trajectory( + t: float, method: InterpolationTechnique = InterpolationTechnique.MIN_JERK +) -> float: + """Compute the time trajectory value based on the specified interpolation method.""" + if t < 0 or t > 1: + raise ValueError("time value is out of range [0,1]") + + if method == InterpolationTechnique.LINEAR: + return t + + elif method == InterpolationTechnique.MIN_JERK: + return 10 * t**3 - 15 * t**4 + 6 * t**5 + + elif method == InterpolationTechnique.EASE_IN_OUT: + if t < 0.5: + return 2 * t * t + else: + return 1 - ((-2 * t + 2) ** 2) / 2 + + elif method == InterpolationTechnique.CARTOON: + c1 = 1.70158 + c2 = c1 * 1.525 + + if t < 0.5: + # phase in + return ((2 * t) ** 2 * ((c2 + 1) * 2 * t - c2)) / 2 + else: + # phase out + return (((2 * t - 2) ** 2 * ((c2 + 1) * (2 * t - 2) + c2)) + 2) / 2 + + else: + raise ValueError( + "Unknown interpolation method: {} (possible values: {})".format( + method, + list(InterpolationTechnique), + ) + ) + + +def delta_angle_between_mat_rot( + P: npt.NDArray[np.float64], Q: npt.NDArray[np.float64] +) -> float: + """Compute the angle (in radians) between two 3x3 rotation matrices `P` and `Q`. + + This is equivalent to the angular distance in axis-angle space. + It is computed via the trace of the relative rotation matrix. + + References: + - https://math.stackexchange.com/questions/2113634/comparing-two-rotation-matrices + - http://www.boris-belousov.net/2016/12/01/quat-dist/ + + Args: + P: A 3x3 rotation matrix. + Q: Another 3x3 rotation matrix. + + Returns: + The angle in radians between the two rotations. + + """ + R = np.dot(P, Q.T) + tr = (np.trace(R) - 1) / 2 + tr = np.clip(tr, -1.0, 1.0) # Ensure numerical stability + return float(np.arccos(tr)) + + +def distance_between_poses( + pose1: npt.NDArray[np.float64], pose2: npt.NDArray[np.float64] +) -> Tuple[float, float, float]: + """Compute three types of distance between two 4x4 homogeneous transformation matrices. + + The result combines translation (in mm) and rotation (in degrees) using an arbitrary but + emotionally satisfying equivalence: 1 degree ≈ 1 mm. + + Args: + pose1: A 4x4 homogeneous transformation matrix representing the first pose. + pose2: A 4x4 homogeneous transformation matrix representing the second pose. + + Returns: + A tuple of: + - translation distance in meters, + - angular distance in radians, + - unhinged distance in magic-mm (translation in mm + rotation in degrees). + + """ + distance_translation = float(np.linalg.norm(pose1[:3, 3] - pose2[:3, 3])) + distance_angle = delta_angle_between_mat_rot(pose1[:3, :3], pose2[:3, :3]) + unhinged_distance = distance_translation * 1000 + np.rad2deg(distance_angle) + + return distance_translation, distance_angle, unhinged_distance + + +def compose_world_offset( + T_abs: npt.NDArray[np.float64], + T_off_world: npt.NDArray[np.float64], + reorthonormalize: bool = False, +) -> npt.NDArray[np.float64]: + """Compose an absolute world-frame pose with a world-frame offset. + + - translations add in world: t_final = t_abs + t_off + - rotations compose in world: R_final = R_off @ R_abs + This rotates the frame in place (about its own origin) by a rotation + defined in world axes, and shifts it by a world translation. + + Parameters + ---------- + T_abs : (4,4) ndarray + Absolute pose in world frame. + T_off_world : (4,4) ndarray + Offset transform specified in world axes (dx,dy,dz in world; dR about world axes). + reorthonormalize : bool + If True, SVD-orthonormalize the resulting rotation to fight drift. + + Returns + ------- + T_final : (4,4) ndarray + Resulting pose in world frame. + + """ + R_abs, t_abs = T_abs[:3, :3], T_abs[:3, 3] + R_off, t_off = T_off_world[:3, :3], T_off_world[:3, 3] + + R_final = R_off @ R_abs + if reorthonormalize: + U, _, Vt = np.linalg.svd(R_final) + R_final = U @ Vt + + t_final = t_abs + t_off + + T_final = np.eye(4) + T_final[:3, :3] = R_final + T_final[:3, 3] = t_final + return T_final diff --git a/reachy_mini/src/reachy_mini/utils/parse_urdf_for_kinematics.py b/reachy_mini/src/reachy_mini/utils/parse_urdf_for_kinematics.py new file mode 100644 index 0000000000000000000000000000000000000000..8a38883f7871c316be611af2b79d45e90a4fb82c --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/parse_urdf_for_kinematics.py @@ -0,0 +1,110 @@ +"""Generate kinematics data from URDF using Placo as preprocessing. + +The analytical kinematics need information from the URDF. This files computes the information and writes it in a .json file. +""" + +import json +from importlib.resources import files +from typing import Any, Dict + +import numpy as np # noqa: D100 +from placo_utils.tf import tf + +import reachy_mini +from reachy_mini.kinematics.placo_kinematics import PlacoKinematics + + +def get_data() -> Dict[str, Any]: + """Generate the urdf_kinematics.json file.""" + urdf_root_path: str = str( + files(reachy_mini).joinpath("descriptions/reachy_mini/urdf") + ) + + placo_kinematics = PlacoKinematics(urdf_root_path, 0.02) + robot = placo_kinematics.robot + + placo_kinematics.fk(np.array([0.0] * 7), no_iterations=20) + robot.update_kinematics() + + # Measuring lengths for the arm and branch (constants could be used) + T_world_head_home = robot.get_T_world_frame("head").copy() + T_world_1 = robot.get_T_world_frame("stewart_1") + T_world_arm1 = robot.get_T_world_frame("passive_1_link_x") + T_1_arm1 = np.linalg.inv(T_world_1) @ T_world_arm1 + arm_z = T_1_arm1[2, 3] + motor_arm_length = np.linalg.norm(T_1_arm1[:2, 3]) + + T_world_branch1 = robot.get_T_world_frame("closing_1_2") + T_arm1_branch1 = np.linalg.inv(T_world_arm1) @ T_world_branch1 + rod_length = np.linalg.norm(T_arm1_branch1[:3, 3]) + + motors = [ + { + "name": "stewart_1", + "branch_frame": "closing_1_2", + "offset": 0, + "solution": 0, + }, + { + "name": "stewart_2", + "branch_frame": "closing_2_2", + "offset": 0, + "solution": 1, + }, + { + "name": "stewart_3", + "branch_frame": "closing_3_2", + "offset": 0, + "solution": 0, + }, + { + "name": "stewart_4", + "branch_frame": "closing_4_2", + "offset": 0, + "solution": 1, + }, + { + "name": "stewart_5", + "branch_frame": "closing_5_2", + "offset": 0, + "solution": 0, + }, + { + "name": "stewart_6", + "branch_frame": "passive_7_link_y", + "offset": 0, + "solution": 1, + }, + ] + + for motor in motors: + T_world_branch = robot.get_T_world_frame(motor["branch_frame"]) + T_head_branch = np.linalg.inv(T_world_head_home) @ T_world_branch + T_world_motor = robot.get_T_world_frame(motor["name"]) @ tf.translation_matrix( + (0, 0, arm_z) + ) + motor["T_motor_world"] = np.linalg.inv(T_world_motor).tolist() + motor["branch_position"] = T_head_branch[:3, 3].tolist() + motor["limits"] = robot.get_joint_limits(motor["name"]).tolist() + + data = { + "motor_arm_length": motor_arm_length, + "rod_length": rod_length, + "head_z_offset": placo_kinematics.head_z_offset, + "motors": motors, + } + + return data + + +def main() -> None: + """Generate the urdf_kinematics.json file.""" + assets_root_path: str = str(files(reachy_mini).joinpath("assets/")) + data = get_data() + print(assets_root_path + "/" + "kinematics_data.json") + with open(assets_root_path + "/" + "kinematics_data.json", "w") as f: + json.dump(data, f, indent=4) + + +if __name__ == "__main__": + main() diff --git a/reachy_mini/src/reachy_mini/utils/rerun.py b/reachy_mini/src/reachy_mini/utils/rerun.py new file mode 100644 index 0000000000000000000000000000000000000000..eeab8e7ba3c21d63095deb883630ec7f337839ae --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/rerun.py @@ -0,0 +1,320 @@ +"""Rerun logging for Reachy Mini. + +This module provides functionality to log the state of the Reachy Mini robot to Rerun, + a tool for visualizing and debugging robotic systems. + +It includes methods to log joint positions, camera images, and other relevant data. +""" + +import json +import logging +import os +import tempfile +import time +from threading import Event, Thread +from typing import Dict, List, Optional + +import numpy as np +import requests +import rerun as rr +from scipy.spatial.transform import Rotation as R +from urdf_parser_py import urdf + +from reachy_mini.kinematics.placo_kinematics import PlacoKinematics +from reachy_mini.media.media_manager import MediaBackend +from reachy_mini.reachy_mini import ReachyMini + + +class Rerun: + """Rerun logging for Reachy Mini.""" + + def __init__( + self, + reachymini: ReachyMini, + app_id: str = "reachy_mini_rerun", + spawn: bool = True, + ): + """Initialize the Rerun logging for Reachy Mini. + + Args: + reachymini (ReachyMini): The Reachy Mini instance to log. + app_id (str): The application ID for Rerun. Defaults to reachy_mini_daemon. + spawn (bool): If True, spawn the Rerun server. Defaults to True. + + """ + rr.init(app_id, spawn=spawn) + self.app_id = app_id + self._reachymini = reachymini + self.logger = logging.getLogger(__name__) + self.logger.setLevel(reachymini.logger.getEffectiveLevel()) + + self._robot_ip = "localhost" + if self._reachymini.client.get_status()["wireless_version"]: + self._robot_ip = self._reachymini.client.get_status()["wlan_ip"] + + self.recording = rr.get_global_data_recording() + + script_dir = os.path.dirname(os.path.abspath(__file__)) + + urdf_path = os.path.join( + script_dir, "../descriptions/reachy_mini/urdf/robot_no_collision.urdf" + ) + asset_path = os.path.join(script_dir, "../descriptions/reachy_mini/urdf") + + fixed_urdf = self.set_absolute_path_to_urdf(urdf_path, asset_path) + self.logger.debug( + f"Using URDF file: {fixed_urdf} with absolute paths for Rerun." + ) + + self.head_kinematics = PlacoKinematics(fixed_urdf) + + self.urdf_model = urdf.URDF.from_xml_file(fixed_urdf) + self._joints_by_name: Dict[str, urdf.Joint] = { + joint.name: joint for joint in self.urdf_model.joints + } + self._entity_paths = UrdfEntityPaths(self.urdf_model, "ReachyMini") + + rr.set_time("reachymini", timestamp=time.time(), recording=self.recording) + + # Use the native URDF loader in Rerun to visualize Reachy Mini's model + # Logging as non-static to allow updating joint positions + rr.log_file_from_path( + fixed_urdf, + static=False, + entity_path_prefix=self._entity_paths.prefix, + recording=self.recording, + ) + + self.running = Event() + self.thread_log_camera: Optional[Thread] = None + if ( + reachymini.media.backend == MediaBackend.GSTREAMER + or reachymini.media.backend == MediaBackend.DEFAULT + ): + self.thread_log_camera = Thread(target=self.log_camera, daemon=True) + self.thread_log_movements = Thread(target=self.log_movements, daemon=True) + + def set_absolute_path_to_urdf(self, urdf_path: str, abs_path: str) -> str: + """Set the absolute paths in the URDF file. Rerun cannot read the "package://" paths.""" + with open(urdf_path, "r") as f: + urdf_content = f.read() + urdf_content_mod = urdf_content.replace("package://", f"file://{abs_path}/") + + with tempfile.NamedTemporaryFile("w", delete=False, suffix=".urdf") as tmp_file: + tmp_file.write(urdf_content_mod) + return tmp_file.name + + def start(self) -> None: + """Start the Rerun logging thread.""" + if self.thread_log_camera is not None: + self.thread_log_camera.start() + self.thread_log_movements.start() + + def stop(self) -> None: + """Stop the Rerun logging thread.""" + self.running.set() + + def _get_joint(self, joint_name: str) -> urdf.Joint: + try: + return self._joints_by_name[joint_name] + except KeyError as exc: + raise RuntimeError(f"Invalid joint name: {joint_name}") from exc + + def _joint_entity_path(self, joint: urdf.Joint) -> str: + return self._entity_paths.joint_paths[joint.name] + + def log_camera(self) -> None: + """Log the camera image to Rerun.""" + if self._reachymini.media.camera is None: + self.logger.warning("Camera is not initialized.") + return + + self.logger.info("Starting camera logging to Rerun.") + + while not self.running.is_set(): + rr.set_time("reachymini", timestamp=time.time(), recording=self.recording) + frame = self._reachymini.media.get_frame() + if frame is not None: + if isinstance(frame, bytes): + self.logger.warning( + "Received frame is jpeg. Please use default backend." + ) + return + + else: + return + + K = np.array( + [ + [550.3564, 0.0, 638.0112], + [0.0, 549.1653, 364.589], + [0.0, 0.0, 1.0], + ] + ) + + cam_joint = self._get_joint("camera_optical_frame") + cam_path = self._joint_entity_path(cam_joint) + rr.log( + f"{cam_path}/image", + rr.Pinhole( + image_from_camera=rr.datatypes.Mat3x3(K), + width=frame.shape[1], + height=frame.shape[0], + image_plane_distance=0.8, + camera_xyz=rr.ViewCoordinates.RDF, + ), + rr.Image(frame, color_model="bgr").compress(), + recording=self.recording, + ) + + time.sleep(0.03) # ~30fps + + def _log_joint_angle( + self, + joint_name: str, + angle: float, + axis: list[float] | None = None, + ) -> None: + """Log the joint angle to Rerun.""" + joint = self._get_joint(joint_name) + joint_path = self._joint_entity_path(joint) + + base_euler = joint.origin.rotation or [0.0, 0.0, 0.0] + + # if we specify an axis override, use it; otherwise, use the joint's defined axis + effective_axis = ( + np.array(axis) + if axis is not None + else np.array(joint.axis or [1.0, 0.0, 0.0]) + ) + + target_euler = np.array(base_euler) + (effective_axis * angle) + target_translation = joint.origin.xyz or [0.0, 0.0, 0.0] + + rr.log( + joint_path, + rr.Transform3D( + translation=target_translation, + quaternion=R.from_euler("xyz", target_euler).as_quat(), + ), + recording=self.recording, + ) + + def log_movements(self) -> None: + """Log the movement data to Rerun.""" + url = f"http://{self._robot_ip}:8000/api/state/full" + + params = { + "with_control_mode": "false", + "with_head_pose": "false", + "with_target_head_pose": "false", + "with_head_joints": "true", + "with_target_head_joints": "false", + "with_body_yaw": "false", # already in head_joints + "with_target_body_yaw": "false", + "with_antenna_positions": "true", + "with_target_antenna_positions": "false", + "use_pose_matrix": "false", + "with_passive_joints": "true", + } + + while not self.running.is_set(): + msg = requests.get(url, params=params) + + if msg.status_code != 200: + self.logger.error( + f"Request failed with status {msg.status_code}: {msg.text}" + ) + time.sleep(0.1) + continue + try: + data = json.loads(msg.text) + self.logger.debug(f"Data: {data}") + except Exception: + continue + + rr.set_time("reachymini", timestamp=time.time(), recording=self.recording) + + if "antennas_position" in data and data["antennas_position"] is not None: + antennas = data["antennas_position"] + if antennas is not None: + self._log_joint_angle("left_antenna", antennas[0]) + self._log_joint_angle("right_antenna", antennas[1]) + + if "head_joints" in data and data["head_joints"] is not None: + head_joints = data["head_joints"] + + # The joint axis definitions in the URDF do not match the real axis of rotation + # due to URDF not supporting ball joints properly. + self._log_joint_angle("yaw_body", -head_joints[0], axis=[0, 0, 1]) + self._log_joint_angle("stewart_1", -head_joints[1], axis=[0, 1, 0]) + self._log_joint_angle("stewart_2", head_joints[2], axis=[0, 1, 0]) + self._log_joint_angle("stewart_3", -head_joints[3], axis=[0, 1, 0]) + self._log_joint_angle("stewart_4", head_joints[4], axis=[0, 1, 0]) + self._log_joint_angle("stewart_5", -head_joints[5], axis=[0, 1, 0]) + self._log_joint_angle("stewart_6", head_joints[6], axis=[0, 1, 0]) + + if "passive_joints" in data and data["passive_joints"] is not None: + passive_joints = data["passive_joints"] + + for axis_idx, axis in enumerate(["x", "y", "z"]): + for i in range(1, 8): + joint_name = f"passive_{i}_{axis}" + value_index = (i - 1) * 3 + axis_idx + + override_axis = [0.0, 0.0, 0.0] + override_axis[axis_idx] = 1.0 + self._log_joint_angle( + joint_name, + passive_joints[value_index], + axis=override_axis, + ) + + time.sleep(0.1) + + +class UrdfEntityPaths: + """Helper for constructing link/joint entity paths that match the native URDF logger.""" + + def __init__(self, model: urdf.URDF, entity_path_prefix: Optional[str]) -> None: + """Construct a new `UrdfEntityPaths` instance. + + Args: + model (urdf.URDF): The URDF model. + entity_path_prefix (Optional[str]): The prefix for entity paths. + + """ + self._model = model + self.prefix = entity_path_prefix + self.link_paths: Dict[str, str] = {} + self.joint_paths: Dict[str, str] = {} + + base_parts = [part for part in (self.prefix, model.name) if part] + self._base_path = "/".join(base_parts) + + children_map: Dict[str, List[urdf.Joint]] = {} + for joint in model.joints: + children_map.setdefault(joint.parent, []).append(joint) + + root_link = model.get_root() + self._build_paths(root_link, self._base_path, children_map) + + def _build_paths( + self, + link_name: str, + parent_path: str, + children_map: Dict[str, List[urdf.Joint]], + ) -> None: + link_path = self._join(parent_path, link_name) + self.link_paths[link_name] = link_path + + for joint in children_map.get(link_name, []): + joint_path = self._join(link_path, joint.name) + self.joint_paths[joint.name] = joint_path + self._build_paths(joint.child, joint_path, children_map) + + @staticmethod + def _join(parent: str, child: str) -> str: + if parent: + return f"{parent}/{child}" + return child diff --git a/reachy_mini/src/reachy_mini/utils/wireless_version/__init__.py b/reachy_mini/src/reachy_mini/utils/wireless_version/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8db2704a00479b0c46e41536d2b86a417177b991 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/wireless_version/__init__.py @@ -0,0 +1 @@ +"""Utility functions for working with wireless version.""" diff --git a/reachy_mini/src/reachy_mini/utils/wireless_version/update.py b/reachy_mini/src/reachy_mini/utils/wireless_version/update.py new file mode 100644 index 0000000000000000000000000000000000000000..b12367010c96c6d25b8aa3c128872481900b8e57 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/wireless_version/update.py @@ -0,0 +1,20 @@ +"""Module to handle software updates for the Reachy Mini wireless.""" + +import logging + +from .utils import call_logger_wrapper + + +async def update_reachy_mini(pre_release: bool, logger: logging.Logger) -> None: + """Perform a software update by upgrading the reachy_mini package and restarting the daemon.""" + extra_args = [] + if pre_release: + extra_args.append("--pre") + + await call_logger_wrapper( + ["pip", "install", "--upgrade", "reachy_mini[wireless-version]"] + extra_args, + logger, + ) + await call_logger_wrapper( + ["sudo", "systemctl", "restart", "reachy-mini-daemon"], logger + ) diff --git a/reachy_mini/src/reachy_mini/utils/wireless_version/update_available.py b/reachy_mini/src/reachy_mini/utils/wireless_version/update_available.py new file mode 100644 index 0000000000000000000000000000000000000000..b8320b42bf8834df7e844a25dc59e4666867c409 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/wireless_version/update_available.py @@ -0,0 +1,61 @@ +"""Check if an update is available for Reachy Mini Wireless. + +For now, this only checks if a new version of "reachy_mini" is available on PyPI. +""" + +from importlib.metadata import version + +import requests +import semver + + +def is_update_available(package_name: str, pre_release: bool) -> bool: + """Check if an update is available for the given package.""" + pypi_version = get_pypi_version(package_name, pre_release) + local_version = get_local_version(package_name) + + is_update_available = pypi_version > local_version + assert isinstance(is_update_available, bool) + + return is_update_available + + +def get_pypi_version(package_name: str, pre_release: bool) -> semver.Version: + """Get the latest version of a package from PyPI.""" + url = f"https://pypi.org/pypi/{package_name}/json" + response = requests.get(url) + response.raise_for_status() + data = response.json() + + version = data["info"]["version"] + + if pre_release: + releases = list(data["releases"].keys()) + pre_version = _semver_version(releases[-1]) + if pre_version > version: + return pre_version + + return _semver_version(version) + + +def get_local_version(package_name: str) -> semver.Version: + """Get the currently installed version of a package.""" + return _semver_version(version(package_name)) + + +def _semver_version(v: str) -> semver.Version: + """Convert a version string to a semver.Version object, handling pypi pre-release formats.""" + try: + return semver.Version.parse(v) + except ValueError: + version_parts = v.split(".") + if len(version_parts) < 3: + raise ValueError(f"Invalid version string: {v}") + + patch_part = version_parts[2] + if "rc" in patch_part: + patch, rc = patch_part.split("rc", 1) + v_clean = f"{version_parts[0]}.{version_parts[1]}.{patch}-rc.{rc}" + return semver.Version.parse(v_clean) + + raise ValueError(f"Invalid version string: {v}") diff --git a/reachy_mini/src/reachy_mini/utils/wireless_version/utils.py b/reachy_mini/src/reachy_mini/utils/wireless_version/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..dff1b3650f38f259c1b35fc50cafc4f79572c809 --- /dev/null +++ b/reachy_mini/src/reachy_mini/utils/wireless_version/utils.py @@ -0,0 +1,39 @@ +"""Utility functions for running shell commands asynchronously with real-time logging.""" + +import asyncio +import logging +from typing import Callable + + +async def call_logger_wrapper(command: list[str], logger: logging.Logger) -> None: + """Run a command asynchronously, streaming stdout and stderr to logger in real time. + + Args: + command: list or tuple of command arguments (not a string) + logger: logger object with .info and .error methods + + """ + process = await asyncio.create_subprocess_exec( + *command, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + + async def stream_output( + stream: asyncio.StreamReader, + log_func: Callable[[str], None], + ) -> None: + while True: + line = await stream.readline() + if not line: + break + log_func(line.decode().rstrip()) + + tasks = [] + if process.stdout is not None: + tasks.append(asyncio.create_task(stream_output(process.stdout, logger.info))) + if process.stderr is not None: + tasks.append(asyncio.create_task(stream_output(process.stderr, logger.error))) + + await asyncio.gather(*tasks) + await process.wait() diff --git a/reachy_mini/tests/faulty_app/README.md b/reachy_mini/tests/faulty_app/README.md new file mode 100644 index 0000000000000000000000000000000000000000..63915a996d683aad5ba055ef43f9d2ca093c5b51 --- /dev/null +++ b/reachy_mini/tests/faulty_app/README.md @@ -0,0 +1 @@ +# faulty_app - A ReachyMini application \ No newline at end of file diff --git a/reachy_mini/tests/faulty_app/faulty_app/__init__.py b/reachy_mini/tests/faulty_app/faulty_app/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/reachy_mini/tests/faulty_app/faulty_app/main.py b/reachy_mini/tests/faulty_app/faulty_app/main.py new file mode 100644 index 0000000000000000000000000000000000000000..7834aefc7b3cdd3805128f66b4b5ddb96a93ddcc --- /dev/null +++ b/reachy_mini/tests/faulty_app/faulty_app/main.py @@ -0,0 +1,9 @@ +import threading + +from reachy_mini import ReachyMini, ReachyMiniApp + + +class FaultyApp(ReachyMiniApp): + def run(self, reachy_mini: ReachyMini, stop_event: threading.Event): + raise RuntimeError("This is a faulty app for testing purposes.") + diff --git a/reachy_mini/tests/faulty_app/pyproject.toml b/reachy_mini/tests/faulty_app/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..5fe572f708a23be63839c0853fdaf09b46e7196f --- /dev/null +++ b/reachy_mini/tests/faulty_app/pyproject.toml @@ -0,0 +1,18 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + + +[project] +name = "faulty_app" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.8" +dependencies = [ + "reachy-mini" +] +keywords = ["reachy-mini-app"] + +[project.entry-points."reachy_mini_apps"] +faulty_app = "faulty_app.main:FaultyApp" \ No newline at end of file diff --git a/reachy_mini/tests/ok_app/README.md b/reachy_mini/tests/ok_app/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3297f129a114bac224eb602bce4300e26d01ad19 --- /dev/null +++ b/reachy_mini/tests/ok_app/README.md @@ -0,0 +1 @@ +# ok_app - A ReachyMini application \ No newline at end of file diff --git a/reachy_mini/tests/ok_app/ok_app/__init__.py b/reachy_mini/tests/ok_app/ok_app/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/reachy_mini/tests/ok_app/ok_app/main.py b/reachy_mini/tests/ok_app/ok_app/main.py new file mode 100644 index 0000000000000000000000000000000000000000..80e245f3817b53dd35cb4cc06f0f0f2e08f6943f --- /dev/null +++ b/reachy_mini/tests/ok_app/ok_app/main.py @@ -0,0 +1,10 @@ +import threading +import time + +from reachy_mini import ReachyMini, ReachyMiniApp + + +class OkApp(ReachyMiniApp): + def run(self, reachy_mini: ReachyMini, stop_event: threading.Event): + while not stop_event.is_set(): + time.sleep(0.5) \ No newline at end of file diff --git a/reachy_mini/tests/ok_app/pyproject.toml b/reachy_mini/tests/ok_app/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..58ff6f6df56e0b3a9c433de7d9985a617ff19389 --- /dev/null +++ b/reachy_mini/tests/ok_app/pyproject.toml @@ -0,0 +1,18 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + + +[project] +name = "ok_app" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.8" +dependencies = [ + "reachy-mini" +] +keywords = ["reachy-mini-app"] + +[project.entry-points."reachy_mini_apps"] +ok_app = "ok_app.main:OkApp" \ No newline at end of file diff --git a/reachy_mini/tests/test_analytical_kinematics.py b/reachy_mini/tests/test_analytical_kinematics.py new file mode 100644 index 0000000000000000000000000000000000000000..810006a99a15321d2cf6fb2720814d2bbc0cb9ff --- /dev/null +++ b/reachy_mini/tests/test_analytical_kinematics.py @@ -0,0 +1,19 @@ +from reachy_mini.kinematics import AnalyticalKinematics +import numpy as np + +def test_analytical_kinematics(): + ak = AnalyticalKinematics() + pose = np.eye(4) + sol = ak.ik(pose) + assert sol is not None, "IK solution should be found" + fk_pose = ak.fk(sol, no_iterations=10) + assert np.allclose(fk_pose, pose, atol=1e-2), "FK should match the original pose" + +def test_analytical_kinematics_with_yaw(): + ak = AnalyticalKinematics() + pose = np.eye(4) + body_yaw = np.pi / 4 # 45 degrees + sol = ak.ik(pose, body_yaw=body_yaw) + assert sol is not None, "IK solution should be found with body yaw" + fk_pose = ak.fk(sol, no_iterations=10) + assert np.allclose(fk_pose, pose, atol=1e-2), "FK should match the original pose with body yaw" \ No newline at end of file diff --git a/reachy_mini/tests/test_app.py b/reachy_mini/tests/test_app.py new file mode 100644 index 0000000000000000000000000000000000000000..58eb7c6d9e5d9e958eaba35f6d44617172a66211 --- /dev/null +++ b/reachy_mini/tests/test_app.py @@ -0,0 +1,114 @@ + +import asyncio +from pathlib import Path +from threading import Event +import time +import pytest + +from reachy_mini import ReachyMiniApp +from reachy_mini.apps import AppInfo, SourceKind +from reachy_mini.apps.manager import AppManager, AppState +from reachy_mini.daemon.daemon import Daemon +from reachy_mini.reachy_mini import ReachyMini + + +@pytest.mark.asyncio +async def test_app() -> None: + class MockApp(ReachyMiniApp): + def run(self, reachy_mini: ReachyMini, stop_event: Event) -> None: + time.sleep(1) # Simulate some processing time + + daemon = Daemon() + await daemon.start( + sim=True, + headless=True, + wake_up_on_start=False, + ) + + stop = Event() + + with ReachyMini(media_backend="no_media") as mini: + app = MockApp() + app.run(mini, stop) + + await daemon.stop(goto_sleep_on_stop=False) + + +@pytest.mark.asyncio +async def test_app_manager() -> None: + daemon = Daemon() + await daemon.start( + sim=True, + headless=True, + wake_up_on_start=False, + ) + + app_mngr = AppManager() + + before_installed_apps = await app_mngr.list_available_apps(SourceKind.INSTALLED) + + app_info = AppInfo( + name="ok_app", + source_kind=SourceKind.LOCAL, + extra={"path": str(Path(__file__).parent / "ok_app")}, + ) + await app_mngr.install_new_app(app_info, daemon.logger) + + after_installed_apps = await app_mngr.list_available_apps(SourceKind.INSTALLED) + + assert len(after_installed_apps) == len(before_installed_apps) + 1 + + status = await app_mngr.start_app("ok_app", media_backend="no_media") + assert status is not None and status.state in (AppState.STARTING, AppState.RUNNING) + assert app_mngr.is_app_running() + status = await app_mngr.current_app_status() + assert status is not None and status.state in (AppState.STARTING, AppState.RUNNING) + + await app_mngr.stop_current_app() + assert not app_mngr.is_app_running() + status = await app_mngr.current_app_status() + assert status is None + + await app_mngr.remove_app("ok_app", daemon.logger) + after_uninstalled_apps = await app_mngr.list_available_apps(SourceKind.INSTALLED) + + assert len(after_uninstalled_apps) == len(before_installed_apps) + + await daemon.stop(goto_sleep_on_stop=False) + + + +@pytest.mark.asyncio +async def test_faulty_app() -> None: + daemon = Daemon() + await daemon.start( + sim=True, + headless=True, + wake_up_on_start=False, + ) + + app_mngr = AppManager() + + app_info = AppInfo( + name="faulty_app", + source_kind=SourceKind.LOCAL, + extra={"path": str(Path(__file__).parent / "faulty_app")}, + ) + await app_mngr.install_new_app(app_info, daemon.logger) + + + status = await app_mngr.start_app("faulty_app", media_backend="no_media") + + for _ in range(10): + status = await app_mngr.current_app_status() + if status is None or status.state in (AppState.STARTING, AppState.RUNNING): + await asyncio.sleep(1.0) + continue + assert status is not None and status.state == AppState.ERROR + break + else: + pytest.fail("Faulty app did not reach ERROR state in time") + + await app_mngr.remove_app("faulty_app", daemon.logger) + + await daemon.stop(goto_sleep_on_stop=False) diff --git a/reachy_mini/tests/test_audio.py b/reachy_mini/tests/test_audio.py new file mode 100644 index 0000000000000000000000000000000000000000..8ca28475f0960c0860c04b196c745c166ecbf09f --- /dev/null +++ b/reachy_mini/tests/test_audio.py @@ -0,0 +1,90 @@ +import os +import time +import tempfile +import pytest +import soundfile as sf +from reachy_mini.media.media_manager import MediaManager, MediaBackend + +@pytest.mark.audio +def test_play_sound_default_backend() -> None: + """Test playing a sound with the default backend.""" + media = MediaManager(backend=MediaBackend.DEFAULT_NO_VIDEO) + # Use a short sound file present in your assets directory + sound_file = "wake_up.wav" # Change to a valid file if needed + media.play_sound(sound_file) + print("Playing sound with default backend...") + # Wait a bit to let the sound play (non-blocking backend) + time.sleep(2) + # No assertion: test passes if no exception is raised. + # Sound should be audible if the audio device is correctly set up. + +@pytest.mark.audio +def test_record_audio_and_file_exists() -> None: + """Test recording audio and check that the file exists and is not empty.""" + media = MediaManager(backend=MediaBackend.DEFAULT_NO_VIDEO) + duration = 2 # seconds + tmpfile = tempfile.NamedTemporaryFile(suffix='.wav', delete=False) + tmpfile.close() + media.start_recording() + time.sleep(duration) + media.stop_recording() + audio = media.get_audio_sample() + samplerate = media.get_input_audio_samplerate() + if audio is not None: + sf.write(tmpfile.name, audio, samplerate) + assert os.path.exists(tmpfile.name) + assert os.path.getsize(tmpfile.name) > 0 + # comment the following line if you want to keep the file for inspection + os.remove(tmpfile.name) + # print(f"Recorded audio saved to {tmpfile.name}") + +@pytest.mark.audio +def test_DoA() -> None: + """Test Direction of Arrival (DoA) estimation.""" + media = MediaManager(backend=MediaBackend.DEFAULT_NO_VIDEO) + doa = media.audio.get_DoA() + assert doa is not None + assert isinstance(doa, tuple) + assert len(doa) == 2 + assert isinstance(doa[0], float) + assert isinstance(doa[1], bool) + + +''' +@pytest.mark.audio_gstreamer +def test_play_sound_gstreamer_backend() -> None: + """Test playing a sound with the GStreamer backend.""" + media = MediaManager(backend=MediaBackend.GSTREAMER) + time.sleep(2) # Give some time for the audio system to initialize + # Use a short sound file present in your assets directory + sound_file = "wake_up.wav" # Change to a valid file if needed + media.play_sound(sound_file) + print("Playing sound with GStreamer backend...") + # Wait a bit to let the sound play (non-blocking backend) + time.sleep(2) + # No assertion: test passes if no exception is raised. + # Sound should be audible if the audio device is correctly set up. +''' + +@pytest.mark.audio_gstreamer +def test_record_audio_and_file_exists_gstreamer() -> None: + """Test recording audio and check that the file exists and is not empty.""" + media = MediaManager(backend=MediaBackend.GSTREAMER) + duration = 2 # seconds + tmpfile = tempfile.NamedTemporaryFile(suffix='.wav', delete=False) + tmpfile.close() + media.start_recording() + time.sleep(duration) + audio = media.get_audio_sample() + assert audio is not None + media.stop_recording() + + +def test_no_media() -> None: + """Test that methods handle uninitialized media gracefully.""" + media = MediaManager(backend=MediaBackend.NO_MEDIA) + + assert media.get_frame() is None + assert media.get_audio_sample() is None + assert media.get_input_audio_samplerate() == -1 + assert media.get_output_audio_samplerate() == -1 diff --git a/reachy_mini/tests/test_collision.py b/reachy_mini/tests/test_collision.py new file mode 100644 index 0000000000000000000000000000000000000000..8948d8d6a869453d78e88dd94155e708495852b5 --- /dev/null +++ b/reachy_mini/tests/test_collision.py @@ -0,0 +1,17 @@ +from reachy_mini.utils.constants import URDF_ROOT_PATH +from reachy_mini.kinematics import PlacoKinematics +from reachy_mini.utils import create_head_pose + + +def offline_test_collision(): + head_kinematics = PlacoKinematics( + urdf_path=URDF_ROOT_PATH, check_collision=True + ) + + reachable_pose = create_head_pose() + sol = head_kinematics.ik(reachable_pose) + assert sol is not None, "The reachable pose should not cause a collision." + + unreachable_pose = create_head_pose(x=20, y=20, mm=True) + sol = head_kinematics.ik(unreachable_pose) + assert sol is None, "The unreachable pose should cause a collision." diff --git a/reachy_mini/tests/test_daemon.py b/reachy_mini/tests/test_daemon.py new file mode 100644 index 0000000000000000000000000000000000000000..589f1c09c042a43c335cbdbc555f1961550eb565 --- /dev/null +++ b/reachy_mini/tests/test_daemon.py @@ -0,0 +1,92 @@ +import asyncio +import numpy as np +import pytest + +from reachy_mini.daemon.daemon import Daemon +from reachy_mini.reachy_mini import ReachyMini + +@pytest.mark.asyncio +async def test_daemon_start_stop() -> None: + from reachy_mini.daemon.daemon import Daemon + + daemon = Daemon() + await daemon.start( + sim=True, + headless=True, + wake_up_on_start=False, + ) + await daemon.stop(goto_sleep_on_stop=False) + + +@pytest.mark.asyncio +async def test_daemon_multiple_start_stop() -> None: + daemon = Daemon() + + for _ in range(3): + await daemon.start( + sim=True, + headless=True, + wake_up_on_start=False, + ) + await daemon.stop(goto_sleep_on_stop=False) + + +@pytest.mark.asyncio +async def test_daemon_client_disconnection() -> None: + daemon = Daemon() + await daemon.start( + sim=True, + headless=True, + wake_up_on_start=False, + ) + + client_connected = asyncio.Event() + + async def simple_client() -> None: + with ReachyMini(media_backend="no_media") as mini: + status = mini.client.get_status() + assert status['state'] == "running" + assert status['simulation_enabled'] + assert status['error'] is None + assert status['backend_status']['motor_control_mode'] == "enabled" + assert status['backend_status']['error'] is None + assert status['wlan_ip'] is None + client_connected.set() + + async def wait_for_client() -> None: + await client_connected.wait() + await daemon.stop(goto_sleep_on_stop=False) + + await asyncio.gather(simple_client(), wait_for_client()) + +@pytest.mark.asyncio +async def test_daemon_early_stop() -> None: + daemon = Daemon() + await daemon.start( + sim=True, + headless=True, + wake_up_on_start=False, + ) + + client_connected = asyncio.Event() + daemon_stopped = asyncio.Event() + + async def client_bg() -> None: + with ReachyMini(media_backend="no_media") as reachy: + client_connected.set() + await daemon_stopped.wait() + + # Make sure the keep-alive check runs at least once + reachy.client._check_alive_evt.clear() + reachy.client._check_alive_evt.wait(timeout=100.0) + + with pytest.raises(ConnectionError, match="Lost connection with the server."): + reachy.set_target(head=np.eye(4)) + + async def will_stop_soon() -> None: + await client_connected.wait() + await daemon.stop(goto_sleep_on_stop=False) + daemon_stopped.set() + + await asyncio.gather(client_bg(), will_stop_soon()) + diff --git a/reachy_mini/tests/test_import.py b/reachy_mini/tests/test_import.py new file mode 100644 index 0000000000000000000000000000000000000000..a553156690d214bc6e65f88f56c5bbbf7cf6c13b --- /dev/null +++ b/reachy_mini/tests/test_import.py @@ -0,0 +1,6 @@ + + +def test_import(): # noqa: D100, D103 + from reachy_mini import ReachyMini # noqa: F401 + from reachy_mini import ReachyMiniApp # noqa: F401 + diff --git a/reachy_mini/tests/test_placo.py b/reachy_mini/tests/test_placo.py new file mode 100644 index 0000000000000000000000000000000000000000..1f9a76aff6c49311993d963fcb4ebde42b0c5b7e --- /dev/null +++ b/reachy_mini/tests/test_placo.py @@ -0,0 +1,7 @@ +def test_load_kinematics(): # noqa: D100, D103 + from reachy_mini.utils.constants import URDF_ROOT_PATH + from reachy_mini.kinematics import PlacoKinematics + + # Test loading the kinematics + kinematics = PlacoKinematics(URDF_ROOT_PATH) + assert kinematics is not None, "Failed to load PlacoKinematics." diff --git a/reachy_mini/tests/test_video.py b/reachy_mini/tests/test_video.py new file mode 100644 index 0000000000000000000000000000000000000000..63fbccd0bac4dd75e771ec72b818f523461a7350 --- /dev/null +++ b/reachy_mini/tests/test_video.py @@ -0,0 +1,87 @@ +from reachy_mini.media.camera_constants import ReachyMiniCamSpecs, ArduCamResolution, MujocoCameraSpecs +from reachy_mini.media.media_manager import MediaManager, MediaBackend +import numpy as np +import pytest +import time +# import tempfile +# import cv2 + + +@pytest.mark.video +def test_get_frame_exists() -> None: + """Test that a frame can be retrieved from the camera and is not None.""" + media = MediaManager(backend=MediaBackend.DEFAULT) + frame = media.get_frame() + assert frame is not None, "No frame was retrieved from the camera." + assert isinstance(frame, np.ndarray), "Frame is not a numpy array." + assert frame.size > 0, "Frame is empty." + assert frame.shape[0] == media.camera.resolution[1] and frame.shape[1] == media.camera.resolution[0], f"Frame has incorrect dimensions: {frame.shape}" + + # with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp_file: + # cv2.imwrite(tmp_file.name, frame) + # print(f"Frame saved for inspection: {tmp_file.name}") + +@pytest.mark.video +def test_get_frame_exists_all_resolutions() -> None: + """Test that a frame can be retrieved from the camera for all supported resolutions.""" + media = MediaManager(backend=MediaBackend.DEFAULT) + for resolution in media.camera.camera_specs.available_resolutions: + media.camera.set_resolution(resolution) + frame = media.get_frame() + assert frame is not None, f"No frame was retrieved from the camera at resolution {resolution}." + assert isinstance(frame, np.ndarray), f"Frame is not a numpy array at resolution {resolution}." + assert frame.size > 0, f"Frame is empty at resolution {resolution}." + assert frame.shape[0] == resolution.value[1] and frame.shape[1] == resolution.value[0], f"Frame has incorrect dimensions at resolution {resolution}: {frame.shape}" + +@pytest.mark.video +def test_change_resolution_errors() -> None: + """Test that changing resolution raises a runtime error if not allowed.""" + media = MediaManager(backend=MediaBackend.DEFAULT) + media.camera.camera_specs = None + with pytest.raises(RuntimeError): + media.camera.set_resolution(ArduCamResolution.R1280x720) + + media.camera.camera_specs = MujocoCameraSpecs() + with pytest.raises(RuntimeError): + media.camera.set_resolution(ArduCamResolution.R1280x720) + + media.camera.camera_specs = ReachyMiniCamSpecs() + with pytest.raises(ValueError): + media.camera.set_resolution(ArduCamResolution.R1280x720) + + +@pytest.mark.video_gstreamer +def test_get_frame_exists_gstreamer() -> None: + """Test that a frame can be retrieved from the camera and is not None.""" + media = MediaManager(backend=MediaBackend.GSTREAMER) + time.sleep(2) # Give some time for the camera to initialize + frame = media.get_frame() + assert frame is not None, "No frame was retrieved from the camera." + assert isinstance(frame, np.ndarray), "Frame is not a numpy array." + assert frame.size > 0, "Frame is empty." + assert frame.shape[0] == media.camera.resolution[1] and frame.shape[1] == media.camera.resolution[0], f"Frame has incorrect dimensions: {frame.shape}" + +@pytest.mark.video_gstreamer +def test_get_frame_exists_all_resolutions_gstreamer() -> None: + """Test that a frame can be retrieved from the camera for all supported resolutions.""" + media = MediaManager(backend=MediaBackend.GSTREAMER) + time.sleep(2) # Give some time for the camera to initialize + + for resolution in media.camera.camera_specs.available_resolutions: + media.camera.close() + media.camera.set_resolution(resolution) + media.camera.open() + time.sleep(2) # Give some time for the camera to adjust to new resolution + frame = media.get_frame() + assert frame is not None, f"No frame was retrieved from the camera at resolution {resolution}." + assert isinstance(frame, np.ndarray), f"Frame is not a numpy array at resolution {resolution}." + assert frame.size > 0, f"Frame is empty at resolution {resolution}." + assert frame.shape[0] == resolution.value[1] and frame.shape[1] == resolution.value[0], f"Frame has incorrect dimensions at resolution {resolution}: {frame.shape}" + +@pytest.mark.video_gstreamer +def test_change_resolution_errors_gstreamer() -> None: + """Test that changing resolution raises a runtime error if not allowed.""" + media = MediaManager(backend=MediaBackend.GSTREAMER) + time.sleep(1) # Give some time for the camera to initialize + with pytest.raises(RuntimeError): + media.camera.set_resolution(media.camera.camera_specs.available_resolutions[0]) diff --git a/reachy_mini/tests/test_wireless.py b/reachy_mini/tests/test_wireless.py new file mode 100644 index 0000000000000000000000000000000000000000..0d702d4666d90218d3a0548319ab50e256b824b5 --- /dev/null +++ b/reachy_mini/tests/test_wireless.py @@ -0,0 +1,30 @@ +import pytest + + +from reachy_mini.reachy_mini import ReachyMini +import time +import numpy as np +from reachy_mini.media.camera_constants import RPICameraResolution + +@pytest.mark.wireless +def test_daemon_wireless_client_disconnection() -> None: + with ReachyMini(media_backend="no_media", localhost_only=False) as mini: + status = mini.client.get_status() + assert status['state'] == "running" + assert status['wireless_version'] is True + assert not status['simulation_enabled'] + assert status['error'] is None + assert status['backend_status']['motor_control_mode'] == "enabled" + assert status['backend_status']['error'] is None + assert isinstance(status['wlan_ip'], str) + assert status['wlan_ip'].count('.') == 3 + assert all(0 <= int(part) <= 255 for part in status['wlan_ip'].split('.') if part.isdigit()) + +@pytest.mark.wireless_gstreamer +def test_daemon_wireless_gstreamer() -> None: + with ReachyMini(media_backend="gstreamer") as mini: + time.sleep(3) # Give some time for the camera to initialize + frame = mini.media.get_frame() + assert frame is not None, "No frame was retrieved from the camera." + assert isinstance(frame, np.ndarray), "Frame is not a numpy array." + assert frame.shape[0] == RPICameraResolution.R1280x720.value[1] and frame.shape[1] == RPICameraResolution.R1280x720.value[0], f"Frame has incorrect dimensions: {frame.shape}" diff --git a/reachy_mini/tools/setup_motor.py b/reachy_mini/tools/setup_motor.py new file mode 100644 index 0000000000000000000000000000000000000000..32b74b0c1f93bf28756662ebbf71d0343a14e611 --- /dev/null +++ b/reachy_mini/tools/setup_motor.py @@ -0,0 +1,389 @@ +"""Motor setup script for the Reachy Mini robot. + +This script allows to configure the motors of the Reachy Mini robot by setting their ID, baudrate, offset, angle limits, return delay time, and removing the input voltage error. + +The motor needs to be configured one by one, so you will need to connect only one motor at a time to the serial port. You can specify which motor to configure by passing its name as an argument. + +If not specified, it assumes the motor is in the factory settings (ID 1 and baudrate 57600). If it's not the case, you will need to use a tool like Dynamixel Wizard to first reset it or manually specify the ID and baudrate. + +Please note that all values given in the configuration file are in the motor's raw units. +""" + +import argparse +import time +from pathlib import Path + +from rustypot import Xl330PyController + +from reachy_mini.utils.hardware_config.parser import MotorConfig, parse_yaml_config + +FACTORY_DEFAULT_ID = 1 +FACTORY_DEFAULT_BAUDRATE = 57600 +SERIAL_TIMEOUT = 0.01 # seconds +MOTOR_SETUP_DELAY = 0.1 # seconds + +XL_BAUDRATE_CONV_TABLE = { + 9600: 0, + 57600: 1, + 115200: 2, + 1000000: 3, + 2000000: 4, + 3000000: 5, + 4000000: 6, +} + + +def setup_motor( + motor_config: MotorConfig, + serial_port: str, + from_baudrate: int, + target_baudrate: int, + from_id: int, +): + """Set up the motor with the given configuration.""" + if not lookup_for_motor( + serial_port, + from_id, + from_baudrate, + ): + raise RuntimeError( + f"No motor found on port {serial_port}. " + f"Make sure the motor is in factory settings (ID {from_id} and baudrate {from_baudrate}) and connected to the specified port." + ) + + # Make sure the torque is disabled to be able to write EEPROM + disable_torque(serial_port, from_id, from_baudrate) + try: + if from_baudrate != target_baudrate: + change_baudrate( + serial_port, + id=from_id, + base_baudrate=from_baudrate, + target_baudrate=target_baudrate, + ) + time.sleep(MOTOR_SETUP_DELAY) + + if from_id != motor_config.id: + change_id( + serial_port, + current_id=from_id, + new_id=motor_config.id, + baudrate=target_baudrate, + ) + time.sleep(MOTOR_SETUP_DELAY) + + change_offset( + serial_port, + id=motor_config.id, + offset=motor_config.offset, + baudrate=target_baudrate, + ) + + time.sleep(MOTOR_SETUP_DELAY) + + change_angle_limits( + serial_port, + id=motor_config.id, + angle_limit_min=motor_config.angle_limit_min, + angle_limit_max=motor_config.angle_limit_max, + baudrate=target_baudrate, + ) + + time.sleep(MOTOR_SETUP_DELAY) + + change_shutdown_error( + serial_port, + id=motor_config.id, + baudrate=target_baudrate, + shutdown_error=motor_config.shutdown_error, + ) + + time.sleep(MOTOR_SETUP_DELAY) + + change_return_delay_time( + serial_port, + id=motor_config.id, + return_delay_time=motor_config.return_delay_time, + baudrate=target_baudrate, + ) + + time.sleep(MOTOR_SETUP_DELAY) + except Exception as e: + print(f"Error while setting up motor ID {from_id}: {e}") + raise e + + +def lookup_for_motor( + serial_port: str, id: int, baudrate: int, silent: bool = False +) -> bool: + """Check if a motor with the given ID is reachable on the specified serial port.""" + if not silent: + print( + f"Looking for motor with ID {id} on port {serial_port}...", + end="", + flush=True, + ) + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + ret = c.ping(id) + if not silent: + print(f"{'✅' if ret else '❌'}") + return ret + + +def disable_torque(serial_port: str, id: int, baudrate: int): + """Disable the torque of the motor with the given ID on the specified serial port.""" + print(f"Disabling torque for motor with ID {id}...", end="", flush=True) + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + c.write_torque_enable(id, False) + print("✅") + + +def change_baudrate( + serial_port: str, id: int, base_baudrate: int, target_baudrate: int +): + """Change the baudrate of the motor with the given ID on the specified serial port.""" + print(f"Changing baudrate to {target_baudrate}...", end="", flush=True) + c = Xl330PyController(serial_port, baudrate=base_baudrate, timeout=SERIAL_TIMEOUT) + c.write_baud_rate(id, XL_BAUDRATE_CONV_TABLE[target_baudrate]) + print("✅") + + +def change_id(serial_port: str, current_id: int, new_id: int, baudrate: int): + """Change the ID of the motor with the given current ID on the specified serial port.""" + print(f"Changing ID from {current_id} to {new_id}...", end="", flush=True) + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + c.write_id(current_id, new_id) + print("✅") + + +def change_offset(serial_port: str, id: int, offset: int, baudrate: int): + """Change the offset of the motor with the given ID on the specified serial port.""" + print(f"Changing offset for motor with ID {id} to {offset}...", end="", flush=True) + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + c.write_homing_offset(id, offset) + print("✅") + + +def change_angle_limits( + serial_port: str, + id: int, + angle_limit_min: int, + angle_limit_max: int, + baudrate: int, +): + """Change the angle limits of the motor with the given ID on the specified serial port.""" + print( + f"Changing angle limits for motor with ID {id} to [{angle_limit_min}, {angle_limit_max}]...", + end="", + flush=True, + ) + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + c.write_raw_min_position_limit(id, angle_limit_min) + c.write_raw_max_position_limit(id, angle_limit_max) + print("✅") + + +def change_shutdown_error( + serial_port: str, id: int, baudrate: int, shutdown_error: int +): + """Change the shutdown error of the motor with the given ID on the specified serial port.""" + print( + f"Changing shutdown error for motor with ID {id} to {shutdown_error}...", + end="", + flush=True, + ) + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + c.write_shutdown(id, shutdown_error) + print("✅") + + +def change_return_delay_time( + serial_port: str, id: int, return_delay_time: int, baudrate: int +): + """Change the return delay time of the motor with the given ID on the specified serial port.""" + print( + f"Changing return delay time for motor with ID {id} to {return_delay_time}...", + end="", + flush=True, + ) + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + c.write_return_delay_time(id, return_delay_time) + print("✅") + + +def light_led_up(serial_port: str, id: int, baudrate: int): + """Light the LED of the motor with the given ID on the specified serial port.""" + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + + trials = 0 + + while trials < 3: + try: + c.write_led(id, 1) + break + except RuntimeError as e: + print(f"Error while turning on LED for motor ID {id}: {e}") + trials += 1 + + +def light_led_down(serial_port: str, id: int, baudrate: int): + """Light the LED of the motor with the given ID on the specified serial port.""" + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + trials = 0 + + while trials < 3: + try: + c.write_led(id, 0) + break + except RuntimeError as e: + print(f"Error while turning off LED for motor ID {id}: {e}") + trials += 1 + + +def check_configuration(motor_config: MotorConfig, serial_port: str, baudrate: int): + """Check the configuration of the motor with the given ID on the specified serial port.""" + c = Xl330PyController(serial_port, baudrate=baudrate, timeout=SERIAL_TIMEOUT) + + print("Checking configuration...") + + # Check if there is a motor with the desired ID + if not c.ping(motor_config.id): + raise RuntimeError(f"No motor with ID {motor_config.id} found, cannot proceed") + print(f"Found motor with ID {motor_config.id} ✅.") + + # Read return delay time + return_delay = c.read_return_delay_time(motor_config.id)[0] + if return_delay != motor_config.return_delay_time: + raise RuntimeError( + f"Return delay time is {return_delay}, expected {motor_config.return_delay_time}" + ) + print(f"Return delay time is correct: {return_delay} ✅.") + + # Read angle limits + angle_limit_min = c.read_raw_min_position_limit(motor_config.id)[0] + angle_limit_max = c.read_raw_max_position_limit(motor_config.id)[0] + if angle_limit_min != motor_config.angle_limit_min: + raise RuntimeError( + f"Angle limit min is {angle_limit_min}, expected {motor_config.angle_limit_min}" + ) + if angle_limit_max != motor_config.angle_limit_max: + raise RuntimeError( + f"Angle limit max is {angle_limit_max}, expected {motor_config.angle_limit_max}" + ) + print( + f"Angle limits are correct: [{motor_config.angle_limit_min}, {motor_config.angle_limit_max}] ✅." + ) + + # Read homing offset + offset = c.read_homing_offset(motor_config.id)[0] + if offset != motor_config.offset: + raise RuntimeError(f"Homing offset is {offset}, expected {motor_config.offset}") + print(f"Homing offset is correct: {offset} ✅.") + + # Read shutdown + shutdown = c.read_shutdown(motor_config.id)[0] + if shutdown != motor_config.shutdown_error: + raise RuntimeError( + f"Shutdown is {shutdown}, expected {motor_config.shutdown_error}" + ) + print(f"Shutdown error is correct: {shutdown} ✅.") + + print("Configuration is correct ✅!") + + +def run(args): + """Entry point for the Reachy Mini motor configuration tool.""" + config = parse_yaml_config(args.config_file) + + if args.motor_name == "all": + motors = list(config.motors.keys()) + else: + motors = [args.motor_name] + + for motor_name in motors: + motor_config = config.motors[motor_name] + + if args.update_config: + args.from_id = motor_config.id + args.from_baudrate = config.serial.baudrate + + if not args.check_only: + setup_motor( + motor_config, + args.serialport, + from_id=args.from_id, + from_baudrate=args.from_baudrate, + target_baudrate=config.serial.baudrate, + ) + + try: + check_configuration( + motor_config, + args.serialport, + baudrate=config.serial.baudrate, + ) + except RuntimeError as e: + print(f"❌ Configuration check failed for motor '{motor_name}': {e}") + return + + light_led_up( + args.serialport, + motor_config.id, + baudrate=config.serial.baudrate, + ) + + +if __name__ == "__main__": + """Entry point for the Reachy Mini motor configuration tool.""" + parser = argparse.ArgumentParser(description="Motor Configuration tool") + parser.add_argument( + "config_file", + type=Path, + help="Path to the hardware configuration file (default: hardware_config.yaml).", + ) + parser.add_argument( + "motor_name", + type=str, + help="Name of the motor to configure.", + choices=[ + "body_rotation", + "stewart_1", + "stewart_2", + "stewart_3", + "stewart_4", + "stewart_5", + "stewart_6", + "right_antenna", + "left_antenna", + "all", + ], + ) + parser.add_argument( + "serialport", + type=str, + help="Serial port for communication with the motor.", + ) + parser.add_argument( + "--check-only", + action="store_true", + help="Only check the configuration without applying changes.", + ) + parser.add_argument( + "--from-id", + type=int, + default=FACTORY_DEFAULT_ID, + help=f"Current ID of the motor (default: {FACTORY_DEFAULT_ID}).", + ) + parser.add_argument( + "--from-baudrate", + type=int, + default=FACTORY_DEFAULT_BAUDRATE, + help=f"Current baudrate of the motor (default: {FACTORY_DEFAULT_BAUDRATE}).", + ) + parser.add_argument( + "--update-config", + action="store_true", + help="Update a specific motor (assumes it already has the correct id and baudrate).", + ) + args = parser.parse_args() + run(args) diff --git a/reachy_mini/tools/setup_motor_rpi.py b/reachy_mini/tools/setup_motor_rpi.py new file mode 100644 index 0000000000000000000000000000000000000000..6d865de339bc1d7bf3032fb26cd6b2d9417ef8c7 --- /dev/null +++ b/reachy_mini/tools/setup_motor_rpi.py @@ -0,0 +1,108 @@ +"""You need to `pip install gpiozero lgpio`.""" + +import argparse +import os +import time +from typing import List + +import numpy as np +from gpiozero import DigitalOutputDevice +from setup_motor import ( + FACTORY_DEFAULT_BAUDRATE, + FACTORY_DEFAULT_ID, + light_led_down, + lookup_for_motor, + parse_yaml_config, + run, +) + +assets_root_path = "../src/reachy_mini/assets/" + + +UART_PORT = "/dev/ttyAMA3" +CONFIG_FILE_PATH = os.path.join(assets_root_path, "config", "hardware_config.yaml") + +ID_TO_CHANNEL = { + 10: 0, + 11: 1, + 12: 2, + 13: 3, + 14: 4, + 15: 5, + 16: 6, + 17: 7, + 18: 8, +} +CHANNEL_TO_ID = {v: k for k, v in ID_TO_CHANNEL.items()} + +S0 = DigitalOutputDevice(25) +S1 = DigitalOutputDevice(8) +S2 = DigitalOutputDevice(7) +S3 = DigitalOutputDevice(1) + + +def get_channel_binary(channel) -> List[int]: + """Convert channel number (0-8) to 4-bit binary representation.""" + assert channel in np.arange(9), "Channel must be between 0 and 8" + bits = [int(b) for b in f"{channel:04b}"] # 4-bit binary + return bits[::-1] # flip the order + + +def select_channel(channel: int): + """Select a channel on the multiplexer.""" + bits = get_channel_binary(channel) + S0.on() if bits[0] else S0.off() + S1.on() if bits[1] else S1.off() + S2.on() if bits[2] else S2.off() + S3.on() if bits[3] else S3.off() + + +def main(): + """Scan all channels of the multiplexer to find motors in factory default state, and set them up one by one.""" + config = parse_yaml_config(CONFIG_FILE_PATH) + motor_name_to_id = {m: config.motors[m].id for m in config.motors} + id_to_motor_name = {v: k for k, v in motor_name_to_id.items()} + + print("Starting motor setup...") + current_channel = 0 + while True: + current_channel = (current_channel + 1) % 9 + select_channel(current_channel) + target_id = CHANNEL_TO_ID[current_channel] + target_name = id_to_motor_name[target_id] + if lookup_for_motor( + UART_PORT, FACTORY_DEFAULT_ID, FACTORY_DEFAULT_BAUDRATE, silent=True + ): + print(f"Found motor on channel {current_channel}!") + args = argparse.Namespace( + config_file=CONFIG_FILE_PATH, + motor_name=target_name, + serialport=UART_PORT, + check_only=False, + from_id=FACTORY_DEFAULT_ID, + from_baudrate=FACTORY_DEFAULT_BAUDRATE, + update_config=False, + ) + run(args) + + elif lookup_for_motor(UART_PORT, current_channel + 10, 1000000, silent=True): + print(f"Motor on channel {current_channel} already set up.") + # light_led_up(UART_PORT, current_channel+10, 1000000) + light_led_down(UART_PORT, current_channel + 10, 1000000) + args = argparse.Namespace( + config_file=CONFIG_FILE_PATH, + motor_name=target_name, + serialport=UART_PORT, + check_only=False, + from_id=current_channel + 10, + from_baudrate=1000000, + update_config=False, + ) + run(args) + time.sleep(2) + + time.sleep(0.01) + + +if __name__ == "__main__": + main() diff --git a/reachy_mini/uv.lock b/reachy_mini/uv.lock new file mode 100644 index 0000000000000000000000000000000000000000..fed1adff9e455914f52d524e9fefff4ea32b141f --- /dev/null +++ b/reachy_mini/uv.lock @@ -0,0 +1,3938 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.13'", + "python_full_version >= '3.11' and python_full_version < '3.13'", + "python_full_version < '3.11'", +] + +[[package]] +name = "absl-py" +version = "2.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" }, +] + +[[package]] +name = "ahrs" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/29/1232576b1f6769bf7d1436e5ae5f7234b56bb7bbc255b68a483165090cf3/ahrs-0.4.0.tar.gz", hash = "sha256:4b632b9e53b9cfd1cecadefa543a3534574baeafeef048db703ab33a07dcca21", size = 530456, upload-time = "2025-10-13T11:05:58.675Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/76/931b879e1ad5e287c4ed9b60ccea807e63e06cd257829e154c79394abb66/ahrs-0.4.0-py3-none-any.whl", hash = "sha256:7be83963d8021ae326d20b646c05a2218401e559f645bb5c2e40ff7dd54245d7", size = 244694, upload-time = "2025-10-13T11:05:57.097Z" }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.12.15" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "async-timeout", marker = "python_full_version < '3.11'" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/dc/ef9394bde9080128ad401ac7ede185267ed637df03b51f05d14d1c99ad67/aiohttp-3.12.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b6fc902bff74d9b1879ad55f5404153e2b33a82e72a95c89cec5eb6cc9e92fbc", size = 703921, upload-time = "2025-07-29T05:49:43.584Z" }, + { url = "https://files.pythonhosted.org/packages/8f/42/63fccfc3a7ed97eb6e1a71722396f409c46b60a0552d8a56d7aad74e0df5/aiohttp-3.12.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:098e92835b8119b54c693f2f88a1dec690e20798ca5f5fe5f0520245253ee0af", size = 480288, upload-time = "2025-07-29T05:49:47.851Z" }, + { url = "https://files.pythonhosted.org/packages/9c/a2/7b8a020549f66ea2a68129db6960a762d2393248f1994499f8ba9728bbed/aiohttp-3.12.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:40b3fee496a47c3b4a39a731954c06f0bd9bd3e8258c059a4beb76ac23f8e421", size = 468063, upload-time = "2025-07-29T05:49:49.789Z" }, + { url = "https://files.pythonhosted.org/packages/8f/f5/d11e088da9176e2ad8220338ae0000ed5429a15f3c9dfd983f39105399cd/aiohttp-3.12.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ce13fcfb0bb2f259fb42106cdc63fa5515fb85b7e87177267d89a771a660b79", size = 1650122, upload-time = "2025-07-29T05:49:51.874Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6b/b60ce2757e2faed3d70ed45dafee48cee7bfb878785a9423f7e883f0639c/aiohttp-3.12.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3beb14f053222b391bf9cf92ae82e0171067cc9c8f52453a0f1ec7c37df12a77", size = 1624176, upload-time = "2025-07-29T05:49:53.805Z" }, + { url = "https://files.pythonhosted.org/packages/dd/de/8c9fde2072a1b72c4fadecf4f7d4be7a85b1d9a4ab333d8245694057b4c6/aiohttp-3.12.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c39e87afe48aa3e814cac5f535bc6199180a53e38d3f51c5e2530f5aa4ec58c", size = 1696583, upload-time = "2025-07-29T05:49:55.338Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ad/07f863ca3d895a1ad958a54006c6dafb4f9310f8c2fdb5f961b8529029d3/aiohttp-3.12.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5f1b4ce5bc528a6ee38dbf5f39bbf11dd127048726323b72b8e85769319ffc4", size = 1738896, upload-time = "2025-07-29T05:49:57.045Z" }, + { url = "https://files.pythonhosted.org/packages/20/43/2bd482ebe2b126533e8755a49b128ec4e58f1a3af56879a3abdb7b42c54f/aiohttp-3.12.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1004e67962efabbaf3f03b11b4c43b834081c9e3f9b32b16a7d97d4708a9abe6", size = 1643561, upload-time = "2025-07-29T05:49:58.762Z" }, + { url = "https://files.pythonhosted.org/packages/23/40/2fa9f514c4cf4cbae8d7911927f81a1901838baf5e09a8b2c299de1acfe5/aiohttp-3.12.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8faa08fcc2e411f7ab91d1541d9d597d3a90e9004180edb2072238c085eac8c2", size = 1583685, upload-time = "2025-07-29T05:50:00.375Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c3/94dc7357bc421f4fb978ca72a201a6c604ee90148f1181790c129396ceeb/aiohttp-3.12.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fe086edf38b2222328cdf89af0dde2439ee173b8ad7cb659b4e4c6f385b2be3d", size = 1627533, upload-time = "2025-07-29T05:50:02.306Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3f/1f8911fe1844a07001e26593b5c255a685318943864b27b4e0267e840f95/aiohttp-3.12.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:79b26fe467219add81d5e47b4a4ba0f2394e8b7c7c3198ed36609f9ba161aecb", size = 1638319, upload-time = "2025-07-29T05:50:04.282Z" }, + { url = "https://files.pythonhosted.org/packages/4e/46/27bf57a99168c4e145ffee6b63d0458b9c66e58bb70687c23ad3d2f0bd17/aiohttp-3.12.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b761bac1192ef24e16706d761aefcb581438b34b13a2f069a6d343ec8fb693a5", size = 1613776, upload-time = "2025-07-29T05:50:05.863Z" }, + { url = "https://files.pythonhosted.org/packages/0f/7e/1d2d9061a574584bb4ad3dbdba0da90a27fdc795bc227def3a46186a8bc1/aiohttp-3.12.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e153e8adacfe2af562861b72f8bc47f8a5c08e010ac94eebbe33dc21d677cd5b", size = 1693359, upload-time = "2025-07-29T05:50:07.563Z" }, + { url = "https://files.pythonhosted.org/packages/08/98/bee429b52233c4a391980a5b3b196b060872a13eadd41c3a34be9b1469ed/aiohttp-3.12.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fc49c4de44977aa8601a00edbf157e9a421f227aa7eb477d9e3df48343311065", size = 1716598, upload-time = "2025-07-29T05:50:09.33Z" }, + { url = "https://files.pythonhosted.org/packages/57/39/b0314c1ea774df3392751b686104a3938c63ece2b7ce0ba1ed7c0b4a934f/aiohttp-3.12.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2776c7ec89c54a47029940177e75c8c07c29c66f73464784971d6a81904ce9d1", size = 1644940, upload-time = "2025-07-29T05:50:11.334Z" }, + { url = "https://files.pythonhosted.org/packages/1b/83/3dacb8d3f8f512c8ca43e3fa8a68b20583bd25636ffa4e56ee841ffd79ae/aiohttp-3.12.15-cp310-cp310-win32.whl", hash = "sha256:2c7d81a277fa78b2203ab626ced1487420e8c11a8e373707ab72d189fcdad20a", size = 429239, upload-time = "2025-07-29T05:50:12.803Z" }, + { url = "https://files.pythonhosted.org/packages/eb/f9/470b5daba04d558c9673ca2034f28d067f3202a40e17804425f0c331c89f/aiohttp-3.12.15-cp310-cp310-win_amd64.whl", hash = "sha256:83603f881e11f0f710f8e2327817c82e79431ec976448839f3cd05d7afe8f830", size = 452297, upload-time = "2025-07-29T05:50:14.266Z" }, + { url = "https://files.pythonhosted.org/packages/20/19/9e86722ec8e835959bd97ce8c1efa78cf361fa4531fca372551abcc9cdd6/aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117", size = 711246, upload-time = "2025-07-29T05:50:15.937Z" }, + { url = "https://files.pythonhosted.org/packages/71/f9/0a31fcb1a7d4629ac9d8f01f1cb9242e2f9943f47f5d03215af91c3c1a26/aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe", size = 483515, upload-time = "2025-07-29T05:50:17.442Z" }, + { url = "https://files.pythonhosted.org/packages/62/6c/94846f576f1d11df0c2e41d3001000527c0fdf63fce7e69b3927a731325d/aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9", size = 471776, upload-time = "2025-07-29T05:50:19.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/6c/f766d0aaafcee0447fad0328da780d344489c042e25cd58fde566bf40aed/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5", size = 1741977, upload-time = "2025-07-29T05:50:21.665Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/fb779a05ba6ff44d7bc1e9d24c644e876bfff5abe5454f7b854cace1b9cc/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728", size = 1690645, upload-time = "2025-07-29T05:50:23.333Z" }, + { url = "https://files.pythonhosted.org/packages/37/4e/a22e799c2035f5d6a4ad2cf8e7c1d1bd0923192871dd6e367dafb158b14c/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16", size = 1789437, upload-time = "2025-07-29T05:50:25.007Z" }, + { url = "https://files.pythonhosted.org/packages/28/e5/55a33b991f6433569babb56018b2fb8fb9146424f8b3a0c8ecca80556762/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0", size = 1828482, upload-time = "2025-07-29T05:50:26.693Z" }, + { url = "https://files.pythonhosted.org/packages/c6/82/1ddf0ea4f2f3afe79dffed5e8a246737cff6cbe781887a6a170299e33204/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b", size = 1730944, upload-time = "2025-07-29T05:50:28.382Z" }, + { url = "https://files.pythonhosted.org/packages/1b/96/784c785674117b4cb3877522a177ba1b5e4db9ce0fd519430b5de76eec90/aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd", size = 1668020, upload-time = "2025-07-29T05:50:30.032Z" }, + { url = "https://files.pythonhosted.org/packages/12/8a/8b75f203ea7e5c21c0920d84dd24a5c0e971fe1e9b9ebbf29ae7e8e39790/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8", size = 1716292, upload-time = "2025-07-29T05:50:31.983Z" }, + { url = "https://files.pythonhosted.org/packages/47/0b/a1451543475bb6b86a5cfc27861e52b14085ae232896a2654ff1231c0992/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50", size = 1711451, upload-time = "2025-07-29T05:50:33.989Z" }, + { url = "https://files.pythonhosted.org/packages/55/fd/793a23a197cc2f0d29188805cfc93aa613407f07e5f9da5cd1366afd9d7c/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676", size = 1691634, upload-time = "2025-07-29T05:50:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/ca/bf/23a335a6670b5f5dfc6d268328e55a22651b440fca341a64fccf1eada0c6/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7", size = 1785238, upload-time = "2025-07-29T05:50:37.597Z" }, + { url = "https://files.pythonhosted.org/packages/57/4f/ed60a591839a9d85d40694aba5cef86dde9ee51ce6cca0bb30d6eb1581e7/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7", size = 1805701, upload-time = "2025-07-29T05:50:39.591Z" }, + { url = "https://files.pythonhosted.org/packages/85/e0/444747a9455c5de188c0f4a0173ee701e2e325d4b2550e9af84abb20cdba/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685", size = 1718758, upload-time = "2025-07-29T05:50:41.292Z" }, + { url = "https://files.pythonhosted.org/packages/36/ab/1006278d1ffd13a698e5dd4bfa01e5878f6bddefc296c8b62649753ff249/aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b", size = 428868, upload-time = "2025-07-29T05:50:43.063Z" }, + { url = "https://files.pythonhosted.org/packages/10/97/ad2b18700708452400278039272032170246a1bf8ec5d832772372c71f1a/aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d", size = 453273, upload-time = "2025-07-29T05:50:44.613Z" }, + { url = "https://files.pythonhosted.org/packages/63/97/77cb2450d9b35f517d6cf506256bf4f5bda3f93a66b4ad64ba7fc917899c/aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7", size = 702333, upload-time = "2025-07-29T05:50:46.507Z" }, + { url = "https://files.pythonhosted.org/packages/83/6d/0544e6b08b748682c30b9f65640d006e51f90763b41d7c546693bc22900d/aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444", size = 476948, upload-time = "2025-07-29T05:50:48.067Z" }, + { url = "https://files.pythonhosted.org/packages/3a/1d/c8c40e611e5094330284b1aea8a4b02ca0858f8458614fa35754cab42b9c/aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d", size = 469787, upload-time = "2025-07-29T05:50:49.669Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/b76438e70319796bfff717f325d97ce2e9310f752a267bfdf5192ac6082b/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c", size = 1716590, upload-time = "2025-07-29T05:50:51.368Z" }, + { url = "https://files.pythonhosted.org/packages/79/b1/60370d70cdf8b269ee1444b390cbd72ce514f0d1cd1a715821c784d272c9/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0", size = 1699241, upload-time = "2025-07-29T05:50:53.628Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2b/4968a7b8792437ebc12186db31523f541943e99bda8f30335c482bea6879/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab", size = 1754335, upload-time = "2025-07-29T05:50:55.394Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c1/49524ed553f9a0bec1a11fac09e790f49ff669bcd14164f9fab608831c4d/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb", size = 1800491, upload-time = "2025-07-29T05:50:57.202Z" }, + { url = "https://files.pythonhosted.org/packages/de/5e/3bf5acea47a96a28c121b167f5ef659cf71208b19e52a88cdfa5c37f1fcc/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545", size = 1719929, upload-time = "2025-07-29T05:50:59.192Z" }, + { url = "https://files.pythonhosted.org/packages/39/94/8ae30b806835bcd1cba799ba35347dee6961a11bd507db634516210e91d8/aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c", size = 1635733, upload-time = "2025-07-29T05:51:01.394Z" }, + { url = "https://files.pythonhosted.org/packages/7a/46/06cdef71dd03acd9da7f51ab3a9107318aee12ad38d273f654e4f981583a/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd", size = 1696790, upload-time = "2025-07-29T05:51:03.657Z" }, + { url = "https://files.pythonhosted.org/packages/02/90/6b4cfaaf92ed98d0ec4d173e78b99b4b1a7551250be8937d9d67ecb356b4/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f", size = 1718245, upload-time = "2025-07-29T05:51:05.911Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e6/2593751670fa06f080a846f37f112cbe6f873ba510d070136a6ed46117c6/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d", size = 1658899, upload-time = "2025-07-29T05:51:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/8f/28/c15bacbdb8b8eb5bf39b10680d129ea7410b859e379b03190f02fa104ffd/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519", size = 1738459, upload-time = "2025-07-29T05:51:09.56Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/c269cbc4faa01fb10f143b1670633a8ddd5b2e1ffd0548f7aa49cb5c70e2/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea", size = 1766434, upload-time = "2025-07-29T05:51:11.423Z" }, + { url = "https://files.pythonhosted.org/packages/52/b0/4ff3abd81aa7d929b27d2e1403722a65fc87b763e3a97b3a2a494bfc63bc/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3", size = 1726045, upload-time = "2025-07-29T05:51:13.689Z" }, + { url = "https://files.pythonhosted.org/packages/71/16/949225a6a2dd6efcbd855fbd90cf476052e648fb011aa538e3b15b89a57a/aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1", size = 423591, upload-time = "2025-07-29T05:51:15.452Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d8/fa65d2a349fe938b76d309db1a56a75c4fb8cc7b17a398b698488a939903/aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34", size = 450266, upload-time = "2025-07-29T05:51:17.239Z" }, + { url = "https://files.pythonhosted.org/packages/f2/33/918091abcf102e39d15aba2476ad9e7bd35ddb190dcdd43a854000d3da0d/aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315", size = 696741, upload-time = "2025-07-29T05:51:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2a/7495a81e39a998e400f3ecdd44a62107254803d1681d9189be5c2e4530cd/aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd", size = 474407, upload-time = "2025-07-29T05:51:21.165Z" }, + { url = "https://files.pythonhosted.org/packages/49/fc/a9576ab4be2dcbd0f73ee8675d16c707cfc12d5ee80ccf4015ba543480c9/aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4", size = 466703, upload-time = "2025-07-29T05:51:22.948Z" }, + { url = "https://files.pythonhosted.org/packages/09/2f/d4bcc8448cf536b2b54eed48f19682031ad182faa3a3fee54ebe5b156387/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7", size = 1705532, upload-time = "2025-07-29T05:51:25.211Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f3/59406396083f8b489261e3c011aa8aee9df360a96ac8fa5c2e7e1b8f0466/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d", size = 1686794, upload-time = "2025-07-29T05:51:27.145Z" }, + { url = "https://files.pythonhosted.org/packages/dc/71/164d194993a8d114ee5656c3b7ae9c12ceee7040d076bf7b32fb98a8c5c6/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b", size = 1738865, upload-time = "2025-07-29T05:51:29.366Z" }, + { url = "https://files.pythonhosted.org/packages/1c/00/d198461b699188a93ead39cb458554d9f0f69879b95078dce416d3209b54/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d", size = 1788238, upload-time = "2025-07-29T05:51:31.285Z" }, + { url = "https://files.pythonhosted.org/packages/85/b8/9e7175e1fa0ac8e56baa83bf3c214823ce250d0028955dfb23f43d5e61fd/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d", size = 1710566, upload-time = "2025-07-29T05:51:33.219Z" }, + { url = "https://files.pythonhosted.org/packages/59/e4/16a8eac9df39b48ae102ec030fa9f726d3570732e46ba0c592aeeb507b93/aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645", size = 1624270, upload-time = "2025-07-29T05:51:35.195Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/cd84dee7b6ace0740908fd0af170f9fab50c2a41ccbc3806aabcb1050141/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461", size = 1677294, upload-time = "2025-07-29T05:51:37.215Z" }, + { url = "https://files.pythonhosted.org/packages/ce/42/d0f1f85e50d401eccd12bf85c46ba84f947a84839c8a1c2c5f6e8ab1eb50/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9", size = 1708958, upload-time = "2025-07-29T05:51:39.328Z" }, + { url = "https://files.pythonhosted.org/packages/d5/6b/f6fa6c5790fb602538483aa5a1b86fcbad66244997e5230d88f9412ef24c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d", size = 1651553, upload-time = "2025-07-29T05:51:41.356Z" }, + { url = "https://files.pythonhosted.org/packages/04/36/a6d36ad545fa12e61d11d1932eef273928b0495e6a576eb2af04297fdd3c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693", size = 1727688, upload-time = "2025-07-29T05:51:43.452Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c8/f195e5e06608a97a4e52c5d41c7927301bf757a8e8bb5bbf8cef6c314961/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64", size = 1761157, upload-time = "2025-07-29T05:51:45.643Z" }, + { url = "https://files.pythonhosted.org/packages/05/6a/ea199e61b67f25ba688d3ce93f63b49b0a4e3b3d380f03971b4646412fc6/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51", size = 1710050, upload-time = "2025-07-29T05:51:48.203Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2e/ffeb7f6256b33635c29dbed29a22a723ff2dd7401fff42ea60cf2060abfb/aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0", size = 422647, upload-time = "2025-07-29T05:51:50.718Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8e/78ee35774201f38d5e1ba079c9958f7629b1fd079459aea9467441dbfbf5/aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84", size = 449067, upload-time = "2025-07-29T05:51:52.549Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +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 = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252, upload-time = "2025-08-04T08:54:26.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" }, +] + +[[package]] +name = "asgiref" +version = "3.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/61/0aa957eec22ff70b830b22ff91f825e70e1ef732c06666a805730f28b36b/asgiref-3.9.1.tar.gz", hash = "sha256:a5ab6582236218e5ef1648f242fd9f10626cfd4de8dc377db215d5d5098e3142", size = 36870, upload-time = "2025-07-08T09:07:43.344Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/3c/0464dcada90d5da0e71018c04a140ad6349558afb30b3051b4264cc5b965/asgiref-3.9.1-py3-none-any.whl", hash = "sha256:f3bba7092a48005b5f5bacd747d36ee4a5a61f4a269a6df590b43144355ebd2c", size = 23790, upload-time = "2025-07-08T09:07:41.548Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, +] + +[[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 = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "backports-asyncio-runner" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/98/f3b8013223728a99b908c9344da3aa04ee6e3fa235f19409033eda92fb78/charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72", size = 207695, upload-time = "2025-08-09T07:55:36.452Z" }, + { url = "https://files.pythonhosted.org/packages/21/40/5188be1e3118c82dcb7c2a5ba101b783822cfb413a0268ed3be0468532de/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe", size = 147153, upload-time = "2025-08-09T07:55:38.467Z" }, + { url = "https://files.pythonhosted.org/packages/37/60/5d0d74bc1e1380f0b72c327948d9c2aca14b46a9efd87604e724260f384c/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601", size = 160428, upload-time = "2025-08-09T07:55:40.072Z" }, + { url = "https://files.pythonhosted.org/packages/85/9a/d891f63722d9158688de58d050c59dc3da560ea7f04f4c53e769de5140f5/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c", size = 157627, upload-time = "2025-08-09T07:55:41.706Z" }, + { url = "https://files.pythonhosted.org/packages/65/1a/7425c952944a6521a9cfa7e675343f83fd82085b8af2b1373a2409c683dc/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2", size = 152388, upload-time = "2025-08-09T07:55:43.262Z" }, + { url = "https://files.pythonhosted.org/packages/f0/c9/a2c9c2a355a8594ce2446085e2ec97fd44d323c684ff32042e2a6b718e1d/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0", size = 150077, upload-time = "2025-08-09T07:55:44.903Z" }, + { url = "https://files.pythonhosted.org/packages/3b/38/20a1f44e4851aa1c9105d6e7110c9d020e093dfa5836d712a5f074a12bf7/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0", size = 161631, upload-time = "2025-08-09T07:55:46.346Z" }, + { url = "https://files.pythonhosted.org/packages/a4/fa/384d2c0f57edad03d7bec3ebefb462090d8905b4ff5a2d2525f3bb711fac/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0", size = 159210, upload-time = "2025-08-09T07:55:47.539Z" }, + { url = "https://files.pythonhosted.org/packages/33/9e/eca49d35867ca2db336b6ca27617deed4653b97ebf45dfc21311ce473c37/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a", size = 153739, upload-time = "2025-08-09T07:55:48.744Z" }, + { url = "https://files.pythonhosted.org/packages/2a/91/26c3036e62dfe8de8061182d33be5025e2424002125c9500faff74a6735e/charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f", size = 99825, upload-time = "2025-08-09T07:55:50.305Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/f05db471f81af1fa01839d44ae2a8bfeec8d2a8b4590f16c4e7393afd323/charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669", size = 107452, upload-time = "2025-08-09T07:55:51.461Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b5/991245018615474a60965a7c9cd2b4efbaabd16d582a5547c47ee1c7730b/charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b", size = 204483, upload-time = "2025-08-09T07:55:53.12Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/ae245c41c06299ec18262825c1569c5d3298fc920e4ddf56ab011b417efd/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64", size = 145520, upload-time = "2025-08-09T07:55:54.712Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a4/b3b6c76e7a635748c4421d2b92c7b8f90a432f98bda5082049af37ffc8e3/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91", size = 158876, upload-time = "2025-08-09T07:55:56.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e6/63bb0e10f90a8243c5def74b5b105b3bbbfb3e7bb753915fe333fb0c11ea/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f", size = 156083, upload-time = "2025-08-09T07:55:57.582Z" }, + { url = "https://files.pythonhosted.org/packages/87/df/b7737ff046c974b183ea9aa111b74185ac8c3a326c6262d413bd5a1b8c69/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07", size = 150295, upload-time = "2025-08-09T07:55:59.147Z" }, + { url = "https://files.pythonhosted.org/packages/61/f1/190d9977e0084d3f1dc169acd060d479bbbc71b90bf3e7bf7b9927dec3eb/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30", size = 148379, upload-time = "2025-08-09T07:56:00.364Z" }, + { url = "https://files.pythonhosted.org/packages/4c/92/27dbe365d34c68cfe0ca76f1edd70e8705d82b378cb54ebbaeabc2e3029d/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14", size = 160018, upload-time = "2025-08-09T07:56:01.678Z" }, + { url = "https://files.pythonhosted.org/packages/99/04/baae2a1ea1893a01635d475b9261c889a18fd48393634b6270827869fa34/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c", size = 157430, upload-time = "2025-08-09T07:56:02.87Z" }, + { url = "https://files.pythonhosted.org/packages/2f/36/77da9c6a328c54d17b960c89eccacfab8271fdaaa228305330915b88afa9/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae", size = 151600, upload-time = "2025-08-09T07:56:04.089Z" }, + { url = "https://files.pythonhosted.org/packages/64/d4/9eb4ff2c167edbbf08cdd28e19078bf195762e9bd63371689cab5ecd3d0d/charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849", size = 99616, upload-time = "2025-08-09T07:56:05.658Z" }, + { url = "https://files.pythonhosted.org/packages/f4/9c/996a4a028222e7761a96634d1820de8a744ff4327a00ada9c8942033089b/charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c", size = 107108, upload-time = "2025-08-09T07:56:07.176Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + +[[package]] +name = "cmeel" +version = "0.57.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/ef/0990977bdcb1ffde571f8a0d70c8ad350abe4e398cc09fecabb3e13a8954/cmeel-0.57.3.tar.gz", hash = "sha256:7794a5c3d3365b5ed1db8ab0c152fabfc73af79a3edd6ff8bc2f1405c667dd7f", size = 14884, upload-time = "2025-03-19T15:29:10.298Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/df/634f09c1d2712a6e7b804a5630b0f16f219f6f9c8e1286f3265ca8bdf1ca/cmeel-0.57.3-py3-none-any.whl", hash = "sha256:231d24bb97beae67e3682f026a53e49e227c174e6a3329a9dcb850e5566529b0", size = 20986, upload-time = "2025-03-19T15:29:09.145Z" }, +] + +[[package]] +name = "cmeel-assimp" +version = "5.4.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, + { name = "cmeel-zlib" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/ac/f01a4e8c93e7e76f04788bad60bc5eaf7d4862eef24c11dd38bc8b61e819/cmeel_assimp-5.4.3.1.tar.gz", hash = "sha256:bd663a65ed143e71fe4723e787cbf1480e42cea4d2450c15cb5d9d4223d24f3d", size = 53703174, upload-time = "2025-02-11T15:04:22.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/eb/ed8bdfb61ac66a71f623900a7288b465230f6735120689529846c47131fa/cmeel_assimp-5.4.3.1-0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:cfd834c910402d0a40ec677ec46f2ad25f096f0146faa23b27d9757fa51adb46", size = 10403810, upload-time = "2025-02-11T15:03:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/ca/27/fed4d700c3bb35a86a2e563da3ad2ef26e00fc35da6e152ff82cbd022c97/cmeel_assimp-5.4.3.1-0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9aa68541f68df3ad64c29a1195c154e0a00e33daaf59a5a7ceb1a6f34e69842f", size = 9530204, upload-time = "2025-02-11T15:03:50.44Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f1/085c683b6d2871f6a3ba3c3159d73042231be7e71a63c251b9e919fed1b8/cmeel_assimp-5.4.3.1-0-py3-none-manylinux_2_17_i686.whl", hash = "sha256:673fdeef00e0a018c4b5d21345dca06769b693902a48060bb6b7e53b6b65a0f7", size = 14047356, upload-time = "2025-02-11T15:03:56.314Z" }, + { url = "https://files.pythonhosted.org/packages/8b/85/816c94a00eea68faac68f613f169c0f7023e407b6320193521fccb156e35/cmeel_assimp-5.4.3.1-0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:6be2a9b69a8ccfce575a2b42fb956c0b6c3e3ec2140f63a5cfa194a9d848449d", size = 13367287, upload-time = "2025-02-11T15:03:59.441Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ca/2a90a07d23f0c540fdcc1b5a50e3b424760db880e13bdf246e8b35abfaba/cmeel_assimp-5.4.3.1-0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:ec259b1aad47c3f5b386004570b65b2b06a4d2a4d00b9959469e5528d029b31b", size = 14445192, upload-time = "2025-02-11T15:04:03.823Z" }, + { url = "https://files.pythonhosted.org/packages/72/08/d3c3c5efbcb7039892a79efed07439716107768f261eed7c1bfd01a50f11/cmeel_assimp-5.4.3.1-0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d43933475fb0d76eee49de6b9a6d8e70492a89308afbde4d17ee4666fc15cfc0", size = 13396207, upload-time = "2025-02-11T15:04:08.58Z" }, + { url = "https://files.pythonhosted.org/packages/6a/36/9eef6d28a693ea021186d3456abfe98c5eafb5a9f4b6952b726309550f41/cmeel_assimp-5.4.3.1-0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2a22037a03d8756018c659e06ca2273b51dd1f67f057642df28e6f475cd798a8", size = 14795228, upload-time = "2025-02-11T15:04:12.785Z" }, + { url = "https://files.pythonhosted.org/packages/50/fe/9235a07a66d6d3bc1901360a17ed40b97b0d3904d7cc9f1ac2cc80661bf9/cmeel_assimp-5.4.3.1-0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:2c4ef463d29a30190262c1e48660d07aab744b583f90deccce24c1fecbf442b5", size = 14285514, upload-time = "2025-02-11T15:04:16.198Z" }, +] + +[[package]] +name = "cmeel-boost" +version = "1.87.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/ee/a4c9eff9efe87945b770a3b773630cd72cb5f178de2daec719507e0f6024/cmeel_boost-1.87.0.1.tar.gz", hash = "sha256:c1b706e1f0c878693a96f6c92072596dcdf27bd14833b1cbbffd65a8b7e8d00f", size = 4075, upload-time = "2025-02-13T03:46:52.858Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/9c/f13fd327659b49464cc87b9134d70c7d98d833dabbec3a8e50d8e4867422/cmeel_boost-1.87.0.1-0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8a3a6c1646c6b4cc0b5b7d108b5f83c26b7ec9b0b63b6924e9f3373cca76d8ea", size = 30514323, upload-time = "2025-02-13T03:37:37.054Z" }, + { url = "https://files.pythonhosted.org/packages/d5/39/b5e7b972ac2c80ae98f19af2bb0abbbe7321283b19dbc75c1b2becbf0ea8/cmeel_boost-1.87.0.1-0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6e1b325137363c9dd6b36fd3e21cb3d6386273bc67990b23372c99ccc12648a2", size = 30405820, upload-time = "2025-02-13T03:43:49.338Z" }, + { url = "https://files.pythonhosted.org/packages/e4/71/83db946b7aa223205b104d47bf395e55324ac03ab3593e0c291dd290997b/cmeel_boost-1.87.0.1-0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:33b1c5dd758d0ec32973519c1e3a99fcf492c5d5f0c12ed4b5958b6c74fc72e9", size = 35647645, upload-time = "2025-02-13T03:43:56.397Z" }, + { url = "https://files.pythonhosted.org/packages/23/d3/4a0d6493fa9de78296aa0549ad2b25ea856f93469ddb470c72cf8df62b18/cmeel_boost-1.87.0.1-0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a7939a286ffb85d286f8110678fc6bebf329e2d2c1e8c185735719838288e0ce", size = 35941593, upload-time = "2025-02-13T03:44:03.163Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/bd07149dbbdc9b25f9e1e6028edada2534a053db4075cf230feba6bc5f2f/cmeel_boost-1.87.0.1-0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5a20ae91166381b7eb38b05c315257910f288bcdf36e6a4f13e0c22cfff86557", size = 35983814, upload-time = "2025-02-13T03:44:09.419Z" }, + { url = "https://files.pythonhosted.org/packages/83/29/8cf019d94c17e99987541dfac4fc71125160ba092d66b1534eba38f9c66d/cmeel_boost-1.87.0.1-0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fe63ed4275dfa22f7d23d76074b6e2ef3e02554365a1ba4cf75ebd45e714c4e7", size = 30514344, upload-time = "2025-02-13T03:44:15.034Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5e/9b097f3b07df2f07d280b2ced9a979867df61f719e808293c5e104fc81c0/cmeel_boost-1.87.0.1-0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28d0edd1b49a76563d07b9523fd3d7b37ad54f13644d2507c84e12fc3ba140f5", size = 30405860, upload-time = "2025-02-13T03:44:20.324Z" }, + { url = "https://files.pythonhosted.org/packages/ab/62/d1a88b84e45b3e40009375b43bd103b511899f5070da342a8e71d4d2a12b/cmeel_boost-1.87.0.1-0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e0577a13e99187a66859daa2a873ec5cda852341c27219eb8bbbff6c0be59476", size = 35647178, upload-time = "2025-02-13T03:44:26.095Z" }, + { url = "https://files.pythonhosted.org/packages/9c/75/0b56a0cdfc9e12e1436a24e164f83d4358d89fce73290f32f937e24fbbc2/cmeel_boost-1.87.0.1-0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:4d8f490c3dd7f09a2ff18d8273805371d39efba02ccad711c0417eaba22a5cd8", size = 35941273, upload-time = "2025-02-13T03:44:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/8b/34/5521df709a2337f67a965fd2c5bde52b27c6ccd1a46e54aa8169206ed52a/cmeel_boost-1.87.0.1-0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8309755cf220a7f76cb019253c211a7d40cc98b04258b5979af1125f5f24b2df", size = 35983443, upload-time = "2025-02-13T03:44:39.667Z" }, + { url = "https://files.pythonhosted.org/packages/e8/9e/c53b934ee85485366388d5b3902f92ff4c54ce091058c20a92908e1402dc/cmeel_boost-1.87.0.1-0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8c6ad4bc187152e44caa9f9952c32fa12b3f03d9d6087bff1071c46ee7c84c4", size = 30518387, upload-time = "2025-02-13T03:44:45.267Z" }, + { url = "https://files.pythonhosted.org/packages/f8/7d/751d9fb25f2f29e1bb247c7ddc79cd8d2bc41678a32b413968443c5904eb/cmeel_boost-1.87.0.1-0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ec7a59c722794ddc205b541ed7abe237b72d2fdfdbfe971defbd1920bd58d42e", size = 30407414, upload-time = "2025-02-13T03:44:51.471Z" }, + { url = "https://files.pythonhosted.org/packages/0b/00/5df4db6c596a4da8c8e35c76af79ea8c0d00badee2d64d8baf56659bca79/cmeel_boost-1.87.0.1-0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d3bd5a9855cda2ae8402b487fe028649a50c241e975bce765f33c87dba07324e", size = 35648012, upload-time = "2025-02-13T03:44:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/ca/48/d4145d17b4abede4df4300b49749efe00e00aae4b654b799dc6c4895e177/cmeel_boost-1.87.0.1-0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:fd09a404663bbf610d0a6d786e0ed53a656f2d3dd50b30cf73324b982dd04753", size = 35946214, upload-time = "2025-02-13T03:45:03.378Z" }, + { url = "https://files.pythonhosted.org/packages/ca/10/d405fed8b0157a6fb7100f9dc883d5cd0cdc3840fa0fa652bb5ca7654a5d/cmeel_boost-1.87.0.1-0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bf5bbe225134829ee57b8d3e0941fcc6868f921bf1b00d02ca9456bcf6cd006", size = 35988693, upload-time = "2025-02-13T03:45:09.774Z" }, + { url = "https://files.pythonhosted.org/packages/d3/56/3b9e23dd342bf1f5f141575a5bfbf08fe1577d1d1a14217dc2e757bd3cdd/cmeel_boost-1.87.0.1-0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:3417b8bd016d9e4ddd01afdb7c9cc8fc9806d56e569801b64d90d79a81955727", size = 30518407, upload-time = "2025-02-13T03:45:16.622Z" }, + { url = "https://files.pythonhosted.org/packages/17/0f/d97add23b2f0708cb48d06b4d4cc3c006983491390b84396424b777eb5f5/cmeel_boost-1.87.0.1-0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9193cbb28c4dd5e61f7d0ca472333fb280685ec754813ef15a60bd1bf3ac566f", size = 30407454, upload-time = "2025-02-13T03:45:24.561Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/db157dced18cc57429e4646039e9a54a8d817499666db9984182a30c58e9/cmeel_boost-1.87.0.1-0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:84aa37b8131050f5a291ebf44c9d92bb6f45102a082aad30dcc4e2cc01be250c", size = 35648325, upload-time = "2025-02-13T03:45:30.698Z" }, + { url = "https://files.pythonhosted.org/packages/0d/69/3250e0e3957c36e660bc49add1bdb61f52ab5af32fb0876647b4364f624d/cmeel_boost-1.87.0.1-0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:b947b10632518066b2cd6fae72cbb8e251a15e76dbeef221e99eeeb61d4b50f2", size = 35946299, upload-time = "2025-02-13T03:45:38.901Z" }, + { url = "https://files.pythonhosted.org/packages/62/de/8c12c0ea36ac9c17302289453f2e1f99f679163cf7ccdc5f27e12d18cba4/cmeel_boost-1.87.0.1-0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bcf7c2ef54898cf52bea781907262d86f884f5c26de9e8ce125220e062e83113", size = 35988899, upload-time = "2025-02-13T03:45:45.468Z" }, +] + +[[package]] +name = "cmeel-console-bridge" +version = "1.0.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/13/2e9e9d23db8548aef975564055bdb4fb6da8a397a1e7df8cb61f5afebefb/cmeel_console_bridge-1.0.2.3.tar.gz", hash = "sha256:3b2837da7ab408e9d1a775c83c0a7772356062b3a3672e4ce247f2da71a8ecd9", size = 262061, upload-time = "2025-03-19T18:22:06.845Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/a7/527fa060e5881acb3b0a07bf1d803ccb831cb87739abb62b6bcd14f5aed3/cmeel_console_bridge-1.0.2.3-0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:7aa19b2d006073a1fad55d32968c7d0c7136749e06f98405f4f73a71038a5c41", size = 21341, upload-time = "2025-03-19T18:21:56.834Z" }, + { url = "https://files.pythonhosted.org/packages/bb/db/f8643a8766e8909e0dbfcda6191ca92454cf9a3fadd89be417db261601a1/cmeel_console_bridge-1.0.2.3-0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c47d8c97cb120feed1c01f30845d16c67e4e8205941e3977951018972b9b8721", size = 21286, upload-time = "2025-03-19T18:21:57.984Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b4/9c79177152a220ab2e4ffa0140722165035f6a5c2abbed2912352bd7e7b9/cmeel_console_bridge-1.0.2.3-0-py3-none-manylinux_2_17_i686.whl", hash = "sha256:cad9723ac44ab563cd23bf361b604733623d11847c4edf2a2b4ebd1d984ade09", size = 23740, upload-time = "2025-03-19T18:21:59.683Z" }, + { url = "https://files.pythonhosted.org/packages/92/65/5741de6f550fe701d0780546d97b283306676315a3e1f379a6038e8c0ab0/cmeel_console_bridge-1.0.2.3-0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:372942e9c44f681bfff377fba25b348801283aa6f3826a00e4195089bda9737a", size = 25762, upload-time = "2025-03-19T18:22:01.055Z" }, + { url = "https://files.pythonhosted.org/packages/50/a5/70e23c5570506bb39b56aa4d0f3a4a414e38082ddb33e86a48b546620121/cmeel_console_bridge-1.0.2.3-0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:5bb1115ed38441b2396e732e10ec63d1e68445674f9f5d321f7985eb10e9aeef", size = 24477, upload-time = "2025-03-19T18:22:02.091Z" }, + { url = "https://files.pythonhosted.org/packages/47/36/bfd5a255348902e39243ccc6eba693bce714b891cd3be5603a9bd50c6de5/cmeel_console_bridge-1.0.2.3-0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2b8d084b797f592942208c2040b08e06b82f8832aa6c5e582ba6f1a4a653505b", size = 24970, upload-time = "2025-03-19T18:22:03.075Z" }, + { url = "https://files.pythonhosted.org/packages/b3/02/3ae074e9acb9e150a4d5d97f341c2064573cd5fe9e5af20ab58bf8c0020a/cmeel_console_bridge-1.0.2.3-0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:fb6753a9864217d969c4965389d66a476ac978136c03eadf1063b1619c359220", size = 24689, upload-time = "2025-03-19T18:22:04.084Z" }, + { url = "https://files.pythonhosted.org/packages/69/d0/321f74b7d4167a6c59bb7714a6899ba402d9fad611f62573b9d646107320/cmeel_console_bridge-1.0.2.3-0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9d446c0fc541413d8d2ceea3c1cfb9cbfd57938d6659c113121eca6c245caafe", size = 24404, upload-time = "2025-03-19T18:22:05.232Z" }, +] + +[[package]] +name = "cmeel-octomap" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/89/ab/2fed2dbee13e4b39949591685419f1dbb691295e32a6bbbaf87edc005922/cmeel_octomap-1.10.0.tar.gz", hash = "sha256:bd79d1d17adede534de242e42e13ef0d9f04bdd27daf7d56c57f7c43670c9b05", size = 1694189, upload-time = "2025-01-06T17:57:05.477Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/22/ea67d35df31ec4bb2ed6e594b173c572c72dbd2a87e96906eac67b4af930/cmeel_octomap-1.10.0-4-py3-none-macosx_14_0_arm64.whl", hash = "sha256:c116eb151920d26ee2b2c1f656cd7526862006739817205f11f9366ab0ef6cb4", size = 639956, upload-time = "2025-01-06T17:56:56.826Z" }, + { url = "https://files.pythonhosted.org/packages/b2/da/07725a8c11224881f536ad252e97a3d9801b48e5e776017d5f00fb39b17f/cmeel_octomap-1.10.0-4-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:76cc42553f54bae97584aaf0c7bc33753ff287e2738aa2ecac4820121101dd46", size = 1044402, upload-time = "2025-01-06T17:56:58.553Z" }, + { url = "https://files.pythonhosted.org/packages/a2/15/9617b7039afd6d17d3148f6f970d953f5e265d7736f8fdbca09c86e976a0/cmeel_octomap-1.10.0-4-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:5fdb04546fff3accac5f8626c3fc15c3b99e94ab887793565e0b92cedaf96468", size = 1105037, upload-time = "2025-01-06T17:57:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/51/69/88c1d1eca1abf2387ee8263ac7e12708c8b1b5b70b46a0bd9f43b485165b/cmeel_octomap-1.10.0-4-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:84a7376cfced954bb7e3e347afbd02bdc1c83066b995afbdd0fb1e2d9f57ebec", size = 1108359, upload-time = "2025-01-06T17:57:04.085Z" }, + { url = "https://files.pythonhosted.org/packages/f5/59/57b3b38cf7a382855902b9d24266c283c29d977706438e6b7af62df74e2b/cmeel_octomap-1.10.0-5-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:042b4a21b5e5e19ee78a9a7db78e1b06fb8a287c832031788aec0d3fcabbfecd", size = 748832, upload-time = "2025-02-12T11:57:34.252Z" }, + { url = "https://files.pythonhosted.org/packages/55/8b/f5ec7676808a48c0185e216c0da700e34cb13ba233f13a4557a5ec56324a/cmeel_octomap-1.10.0-5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:79c15a0ece5ca3746170088ef2a377dfb3df8326fafde9bdba688852219758b9", size = 706924, upload-time = "2025-02-12T11:57:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/09/50/56de5a4d9f8ca58100146f16f42c4e2fbb49c0957bfe40d3fd2bc910afe4/cmeel_octomap-1.10.0-5-py3-none-manylinux_2_17_i686.whl", hash = "sha256:e2923bf593ebdafed86b6f3890a122c62fbd9cc9f325d60dbecb72b6b60d78fb", size = 1073973, upload-time = "2025-02-12T11:57:37.914Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f5/8dddf5cdd31176288acd85cc8bf0262b7c3de81d5cb2cb33aa6646f44eb1/cmeel_octomap-1.10.0-5-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:d9e6f9c826905e8de632e9df8cc20e59ce2eb5d1e0b368d8d4abbbc5c0829c1a", size = 1044533, upload-time = "2025-02-12T11:57:39.672Z" }, + { url = "https://files.pythonhosted.org/packages/d6/14/b85bd33bb05c9bb7e87b9ac8401793c12a80a6d594b3ca4bcb5e971a24b7/cmeel_octomap-1.10.0-5-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:b0b54fac180dce4f483afe7029c29cc55f6f2b21be8413e8e2275845b0c204d7", size = 1105199, upload-time = "2025-02-12T11:57:41.286Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/fe3360441159974ebdbb4c013a92ad0425d5f8bf414868d5161060e40660/cmeel_octomap-1.10.0-5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c8691e665bab7c12b6f51e6c5fbbb83ee6f91dce9d15d9d0387553950e7fb5ee", size = 1092962, upload-time = "2025-02-12T11:57:43.297Z" }, + { url = "https://files.pythonhosted.org/packages/82/a6/074166544cc0ce3a5d7844f97dfd13d1b3ec7bff6a6e2cfb18d66a671a7f/cmeel_octomap-1.10.0-5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:735c0ad84dacbbcc8c4237f127c57244c236b7d6c7500b5c45a4c225e19daac1", size = 1083321, upload-time = "2025-02-12T11:57:46.121Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a3/b19ea0d30837369091141b248936b0757ee17f58b809007399bad0b398e4/cmeel_octomap-1.10.0-5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f86a83f6bd60de290cd327f0374d525328369e76591e3ab2ad1bc0b183678c4", size = 1109207, upload-time = "2025-02-12T11:57:48.709Z" }, +] + +[[package]] +name = "cmeel-qhull" +version = "8.0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/dd/8d0bcfb18771b2ea02bf85dfbbc587c97b274496fb5419b72134eb69430b/cmeel_qhull-8.0.2.1.tar.gz", hash = "sha256:68e8d41d95f61830f2d460af1e4d760f0dbe4d46413d7c736f0ed701153ebe52", size = 1308055, upload-time = "2023-11-17T14:21:06.003Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/b4/d72ebd5e9ee711b68ad466e7bd4c0edcb45b0c2c8a358fdcdb64b092666a/cmeel_qhull-8.0.2.1-0-py3-none-macosx_12_0_arm64.whl", hash = "sha256:39f5183a6e026754c3c043239bac005bf1825240d72e1d8fdf090a0f3ea27307", size = 2804225, upload-time = "2023-11-17T14:15:39.958Z" }, + { url = "https://files.pythonhosted.org/packages/29/dc/4bfb8d51a09401cf740e66d10bdb388eacd7c73bae12ef78149cbbc93e83/cmeel_qhull-8.0.2.1-0-py3-none-macosx_12_0_x86_64.whl", hash = "sha256:f135c5a4f4c8ed53f061bc86b794aaca2c0c34761c9269c06b71329c9da56f82", size = 2972481, upload-time = "2023-11-17T14:20:58.418Z" }, + { url = "https://files.pythonhosted.org/packages/0a/7c/74b5c781cbfc8e4a9bb73b71659cc595bc0163223fd700b18133dbcf2831/cmeel_qhull-8.0.2.1-0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:17f519106df79aed9fc5ec92833d4958d132d23021f02a78a9564cdf83a36c7c", size = 3078962, upload-time = "2023-11-17T14:21:00.183Z" }, + { url = "https://files.pythonhosted.org/packages/b4/16/ef7b6201835ba2492753c9c91b266d047b6664507be42ec858e2b24673b5/cmeel_qhull-8.0.2.1-0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:c513abafa40e2b8eb7cd3640e3f92d5391fbd6ec0f4182dbf9536934d8a8ea3e", size = 3194917, upload-time = "2023-11-17T14:21:01.879Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ae/200bdf257507e2c95d0656bf02278cd666d49f0a9e2e6d281ea76d7d085c/cmeel_qhull-8.0.2.1-0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:20a69cb34b6250aee1f018412989734c9ddcad6ff66717a7c5516fc19f55d5ff", size = 3290068, upload-time = "2023-11-17T14:21:03.828Z" }, + { url = "https://files.pythonhosted.org/packages/01/1b/de3fa6091ef58ab40f02653e777c8943acf7cec486184d6007885123571d/cmeel_qhull-8.0.2.1-1-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:b5d47b113c1cb8f519bc813cf015d0d01f8ce5b08912733a24a6018f7caa6e96", size = 2902499, upload-time = "2025-02-12T11:51:16.999Z" }, + { url = "https://files.pythonhosted.org/packages/05/0c/5e5d9a033c683eb272508ccf560c03ac6bf5d397b038fe05f896a2283eaf/cmeel_qhull-8.0.2.1-1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:33a0169f4ee37d093c450195b0ef73d4fe0d9d62abb7899ebe79f778b36e1f36", size = 2773563, upload-time = "2025-02-12T11:51:19.893Z" }, + { url = "https://files.pythonhosted.org/packages/52/9b/00c73069348e60fbbdf6a5a10de046083f7d1ad36844958bbf12163ac688/cmeel_qhull-8.0.2.1-1-py3-none-manylinux_2_17_i686.whl", hash = "sha256:a577e76ac94d128f2966b137ead9f088749513df63749728e2b588f4564b7fdf", size = 3228684, upload-time = "2025-02-12T11:51:21.888Z" }, + { url = "https://files.pythonhosted.org/packages/c0/4a/81b8c88b444935a64d8c83b41e662f696c36dd5937c3ca687113ac4778d0/cmeel_qhull-8.0.2.1-1-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:fd0b2d4ce749b102c3cdead4588249befd34f1a660628f6bfc090ce942925aac", size = 3156051, upload-time = "2025-02-12T11:51:24.594Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c1/44874cd8bfc1e3f7cb15678c836c7a1d5537f34f5a727a0207e01f395598/cmeel_qhull-8.0.2.1-1-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:2371a7c80a14f3e874876359ae3e3094861f081fcdd7a03987c3e880d14e07b9", size = 3262508, upload-time = "2025-02-12T11:51:27.147Z" }, + { url = "https://files.pythonhosted.org/packages/54/0e/425d9ce1f2a831025d39fa5b6479b856bd4d73614c9caa690ac72bbfca04/cmeel_qhull-8.0.2.1-1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:197c14c2006dbeba8f5a5771700a7afea72c1a441aab7cdeaaf10b4ed8c1137d", size = 3172646, upload-time = "2025-02-12T11:51:28.967Z" }, + { url = "https://files.pythonhosted.org/packages/00/c1/e973e287a7d793911b8e6497b17586e601a678f2379ba2c615f72bd76480/cmeel_qhull-8.0.2.1-1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:886d1be24b31842286ae42755af5c312a43a4199632826e4110185ec36dc5c6a", size = 3530837, upload-time = "2025-02-12T11:51:31.651Z" }, + { url = "https://files.pythonhosted.org/packages/fd/65/c6cd54f04b5fcaa4ec52f5b57692c1dcef812ff9ee86545e5607369d365e/cmeel_qhull-8.0.2.1-1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1a49ce7f8492c9a8b49f930e34cce75b5e9b9843b015033dd0a25421441159fc", size = 3301908, upload-time = "2025-02-12T11:51:34.53Z" }, +] + +[[package]] +name = "cmeel-tinyxml2" +version = "10.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/9f/030eca702c485f7a641f975f167fa93164911b3329f005fb0730ff5e793f/cmeel_tinyxml2-10.0.0.tar.gz", hash = "sha256:00252aefc1c94a55b89f25ad08ee79fda2da8d1d94703e051598ddb52a9088fe", size = 645297, upload-time = "2025-02-06T10:29:00.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/5d/bc3a932eb7996a0a789979426a9bb8a3948bf57f3f17bab87dddbef62433/cmeel_tinyxml2-10.0.0-0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:924499bb1b60b9a17bd001d12a9af88ddbee4ca888638ae684ba7f0f3ce49e87", size = 111913, upload-time = "2025-02-06T10:28:45.723Z" }, + { url = "https://files.pythonhosted.org/packages/92/bf/67d11e123313c034712896e94038291fe506bb099bdb75a136392002ffd0/cmeel_tinyxml2-10.0.0-0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:26a1eb30c2a00bfc172e89ed015a18b8efb2b383546252ca8859574aed684686", size = 109487, upload-time = "2025-02-06T10:28:47.546Z" }, + { url = "https://files.pythonhosted.org/packages/ca/48/d8c81ce19b4b278ed0e8f81f93ae8670209bf3a9ac20141b9c386bb40cc7/cmeel_tinyxml2-10.0.0-0-py3-none-manylinux_2_17_i686.whl", hash = "sha256:53d86e02864c712f51f9a9adfcd8b6046b2ed51d44a0c34a8438d93b72b48325", size = 160118, upload-time = "2025-02-06T10:28:49.627Z" }, + { url = "https://files.pythonhosted.org/packages/87/4e/62193e27c9581f8ba7aeaeca7805632a64f2f4a824b1db37ad02ee953e8a/cmeel_tinyxml2-10.0.0-0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:74112e2e9473afbf6ee2d25c9942553e9f6a40465e714533db72db48bc7658e1", size = 158477, upload-time = "2025-02-06T10:28:51.667Z" }, + { url = "https://files.pythonhosted.org/packages/14/f9/d0420c39e9ade99beeec61cd3abc68880fe6e14d85e9df292af8fabe65c8/cmeel_tinyxml2-10.0.0-0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:ecd6e99caa2a06ac0d4b333b740c20fca526d0ca426f99eb5c0a0039117afdb6", size = 147025, upload-time = "2025-02-06T10:28:53.944Z" }, + { url = "https://files.pythonhosted.org/packages/66/9e/df63147fc162ab487217fa5596778ab7a81a82d9b3ce4236fd3a1e48cecb/cmeel_tinyxml2-10.0.0-0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:30993fffb7032a45d5d3b1e5670cb879dad667a13144cd68c8f4e0371a8a3d2e", size = 150958, upload-time = "2025-02-06T10:28:55.301Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a8/b03567275fd83f5af33ddb61de942689dec72c5b21bec01e6a5b11101aa5/cmeel_tinyxml2-10.0.0-0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:8c09ede51784af54211a6225884dc7ddbb02ea1681656d173060c7ad2a5b9a3c", size = 160300, upload-time = "2025-02-06T10:28:57.189Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ec/2781635b66c1059ca1243ae0f5a0410e171a5d8b8a71be3e34cb172f9f2d/cmeel_tinyxml2-10.0.0-0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3bd511d6d0758224efdebc23d3ead6e94f0755b04141ebf7d5493377829e8332", size = 149184, upload-time = "2025-02-06T10:28:58.734Z" }, +] + +[[package]] +name = "cmeel-urdfdom" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, + { name = "cmeel-console-bridge" }, + { name = "cmeel-tinyxml2" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/09/be81a5e7db56f34b6ccdbe7afe855c95a18c8439e173519e0146e9276a8c/cmeel_urdfdom-4.0.1.tar.gz", hash = "sha256:2e3f41e8483889e195b574acb326a4464cf11a3c0a8724031ac28bcda2223efc", size = 291511, upload-time = "2025-02-12T12:07:09.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/d0/20147dd6bb723afc44a58d89ea624df2bad1bed7b898a2df112aaca4a479/cmeel_urdfdom-4.0.1-0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:2fe56939c6b47f6ec57021aac154123da47ecdcd79a217f3a5e3c4b705a07dee", size = 300860, upload-time = "2025-02-12T12:06:58.536Z" }, + { url = "https://files.pythonhosted.org/packages/8e/98/f832bca347e2d987c6b0ebb6930caf7b2c402535324aeed466b6aa2c4513/cmeel_urdfdom-4.0.1-0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:00a0aba78b68c428b27abeed1db58d73e65319ed966911a0e97b37367442e756", size = 300616, upload-time = "2025-02-12T12:07:00.556Z" }, + { url = "https://files.pythonhosted.org/packages/cf/10/bf5765b6f388037cff166a754a0958ac2fee34ca3c0975ef64d0324e4647/cmeel_urdfdom-4.0.1-0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:a701a8f9671331f11b18ecf37a6537db546a21e6a0e5d0ff53341fea0693ed7f", size = 385951, upload-time = "2025-02-12T12:07:02.556Z" }, + { url = "https://files.pythonhosted.org/packages/c3/82/cb3f8f587d293a17bdbea15b50cdaa4a1e28e04583eb4cb4821685b89466/cmeel_urdfdom-4.0.1-0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:12e39fc388c077d79fc9b3841d3d972a1da90b90de754d3363194c1540e18abf", size = 399619, upload-time = "2025-02-12T12:07:04.388Z" }, + { url = "https://files.pythonhosted.org/packages/24/77/322d7ac92c692d8dfaeda9de2d937087d15e2b564dc457d656e5fde3991d/cmeel_urdfdom-4.0.1-0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c4a83925df1d5923c4485c3eb2b80b3a61b14f119ab724fb5bd04cec494690ee", size = 373969, upload-time = "2025-02-12T12:07:06.222Z" }, + { url = "https://files.pythonhosted.org/packages/9f/63/bdc6b55cc8bd99bb9dce6be801b30feffaa1c3841ecb7f4fe4d137424518/cmeel_urdfdom-4.0.1-0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4c4f44270971b3d05c45a4e21b1fb2df7e05a750363ae918f59532bff0bfe0e1", size = 388237, upload-time = "2025-02-12T12:07:08.326Z" }, + { url = "https://files.pythonhosted.org/packages/1d/2d/8463fc23230612daf4da1e31d3229f47708381f3ae4d1500f0f007ac0f92/cmeel_urdfdom-4.0.1-1-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:f7535158f45992eb2ba79e90d9db1bf9adc3846d9c7ed3e7a8c1c4d5343afa37", size = 301006, upload-time = "2025-02-13T11:42:08.8Z" }, + { url = "https://files.pythonhosted.org/packages/0f/d5/c8cdf500e49300d85624cbc3ef804107ddcdc9c541b1d3f726bfb58a9fc1/cmeel_urdfdom-4.0.1-1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fef2a01a00d61d41b3d35dd4958bba973e9025c26eea1d3c9880932f4dba89a5", size = 300758, upload-time = "2025-02-13T11:42:10.449Z" }, + { url = "https://files.pythonhosted.org/packages/cf/b3/2f7bac1544113a7f8e0f6d8b1fab5e75c6a3d27ffbb584b03267251b2165/cmeel_urdfdom-4.0.1-1-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:7a52eb36950ce982014d99a55717ca29985da056e3705f20746f15d3244c1f7a", size = 386043, upload-time = "2025-02-13T11:42:11.923Z" }, + { url = "https://files.pythonhosted.org/packages/86/03/8bdeb36ba6a3e8125d523ecfc010403049e463fe589f9896858d4bdcaf1e/cmeel_urdfdom-4.0.1-1-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:9f3b9c80b10d7246821ff61c2573f799e3da23d483e6f7367ddcad8a48baf58f", size = 399719, upload-time = "2025-02-13T11:42:14.325Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ed/43f99e7512460294cd8acc5753ba25f8a20bdf28d62e143eaf3ec7a28bb6/cmeel_urdfdom-4.0.1-1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2de69f47e8312cc09157624802d5bdaad6406443f863fb4b9ec62a19b4de3c72", size = 374073, upload-time = "2025-02-13T11:42:17.907Z" }, + { url = "https://files.pythonhosted.org/packages/17/c6/2e9bde6d7c02c1cf203ea896f8ce1afd441412f09b44830f1ee4a96d77de/cmeel_urdfdom-4.0.1-1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7708c1402de450fbeab21f7ca264a9a4676ed4c1cdf8d84d840bc5d057aac920", size = 388337, upload-time = "2025-02-13T11:42:19.657Z" }, +] + +[[package]] +name = "cmeel-zlib" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/74/b458f2fbfb652479c06400937cd67022e50d312033221602a9eca75022bc/cmeel_zlib-1.3.1.tar.gz", hash = "sha256:ebb34c54d1b7921dee5e7cd7003c9203b3297a5ba9d93983f1b7d3bb04976c3a", size = 3051, upload-time = "2025-02-11T12:20:39.574Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/dd/1bc2bc50c4ea217a993b2c9d3a7dd5959f839bc2b941556326b1ce71b961/cmeel_zlib-1.3.1-0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:810779922c64d8074a3d12fcc471b1f62255e4402a1ca5f91f5749cc89214b93", size = 268796, upload-time = "2025-02-11T12:20:26.953Z" }, + { url = "https://files.pythonhosted.org/packages/a1/94/cf7e4554b7e2e4348da3f456be3c495774d1972a8dba384b6558b8f0e66b/cmeel_zlib-1.3.1-0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2ccfac8fc80c6ee94ac61a9991f2ac18a5ea3a6cc2e753c221eb7c82729e839d", size = 191024, upload-time = "2025-02-11T12:20:28.737Z" }, + { url = "https://files.pythonhosted.org/packages/a2/cf/92d5a06071326ce3208f6cabc6d07d6c285b415df67e7ea9b87f0b46d44b/cmeel_zlib-1.3.1-0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:f59862cde12d0dcd51fc8f35c408a51e0f279f9d8d9103d5497fe82572e194e4", size = 286338, upload-time = "2025-02-11T12:20:30.784Z" }, + { url = "https://files.pythonhosted.org/packages/21/10/13b53ce0f693085cbad31be9fceb1b6a2b4e3bae5851c1f114c3e7b3c447/cmeel_zlib-1.3.1-0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:7f95b4ed5090fb0fef195f52485f3719dd60213e67a4c07ac4718660bd24da25", size = 282556, upload-time = "2025-02-11T12:20:32.337Z" }, + { url = "https://files.pythonhosted.org/packages/2b/2e/58b295975403b147e5df681e3e3470ba1802feed06a836843f02386d6506/cmeel_zlib-1.3.1-0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2864a55ab1dad1d86749c8410693f3bca6e866cbb5ac16286be686aedb781f6e", size = 287625, upload-time = "2025-02-11T12:20:34.471Z" }, + { url = "https://files.pythonhosted.org/packages/56/f3/4da9d5c5308ef2019ab65a8a9f519ac95004446902d01e859f9ac6b8cdd6/cmeel_zlib-1.3.1-0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e36ac8dccca22ff1f6e4df428ae5597f6288d9e6f85b08c9b767dc63e90fb55", size = 285662, upload-time = "2025-02-11T12:20:37.298Z" }, +] + +[[package]] +name = "coal-library" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, + { name = "cmeel-assimp" }, + { name = "cmeel-boost" }, + { name = "cmeel-octomap" }, + { name = "cmeel-qhull" }, + { name = "eigenpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d0/20/ad159b6d9eb7f4158c7dfa71e335cd89c35288de1ae23be06e24a986a6d0/coal_library-3.0.1.tar.gz", hash = "sha256:40aa6d4e7d6dbe259d3637e697380c8fdec0dcec89886e9cf0cbd36d2a9df2e5", size = 3349502, upload-time = "2025-02-12T19:25:48.349Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/ee/14464beb631396090028267fe4cd167a38ee382bb6f7184961eeb2ab88e7/coal_library-3.0.1-0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9d44f1311f165603eab3f4abc96aed9f5739310305638937fbe6dd5cc563be", size = 4530582, upload-time = "2025-02-12T19:24:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/3a/e3/07c5e05cf2d0f2feef5b9e226f30d11cbca29f5c30173ec8a3fc93f01e59/coal_library-3.0.1-0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e1bdc7575afcdda27a7487af19b7ffc42272fa1859d56f74b40b9512fb23931", size = 4123196, upload-time = "2025-02-12T19:24:41.966Z" }, + { url = "https://files.pythonhosted.org/packages/e6/49/0529dddc58fe7d435d43e50b33852ec5f8121f57e87cce1d7bfce4929a23/coal_library-3.0.1-0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:566a61a913b037e9e6118a42cc1a1170c4b126dec4f13c5628d523e6a93a473a", size = 6388701, upload-time = "2025-02-12T19:24:44.421Z" }, + { url = "https://files.pythonhosted.org/packages/c8/0c/165082211ab7df98ab1aacae6f7354f1b3e6c67cc966ec8ef6ea27c8e229/coal_library-3.0.1-0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c939380c0dc8a3cbb177ddd14c5ddac5f8beeb3d6b8b1e89d4a7d533567532b3", size = 6437127, upload-time = "2025-02-12T19:24:47.545Z" }, + { url = "https://files.pythonhosted.org/packages/c4/fe/8511aba274acbc724678c9b7944cca5c298e038b4c1316e501a4cfca2b0c/coal_library-3.0.1-0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e26cfc2c3953d263cf4c9ba873794e0b79736a5d391fdfababcc161929bf5ed7", size = 4530584, upload-time = "2025-02-12T19:24:53.524Z" }, + { url = "https://files.pythonhosted.org/packages/01/98/8090cc15e4733b14de32f54523f1c2f007b826cbdb0b9a2aa864186cb0b8/coal_library-3.0.1-0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a7ba0b7f51d1e419466b5b1778730547bb8b240fb3f5e373dd9ec9ec372ecb0", size = 4123201, upload-time = "2025-02-12T19:24:55.669Z" }, + { url = "https://files.pythonhosted.org/packages/4b/38/62d5effedab4ad9312e38b91e462b15bca42fbb6a02f2400ef67dbb618eb/coal_library-3.0.1-0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:64129fe9fa2374134a8d18b83051da229ff9987773df7cf0d2a8bd1dbbe6139e", size = 6388488, upload-time = "2025-02-12T19:25:00.058Z" }, + { url = "https://files.pythonhosted.org/packages/68/40/4ae9c8f09532174c49bd152c46efc71f4ee5596236eaef9901ba643b33d5/coal_library-3.0.1-0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a00492012bb43d3386041872cf98d7fdd7cc546a6bb53cba4a478de8c70a0fa4", size = 6436691, upload-time = "2025-02-12T19:25:02.124Z" }, + { url = "https://files.pythonhosted.org/packages/f4/29/469f0b0b086576413e92f68b83bec3ca29b2e0f17c27f2f7c24cd0700d32/coal_library-3.0.1-0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7f0c01e839c455712b540e15d8719ff986e726beed306c7f73424c37021e705", size = 4549472, upload-time = "2025-02-12T19:25:06.779Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d6/d6b2f7256775ec71886d3ffbc3d00bed3594bef23314adaa6e3c23853e5d/coal_library-3.0.1-0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1def214c7aaee3e45dbcdc9049c28096cb945b194b5eb5cad867d5811430255e", size = 4129424, upload-time = "2025-02-12T19:25:08.584Z" }, + { url = "https://files.pythonhosted.org/packages/dd/b5/3014b8f9382539f72ab30f32cd263ee4c885b9926180f79ed7d7853f4a8b/coal_library-3.0.1-0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ad7e8ecd9421b02190a2d4f504d8c53a63f91ab14182deadb508a7e44efba367", size = 6360948, upload-time = "2025-02-12T19:25:12.518Z" }, + { url = "https://files.pythonhosted.org/packages/3f/4c/b8c6c3627f1fe0be7972e38fb50899af8de87745dc8ceb40af82badf185e/coal_library-3.0.1-0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:5701232b34d2c70b622066c8796079ecda9bac77a60044650daed25da77637ef", size = 6421379, upload-time = "2025-02-12T19:25:14.593Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c2/b45fb444004d4026d936297b2c5183fca7c42ad31b1399020ce6c57ba84f/coal_library-3.0.1-0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:8594b26e115d1a78b13db4dbcd2b25e834517734f104decd355d09e3b494d191", size = 4549475, upload-time = "2025-02-12T19:25:17.645Z" }, + { url = "https://files.pythonhosted.org/packages/d8/a9/1c6c3a9d480b8b97c3eafc3c964454f4046d2ea6b780dc0dbc801f9bd41f/coal_library-3.0.1-0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:61a33e9e6d2bd695da718468d0cd3d9b6e20d4dafced90a38b1c17399b3ab73d", size = 4129423, upload-time = "2025-02-12T19:25:21.518Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2a/ba0c897358597b6976aee28e5e849f87ddae132cce04d9e8415003473a0a/coal_library-3.0.1-0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:1013d326633664f3701f91007b9738d8d79465da5a15cd75c65e696304fff366", size = 6360950, upload-time = "2025-02-12T19:25:25.579Z" }, + { url = "https://files.pythonhosted.org/packages/10/f4/615449e99cb23a258a9a9178ea7b56e634b3b1e4b4f07dce79708d3ad245/coal_library-3.0.1-0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:96ce11ffe98215ce6845c435322a1e55297c97f532e0e22ef41e815887d09a41", size = 6421379, upload-time = "2025-02-12T19:25:27.936Z" }, +] + +[[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 = "coloredlogs" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "humanfriendly" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520, upload-time = "2021-06-11T10:22:45.202Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018, upload-time = "2021-06-11T10:22:42.561Z" }, +] + +[[package]] +name = "colorzero" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/ca/688824a06e8c4d04c7d2fd2af2d8da27bed51af20ee5f094154e1d680334/colorzero-2.0.tar.gz", hash = "sha256:e7d5a5c26cd0dc37b164ebefc609f388de24f8593b659191e12d85f8f9d5eb58", size = 25382, upload-time = "2021-03-15T23:42:23.261Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/a6/ddd0f130e44a7593ac6c55aa93f6e256d2270fd88e9d1b64ab7f22ab8fde/colorzero-2.0-py2.py3-none-any.whl", hash = "sha256:0e60d743a6b8071498a56465f7719c96a5e92928f858bab1be2a0d606c9aa0f8", size = 26573, upload-time = "2021-03-15T23:42:21.757Z" }, +] + +[[package]] +name = "commentjson" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lark-parser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/76/c4aa9e408dbacee3f4de8e6c5417e5f55de7e62fb5a50300e1233a2c9cb5/commentjson-0.9.0.tar.gz", hash = "sha256:42f9f231d97d93aff3286a4dc0de39bfd91ae823d1d9eba9fa901fe0c7113dd4", size = 8653, upload-time = "2020-10-05T18:49:06.524Z" } + +[[package]] +name = "cv2-enumerate-cameras" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/e9/1ed371073498f6a4be7cf32dd19605e7fa067497328668a1083e85a3ae71/cv2_enumerate_cameras-1.2.2.tar.gz", hash = "sha256:7dce1335605a4d19fc402c2b3b7d45d5bd80143c20b77be3655f96f30ad76510", size = 11942, upload-time = "2025-07-03T06:05:00.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/37/a198560e077b82092f8d7df438e5c27fc5cc97a721456368f248c6cbf62f/cv2_enumerate_cameras-1.2.2-cp32-abi3-win32.whl", hash = "sha256:5068197f58ec5803da84dd9caa23dd016e09d0c2e6a656d888c5c29abb4ec226", size = 19866, upload-time = "2025-07-03T06:04:56.418Z" }, + { url = "https://files.pythonhosted.org/packages/35/ad/efd8779737ccb88596f9a06f4c46389f4c72aca3696b4b8260d18687d8d6/cv2_enumerate_cameras-1.2.2-cp32-abi3-win_amd64.whl", hash = "sha256:b5c2a765161a4187c5af3dbf2dd4fdf5acd486afde0bda2375eed877852117e5", size = 20751, upload-time = "2025-07-03T06:04:57.513Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d5/be643f4c9542fa07752874820daff2a825c9c67432dfab6853662384385f/cv2_enumerate_cameras-1.2.2-py3-none-any.whl", hash = "sha256:0e54301a65a44a69873f4b4300c37119ae0ed1ea0266d96e1504fcbad678a8d5", size = 11024, upload-time = "2025-07-03T06:04:58.862Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "docutils" +version = "0.22.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/02/111134bfeb6e6c7ac4c74594e39a59f6c0195dc4846afbeac3cba60f1927/docutils-0.22.3.tar.gz", hash = "sha256:21486ae730e4ca9f622677b1412b879af1791efcfba517e4c6f60be543fc8cdd", size = 2290153, upload-time = "2025-11-06T02:35:55.655Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/a8/c6a4b901d17399c77cd81fb001ce8961e9f5e04d3daf27e8925cb012e163/docutils-0.22.3-py3-none-any.whl", hash = "sha256:bd772e4aca73aff037958d44f2be5229ded4c09927fcf8690c577b66234d6ceb", size = 633032, upload-time = "2025-11-06T02:35:52.391Z" }, +] + +[[package]] +name = "eclipse-zenoh" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/59/46/501fa9a336c12a0c6f59a296233e24c00e7f30189d75cb692cab90e0b39f/eclipse_zenoh-1.5.1.tar.gz", hash = "sha256:5525adfe368e548e9a80947dbb930eedb4ae3df139bafc70358306483949b591", size = 126895, upload-time = "2025-09-04T13:53:02.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/63/d3beeb3bc882562bb6ea0a4caecd84a71d88662625bf20949b92371b2046/eclipse_zenoh-1.5.1-cp38-abi3-linux_armv6l.whl", hash = "sha256:c1d494012ef3c693a92980129857a73a4c3f3f0e2af0d0c0274c3615cd48ffda", size = 9084619, upload-time = "2025-09-04T13:52:46.991Z" }, + { url = "https://files.pythonhosted.org/packages/7c/76/05de0c17972dc40adf083a23ea05b094a7ed238cb9f01af926d4f1947b99/eclipse_zenoh-1.5.1-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f124d00868a03640afaa63fdddbf9befc2ea385c83e8944ea62e029363941c4", size = 16904800, upload-time = "2025-09-04T13:52:49.111Z" }, + { url = "https://files.pythonhosted.org/packages/ed/40/6106308e28595cf78bbc3d91fcc389cf6def17b36e5eded29c1db0945e60/eclipse_zenoh-1.5.1-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:5dcaa3a16dd0e8d517c7879f4b1dd6147ba48a15ffd12cc41ecb9b89e618f50b", size = 8652691, upload-time = "2025-09-04T13:52:51.382Z" }, + { url = "https://files.pythonhosted.org/packages/8f/be/2128b27738576d9e80452690682170922cf576e782db8226d9309705bdf2/eclipse_zenoh-1.5.1-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e9f2fc126fce777e12842c4cb62235e854fa6df73afea71c04a28d7471e0b0a", size = 8974218, upload-time = "2025-09-04T13:52:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/d3/fa/4eda37827209c7856d06e6df86f48b53c77291b158baaef4702c90fc3fe7/eclipse_zenoh-1.5.1-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:21239d912c758a0fe3dd8a76454d48f493b169de7795f050cf8045c5d8ea335f", size = 9771132, upload-time = "2025-09-04T13:52:55.008Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4f/a9150d237f6ef71489395127d9c5ddd77fe5fb64864b92e0746eb04dc8a8/eclipse_zenoh-1.5.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76781bbfa61fdc1e9626a03202c7dd8fd103f34761dc7b94b5a2d99f5aae629e", size = 9264787, upload-time = "2025-09-04T13:52:56.761Z" }, + { url = "https://files.pythonhosted.org/packages/a5/1d/9309130f890c6eb783703b5aa2c4718846900f810d123a1228c45416d871/eclipse_zenoh-1.5.1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0f142a36241e50eb3b86f9c3b0149138d2d1d7b6dd2038589fe4c62e12e776ea", size = 9089753, upload-time = "2025-09-04T13:52:59.851Z" }, + { url = "https://files.pythonhosted.org/packages/d4/8a/bec6c2e6fe808afab7e3c7c75eba3e3fa7e549d5028b1bdd7f983cd6d2eb/eclipse_zenoh-1.5.1-cp38-abi3-win_amd64.whl", hash = "sha256:eab374670fa9054e2500060ce33c8248f079208476defa5bb9f9a4b8317d6aac", size = 7581657, upload-time = "2025-09-04T13:53:01.467Z" }, +] + +[[package]] +name = "eigenpy" +version = "3.10.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, + { name = "cmeel-boost" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/d3/ffe0d1b75223013420bf8645aa06e29745366e6f8777e88d78947ef47846/eigenpy-3.10.3.tar.gz", hash = "sha256:95fc73d29ee9d175d8a35484f1cdc79349e54f9b3da5a1a695889c37b0c5d2e4", size = 6529791, upload-time = "2025-02-12T00:19:52.366Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/91/c13f031e420854dfb9d33185423fa7d8ab81bd55340dcfc745182fe0e51e/eigenpy-3.10.3-0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9f8d960640f5c498bbb05ab07d23fd544cc198c18cbc4af624eb17009543fabb", size = 4912581, upload-time = "2025-02-12T00:18:55.012Z" }, + { url = "https://files.pythonhosted.org/packages/82/91/5b74cd05f204f5c63734d0ddf27f3ddf2c7468911c527fe99006f17f55d2/eigenpy-3.10.3-0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6f64b81fbb53a06fca5538b47cbef9b5f6cc7de239e4e8b85456938db568a9b", size = 4256333, upload-time = "2025-02-12T00:18:59.314Z" }, + { url = "https://files.pythonhosted.org/packages/a9/52/b5276d9ce6785595200b442a797c718110d1c5e65a1ed7287b56e5a011d1/eigenpy-3.10.3-0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c585788efef343beb797e4ec2a09e7145f2324aa1bf51847e5729ad6d182bc89", size = 5205940, upload-time = "2025-02-12T00:19:01.838Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/69fc45199bc759b0f686098ddc8a983b6b5784b1cdaa6b2cdab8883d187b/eigenpy-3.10.3-0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:af04ee75774b5e7b3fde4203e15d3fd23de178d70f7a3bdff6fba5a5395ad64a", size = 4939339, upload-time = "2025-02-12T00:19:06.264Z" }, + { url = "https://files.pythonhosted.org/packages/57/b1/08e4a09011cae328c3b00a427b9834b48c75a88bfe34c84d371e1d5870fa/eigenpy-3.10.3-0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d1967cdff87dd49828a41ce0336dfaeb5efb26103d047ddafa35a42dc3cd889a", size = 4912589, upload-time = "2025-02-12T00:19:08.911Z" }, + { url = "https://files.pythonhosted.org/packages/28/3c/6ab509f3765a38f62205505694bba5ed018e1c37047a9d82a32d0b582ae7/eigenpy-3.10.3-0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:12a174ab89aa7608ff33f7ce139846d24250e9402a32c257b917dce8dac082c8", size = 4256296, upload-time = "2025-02-12T00:19:10.633Z" }, + { url = "https://files.pythonhosted.org/packages/02/8a/4a572050d33d959ff8fd9ad9e4f9fbf9c373cdf5b0b25369fc1fe8afce8a/eigenpy-3.10.3-0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b044ec5c1320fa6863b717e302db45220088c3467483fead92ed6effea573982", size = 5205135, upload-time = "2025-02-12T00:19:13.337Z" }, + { url = "https://files.pythonhosted.org/packages/0c/06/f3ddc152d7f453b309547118ff0b92f6b3ab6d40b287240e5726f5e2b7ce/eigenpy-3.10.3-0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:2da3284867d224c067b04f784a1c35ff1350a540556076bffcf39d8b52f7615f", size = 4939523, upload-time = "2025-02-12T00:19:15.224Z" }, + { url = "https://files.pythonhosted.org/packages/f1/de/b96e78da9b94470f984a6dff57a59f09b14020517dd2ff8c85d4cae99f4d/eigenpy-3.10.3-0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c758bd224df13a0e6176162b929aec8026beba01edf416ae34bf86eed6293f50", size = 4901896, upload-time = "2025-02-12T00:19:17.159Z" }, + { url = "https://files.pythonhosted.org/packages/33/36/9a9dd442c6daf6e2a03803766b5ce9675f9015d4aac3dc0c0789b3e941f3/eigenpy-3.10.3-0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9a681e6151e98a67af2b1b30c61686097d3089203ac8627e32ebd68f75627baf", size = 4264524, upload-time = "2025-02-12T00:19:19.715Z" }, + { url = "https://files.pythonhosted.org/packages/d7/06/06b05cce5ba8502206ed0951a15e83f6c015e9a3a3d296dd47effef6c3f9/eigenpy-3.10.3-0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5e00483d44edf961556536f7557dbd84106154cbe84cb1056249c7c2b719e67f", size = 5196136, upload-time = "2025-02-12T00:19:22.457Z" }, + { url = "https://files.pythonhosted.org/packages/93/0c/3efa6ec843e530d07436513972c92c5dc0ed9e2f774ab265b782beb4eeab/eigenpy-3.10.3-0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f151f6fe4f5b575429d69411e12881622b1e76f6fd3805b4081c397fe46cf229", size = 4944229, upload-time = "2025-02-12T00:19:25.356Z" }, + { url = "https://files.pythonhosted.org/packages/ea/25/3299d29624fdc2f8e218756e5823f699209b0a8710d3afecb3f33df2d560/eigenpy-3.10.3-0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:c3874aaef6562d4e482f591b650ed48d6f5a81045a268d6498a4a3506b838893", size = 4901894, upload-time = "2025-02-12T00:19:27.735Z" }, + { url = "https://files.pythonhosted.org/packages/25/34/2283ff0b753528b924b420889a38a37524ed540d8bde63f60fd935139f04/eigenpy-3.10.3-0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e717de8660cee84412832d3f41c3a2769b0cb21f8471bacbde3b6b37cadeeb9", size = 4264518, upload-time = "2025-02-12T00:19:30.417Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d9/8e54eb7e6908a9445c304b4655503ca0b8eb258156c968ceeade3b527a85/eigenpy-3.10.3-0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:d047e63716138ddda51efc7c71c7f7c422489af8585f9f012bd0f31d74c443e2", size = 5196137, upload-time = "2025-02-12T00:19:33.215Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e7/38f1de666adb78de94d2a549bdf4db48d2c447d4d052a3c7e9755d7b71e5/eigenpy-3.10.3-0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ece421651d974a702f99333dec4d2a5b47c2a67bb17913c288fe3bb4bcf99744", size = 4944218, upload-time = "2025-02-12T00:19:35.233Z" }, +] + +[[package]] +name = "eiquadprog" +version = "1.2.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, + { name = "cmeel-boost" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c1/14/3e7fa16567e08e43e6e58aaeba9299977dd0d1c4ac5415e3b9a4a366a64f/eiquadprog-1.2.9.tar.gz", hash = "sha256:7fc82c4c476f636ff1aea4fd3c0baf301b4a6d349a0f3333d1600913d228ca3c", size = 879999, upload-time = "2025-02-17T19:00:17.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/a0/a2bfde96870eb65029ce85a46a74a331e143454640f6d3266536d3d94997/eiquadprog-1.2.9-0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:ffcdb57617894fbd6693aee309f8bc20acb5f810071091b38e22c6c92690dead", size = 102743, upload-time = "2025-02-17T19:00:05.699Z" }, + { url = "https://files.pythonhosted.org/packages/b5/87/63ef7a51df432f4f3a81de5f68c0655c866e86268862d62e6c11eb8c1a8c/eiquadprog-1.2.9-0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:0b88425ca352a9480cca6991303551c9bff5607d3d2d2e31bb2293a06de266ff", size = 90721, upload-time = "2025-02-17T19:00:07.101Z" }, + { url = "https://files.pythonhosted.org/packages/f6/c9/21a8b3630749f418223e7c55e1479652ce3e482f4d070e675245172e01f0/eiquadprog-1.2.9-0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:a45d8e59ffb7512d07ddea261a95beb4a7e13e7bc65b2df3dd5a49f611b79bdb", size = 106935, upload-time = "2025-02-17T19:00:08.931Z" }, + { url = "https://files.pythonhosted.org/packages/4d/cd/c80c605afde9c7f4a369721faea9f4bf61f1b9addcba6f6ad365a00d54cb/eiquadprog-1.2.9-0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:439a1e80a60e09d4483f7937c36a3d114c8c8d0534cb53abb7a55bbea496bb03", size = 112873, upload-time = "2025-02-17T19:00:10.805Z" }, + { url = "https://files.pythonhosted.org/packages/bd/98/63beb8f79f68d15d057ced461573ba733e0404dcc4da5a0b170717433bc8/eiquadprog-1.2.9-0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:95ac0a753ceb6d2e232273cfa6e7a3b868782c6e1d4e4632d8e6279eef64459c", size = 108609, upload-time = "2025-02-17T19:00:12.904Z" }, + { url = "https://files.pythonhosted.org/packages/64/cb/809f0c3e4e7bfe78c6dd468631896a8866c3ba853e3c855cc3fa58fae660/eiquadprog-1.2.9-0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:416f4b584ea30072f166b2a6a3e0a63a2a260a378f9bcbd2dfc9cde13b810a50", size = 118538, upload-time = "2025-02-17T19:00:16.297Z" }, +] + +[[package]] +name = "etils" +version = "1.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/a0/522bbff0f3cdd37968f90dd7f26c7aa801ed87f5ba335f156de7f2b88a48/etils-1.13.0.tar.gz", hash = "sha256:a5b60c71f95bcd2d43d4e9fb3dc3879120c1f60472bb5ce19f7a860b1d44f607", size = 106368, upload-time = "2025-07-15T10:29:10.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/98/87b5946356095738cb90a6df7b35ff69ac5750f6e783d5fbcc5cb3b6cbd7/etils-1.13.0-py3-none-any.whl", hash = "sha256:d9cd4f40fbe77ad6613b7348a18132cc511237b6c076dbb89105c0b520a4c6bb", size = 170603, upload-time = "2025-07-15T10:29:09.076Z" }, +] + +[package.optional-dependencies] +epath = [ + { name = "fsspec" }, + { name = "importlib-resources" }, + { name = "typing-extensions" }, + { name = "zipp" }, +] + +[[package]] +name = "evdev" +version = "1.9.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/fe/a17c106a1f4061ce83f04d14bcedcfb2c38c7793ea56bfb906a6fadae8cb/evdev-1.9.2.tar.gz", hash = "sha256:5d3278892ce1f92a74d6bf888cc8525d9f68af85dbe336c95d1c87fb8f423069", size = 33301, upload-time = "2025-05-01T19:53:47.69Z" } + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "fastapi" +version = "0.116.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, +] + +[[package]] +name = "filelock" +version = "3.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, +] + +[[package]] +name = "flatbuffers" +version = "25.2.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/30/eb5dce7994fc71a2f685d98ec33cc660c0a5887db5610137e60d8cbc4489/flatbuffers-25.2.10.tar.gz", hash = "sha256:97e451377a41262f8d9bd4295cc836133415cc03d8cb966410a4af92eb00d26e", size = 22170, upload-time = "2025-02-11T04:26:46.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/25/155f9f080d5e4bc0082edfda032ea2bc2b8fab3f4d25d46c1e9dd22a1a89/flatbuffers-25.2.10-py2.py3-none-any.whl", hash = "sha256:ebba5f4d5ea615af3f7fd70fc310636fbb2bbd1f566ac0a23d98dd412de50051", size = 30953, upload-time = "2025-02-11T04:26:44.484Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, + { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, + { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, + { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, + { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, + { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, + { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, + { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, + { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, + { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, + { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, + { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, + { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, + { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, + { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, + { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, + { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, + { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, + { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, + { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, + { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, + { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, + { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, + { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, + { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, + { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, + { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, + { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, + { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, + { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, + { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, + { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, + { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, + { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, + { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, + { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, + { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, + { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, + { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, + { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, + { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, + { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, + { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, + { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, + { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, + { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, + { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, + { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, + { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, + { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, + { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, + { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, + { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, + { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, + { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, + { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, + { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, + { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, + { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, + { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, + { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, + { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, + { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, + { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, + { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, + { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, + { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, + { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, + { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, + { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, +] + +[[package]] +name = "fsspec" +version = "2025.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/e0/bab50af11c2d75c9c4a2a26a5254573c0bd97cea152254401510950486fa/fsspec-2025.9.0.tar.gz", hash = "sha256:19fd429483d25d28b65ec68f9f4adc16c17ea2c7c7bf54ec61360d478fb19c19", size = 304847, upload-time = "2025-09-02T19:10:49.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/71/70db47e4f6ce3e5c37a607355f80da8860a33226be640226ac52cb05ef2e/fsspec-2025.9.0-py3-none-any.whl", hash = "sha256:530dc2a2af60a414a832059574df4a6e10cce927f6f4a78209390fe38955cfb7", size = 199289, upload-time = "2025-09-02T19:10:47.708Z" }, +] + +[[package]] +name = "glfw" +version = "2.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/97/a2d667c98b8474f6b8294042488c1bd488681fb3cb4c3b9cdac1a9114287/glfw-2.9.0.tar.gz", hash = "sha256:077111a150ff09bc302c5e4ae265a5eb6aeaff0c8b01f727f7fb34e3764bb8e2", size = 31453, upload-time = "2025-04-15T15:39:54.142Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/71/13dd8a8d547809543d21de9438a3a76a8728fc7966d01ad9fb54599aebf5/glfw-2.9.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-macosx_10_6_intel.whl", hash = "sha256:183da99152f63469e9263146db2eb1b6cc4ee0c4082b280743e57bd1b0a3bd70", size = 105297, upload-time = "2025-04-15T15:39:39.677Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a2/45e6dceec1e0a0ffa8dd3c0ecf1e11d74639a55186243129160c6434d456/glfw-2.9.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-macosx_11_0_arm64.whl", hash = "sha256:aef5b555673b9555216e4cd7bc0bdbbb9983f66c620a85ba7310cfcfda5cd38c", size = 102146, upload-time = "2025-04-15T15:39:42.354Z" }, + { url = "https://files.pythonhosted.org/packages/d2/72/b6261ed918e3747c6070fe80636c63a3c8f1c42ce122670315eeeada156f/glfw-2.9.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-manylinux2014_aarch64.whl", hash = "sha256:fcc430cb21984afba74945b7df38a5e1a02b36c0b4a2a2bab42b4a26d7cc51d6", size = 230002, upload-time = "2025-04-15T15:39:43.933Z" }, + { url = "https://files.pythonhosted.org/packages/45/d6/7f95786332e8b798569b8e60db2ee081874cec2a62572b8ec55c309d85b7/glfw-2.9.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-manylinux2014_x86_64.whl", hash = "sha256:7f85b58546880466ac445fc564c5c831ca93c8a99795ab8eaf0a2d521af293d7", size = 241949, upload-time = "2025-04-15T15:39:45.28Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e6/093ab7874a74bba351e754f6e7748c031bd7276702135da6cbcd00e1f3e2/glfw-2.9.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-manylinux_2_28_aarch64.whl", hash = "sha256:2123716c8086b80b797e849a534fc6f21aebca300519e57c80618a65ca8135dc", size = 231016, upload-time = "2025-04-15T15:39:46.669Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ba/de3630757c7d7fc2086aaf3994926d6b869d31586e4d0c14f1666af31b93/glfw-2.9.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-manylinux_2_28_x86_64.whl", hash = "sha256:4e11271e49eb9bc53431ade022e284d5a59abeace81fe3b178db1bf3ccc0c449", size = 243489, upload-time = "2025-04-15T15:39:48.321Z" }, + { url = "https://files.pythonhosted.org/packages/32/36/c3bada8503681806231d1705ea1802bac8febf69e4186b9f0f0b9e2e4f7e/glfw-2.9.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-win32.whl", hash = "sha256:8e4fbff88e4e953bb969b6813195d5de4641f886530cc8083897e56b00bf2c8e", size = 552655, upload-time = "2025-04-15T15:39:50.029Z" }, + { url = "https://files.pythonhosted.org/packages/cb/70/7f2f052ca20c3b69892818f2ee1fea53b037ea9145ff75b944ed1dc4ff82/glfw-2.9.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-win_amd64.whl", hash = "sha256:9aa3ae51601601c53838315bd2a03efb1e6bebecd072b2f64ddbd0b2556d511a", size = 559441, upload-time = "2025-04-15T15:39:52.531Z" }, +] + +[[package]] +name = "gpiozero" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorzero" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/334b8db8a981eca9a0fb1e7e48e1997a5eaa8f40bb31c504299dcca0e6ff/gpiozero-2.0.1.tar.gz", hash = "sha256:d4ea1952689ec7e331f9d4ebc9adb15f1d01c2c9dcfabb72e752c9869ab7e97e", size = 136176, upload-time = "2024-02-15T11:07:02.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/eb/6518a1b00488d48995034226846653c382d676cf5f04be62b3c3fae2c6a1/gpiozero-2.0.1-py3-none-any.whl", hash = "sha256:8f621de357171d574c0b7ea0e358cb66e560818a47b0eeedf41ce1cdbd20c70b", size = 150818, upload-time = "2024-02-15T11:07:00.451Z" }, +] + +[[package]] +name = "gst-signalling" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pyee" }, + { name = "pygobject" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/77/0c45062d07bb6ad8f940a8a8bc3acd7968cc145be354a566e897d4a6753c/gst_signalling-1.1.2.tar.gz", hash = "sha256:45c7bb3d6801b2704cd4c743130f60d2991b39aa91b6220873ef53ffe9910b98", size = 16467, upload-time = "2025-11-18T13:36:35.935Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/7a/4ac380ce2e7e9ea1e055460648d6c562eb554cdc0dd9b6536b38934b9ef4/gst_signalling-1.1.2-py3-none-any.whl", hash = "sha256:39ebb6eac597933504334d4c1f835abd873cbd42fe31896515e3a0db368db78c", size = 19681, upload-time = "2025-11-18T13:36:34.567Z" }, +] + +[[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 = "hf-xet" +version = "1.1.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/0f/5b60fc28ee7f8cc17a5114a584fd6b86e11c3e0a6e142a7f97a161e9640a/hf_xet-1.1.9.tar.gz", hash = "sha256:c99073ce404462e909f1d5839b2d14a3827b8fe75ed8aed551ba6609c026c803", size = 484242, upload-time = "2025-08-27T23:05:19.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/12/56e1abb9a44cdef59a411fe8a8673313195711b5ecce27880eb9c8fa90bd/hf_xet-1.1.9-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:a3b6215f88638dd7a6ff82cb4e738dcbf3d863bf667997c093a3c990337d1160", size = 2762553, upload-time = "2025-08-27T23:05:15.153Z" }, + { url = "https://files.pythonhosted.org/packages/3a/e6/2d0d16890c5f21b862f5df3146519c182e7f0ae49b4b4bf2bd8a40d0b05e/hf_xet-1.1.9-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:9b486de7a64a66f9a172f4b3e0dfe79c9f0a93257c501296a2521a13495a698a", size = 2623216, upload-time = "2025-08-27T23:05:13.778Z" }, + { url = "https://files.pythonhosted.org/packages/81/42/7e6955cf0621e87491a1fb8cad755d5c2517803cea174229b0ec00ff0166/hf_xet-1.1.9-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4c5a840c2c4e6ec875ed13703a60e3523bc7f48031dfd750923b2a4d1a5fc3c", size = 3186789, upload-time = "2025-08-27T23:05:12.368Z" }, + { url = "https://files.pythonhosted.org/packages/df/8b/759233bce05457f5f7ec062d63bbfd2d0c740b816279eaaa54be92aa452a/hf_xet-1.1.9-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:96a6139c9e44dad1c52c52520db0fffe948f6bce487cfb9d69c125f254bb3790", size = 3088747, upload-time = "2025-08-27T23:05:10.439Z" }, + { url = "https://files.pythonhosted.org/packages/6c/3c/28cc4db153a7601a996985bcb564f7b8f5b9e1a706c7537aad4b4809f358/hf_xet-1.1.9-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ad1022e9a998e784c97b2173965d07fe33ee26e4594770b7785a8cc8f922cd95", size = 3251429, upload-time = "2025-08-27T23:05:16.471Z" }, + { url = "https://files.pythonhosted.org/packages/84/17/7caf27a1d101bfcb05be85850d4aa0a265b2e1acc2d4d52a48026ef1d299/hf_xet-1.1.9-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86754c2d6d5afb11b0a435e6e18911a4199262fe77553f8c50d75e21242193ea", size = 3354643, upload-time = "2025-08-27T23:05:17.828Z" }, + { url = "https://files.pythonhosted.org/packages/cd/50/0c39c9eed3411deadcc98749a6699d871b822473f55fe472fad7c01ec588/hf_xet-1.1.9-cp37-abi3-win_amd64.whl", hash = "sha256:5aad3933de6b725d61d51034e04174ed1dce7a57c63d530df0014dea15a40127", size = 2804797, upload-time = "2025-08-27T23:05:20.77Z" }, +] + +[[package]] +name = "httptools" +version = "0.6.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, + { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, + { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, + { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, + { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, + { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, + { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, + { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, + { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, + { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, + { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, + { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, + { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, + { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, + { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, + { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, + { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, + { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, + { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, + { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, + { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, + { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, + { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, + { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.34.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/c9/bdbe19339f76d12985bc03572f330a01a93c04dffecaaea3061bdd7fb892/huggingface_hub-0.34.4.tar.gz", hash = "sha256:a4228daa6fb001be3f4f4bdaf9a0db00e1739235702848df00885c9b5742c85c", size = 459768, upload-time = "2025-08-08T09:14:52.365Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl", hash = "sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a", size = 561452, upload-time = "2025-08-08T09:14:50.159Z" }, +] + +[[package]] +name = "humanfriendly" +version = "10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyreadline3", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702, upload-time = "2021-09-17T21:40:43.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" }, +] + +[[package]] +name = "identify" +version = "2.6.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/c4/62963f25a678f6a050fb0505a65e9e726996171e6dbe1547f79619eefb15/identify-2.6.14.tar.gz", hash = "sha256:663494103b4f717cb26921c52f8751363dc89db64364cd836a9bf1535f53cd6a", size = 99283, upload-time = "2025-09-06T19:30:52.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/ae/2ad30f4652712c82f1c23423d79136fbce338932ad166d70c1efb86a5998/identify-2.6.14-py2.py3-none-any.whl", hash = "sha256:11a073da82212c6646b1f39bb20d4483bfb9543bd5566fec60053c4bb309bf2e", size = 99172, upload-time = "2025-09-06T19:30:51.759Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "ipython" +version = "8.37.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, + { name = "decorator", marker = "python_full_version < '3.11'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "jedi", marker = "python_full_version < '3.11'" }, + { name = "matplotlib-inline", marker = "python_full_version < '3.11'" }, + { name = "pexpect", marker = "python_full_version < '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit", marker = "python_full_version < '3.11'" }, + { name = "pygments", marker = "python_full_version < '3.11'" }, + { name = "stack-data", marker = "python_full_version < '3.11'" }, + { name = "traitlets", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/31/10ac88f3357fc276dc8a64e8880c82e80e7459326ae1d0a211b40abf6665/ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216", size = 5606088, upload-time = "2025-05-31T16:39:09.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2", size = 831864, upload-time = "2025-05-31T16:39:06.38Z" }, +] + +[[package]] +name = "ipython" +version = "9.5.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13'", + "python_full_version >= '3.11' and python_full_version < '3.13'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, + { name = "decorator", marker = "python_full_version >= '3.11'" }, + { name = "ipython-pygments-lexers", marker = "python_full_version >= '3.11'" }, + { name = "jedi", marker = "python_full_version >= '3.11'" }, + { name = "matplotlib-inline", marker = "python_full_version >= '3.11'" }, + { name = "pexpect", marker = "python_full_version >= '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit", marker = "python_full_version >= '3.11'" }, + { name = "pygments", marker = "python_full_version >= '3.11'" }, + { name = "stack-data", marker = "python_full_version >= '3.11'" }, + { name = "traitlets", marker = "python_full_version >= '3.11'" }, + { name = "typing-extensions", marker = "python_full_version == '3.11.*'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/71/a86262bf5a68bf211bcc71fe302af7e05f18a2852fdc610a854d20d085e6/ipython-9.5.0.tar.gz", hash = "sha256:129c44b941fe6d9b82d36fc7a7c18127ddb1d6f02f78f867f402e2e3adde3113", size = 4389137, upload-time = "2025-08-29T12:15:21.519Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/2a/5628a99d04acb2d2f2e749cdf4ea571d2575e898df0528a090948018b726/ipython-9.5.0-py3-none-any.whl", hash = "sha256:88369ffa1d5817d609120daa523a6da06d02518e582347c29f8451732a9c5e72", size = 612426, upload-time = "2025-08-29T12:15:18.866Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "ischedule" +version = "1.2.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/78/46/0d471c8318050c182badc6b6c3d4d05c1705508de57175e6e316de76e43c/ischedule-1.2.7.tar.gz", hash = "sha256:517ac2c717c8de7e39ded69a86ab974348e5273e466a7ad2af6a096668ff9ba5", size = 7421, upload-time = "2024-03-15T19:13:12.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/0c/937caa3558fa5787927585cce67af4446fec8996d4c28c88d7efdbad6b14/ischedule-1.2.7-py3-none-any.whl", hash = "sha256:2a327e57e3ea179d3d9675cef1e7a0719f2a936c61a9d1ae288c3a5f5156939d", size = 5273, upload-time = "2024-03-15T19:13:09.105Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[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 = "lark-parser" +version = "0.7.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/b8/aa7d6cf2d5efdd2fcd85cf39b33584fe12a0f7086ed451176ceb7fb510eb/lark-parser-0.7.8.tar.gz", hash = "sha256:26215ebb157e6fb2ee74319aa4445b9f3b7e456e26be215ce19fdaaa901c20a4", size = 276204, upload-time = "2019-11-01T12:45:26.558Z" } + +[[package]] +name = "lgpio" +version = "0.2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/33/26ec2e8049eaa2f077bf23a12dc61ca559fbfa7bea0516bf263d657ae275/lgpio-0.2.2.0.tar.gz", hash = "sha256:11372e653b200f76a0b3ef8a23a0735c85ec678a9f8550b9893151ed0f863fff", size = 90087, upload-time = "2024-03-29T21:59:55.901Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/b9/d23f9539bbddf47c01a14fc96158a42d9de454fd9d04f7be1347ca6db8fd/lgpio-0.2.2.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:97fe5fb0e888c96031e8899e8c0eca64c63076a6d1f1e774acad8696430b2ff6", size = 376674, upload-time = "2024-03-29T22:00:41.969Z" }, + { url = "https://files.pythonhosted.org/packages/9c/db/fbbade15dbc9febdbd06bd82531c0a78206f96262003145d6953396d9554/lgpio-0.2.2.0-cp310-cp310-manylinux_2_34_aarch64.whl", hash = "sha256:f8f1a2818ed4293182999679ac8559aea70d45743f5a3ae8025837e529d9e0d4", size = 356711, upload-time = "2024-04-01T22:49:43.455Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ca/1c5278b2548e956a52a07efae91ce2300f81c8cf4ad3d7d6b98ce8987e15/lgpio-0.2.2.0-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:d245f315e4bc5ba1b72df9fd935a16c99e56ccf6b41d9f66a87804c1dfd91c86", size = 362126, upload-time = "2024-04-13T14:08:11.879Z" }, + { url = "https://files.pythonhosted.org/packages/78/4e/5721ae44b29e4fe9175f68c881694e3713066590739a7c87f8cee2835c25/lgpio-0.2.2.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:5b3c403e1fba9c17d178f1bde102726c548fc5c4fc1ccf5ec3e18f3c08e07e04", size = 382992, upload-time = "2024-03-29T22:00:45.039Z" }, + { url = "https://files.pythonhosted.org/packages/88/53/e57a22fe815fc68d0991655c1105b8ed872a68491d32e4e0e7d10ffb5c4d/lgpio-0.2.2.0-cp311-cp311-manylinux_2_34_aarch64.whl", hash = "sha256:a2f71fb95b149d8ac82c7c6bae70f054f6dc42a006ad35c90c7d8e54921fbcf4", size = 364848, upload-time = "2024-04-01T22:49:45.889Z" }, + { url = "https://files.pythonhosted.org/packages/a4/71/11f4e3d76400e4ca43f9f9b014f5a86d9a265340c0bea45cce037277eb34/lgpio-0.2.2.0-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:e9f4f3915abe5ae0ffdb4b96f485076d80a663876d839e2d3fd9218a71b9873e", size = 370183, upload-time = "2024-04-13T14:08:14.139Z" }, + { url = "https://files.pythonhosted.org/packages/fe/73/e56c9afb845df53492d42bdea01df9895272bccfdd5128f34719c3a07990/lgpio-0.2.2.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:6c65ac42e878764d04a71ed12fe6d46089b36e9e8127722bf29bb2e4bc91de22", size = 383956, upload-time = "2024-03-29T22:00:47.315Z" }, + { url = "https://files.pythonhosted.org/packages/3b/1c/becd00f66d2c65feed9a668ff9d91732394cb6baba7bec505d55de0e30c9/lgpio-0.2.2.0-cp312-cp312-manylinux_2_34_aarch64.whl", hash = "sha256:d907db79292c721c605af08187385ddb3b7af09907e1ffca56cf0cd6558ace0a", size = 366058, upload-time = "2024-04-01T22:49:47.615Z" }, + { url = "https://files.pythonhosted.org/packages/4c/7a/e3b4e5225c9792c4092b2cc07504746acbe62d0a8e4cb023bdf65f6430cf/lgpio-0.2.2.0-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:2aadff092f642fcdada8457c158f87259dfda3a89ec19bae0b99ff22b34aac4b", size = 372103, upload-time = "2024-04-13T14:08:16.351Z" }, +] + +[[package]] +name = "libusb-package" +version = "1.0.26.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-resources" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/27/c989cd606683102170c2dc2e89771a22dc71b9d88c4d20c3a97f6d23a0a1/libusb_package-1.0.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ffa01d1db3ef9e7faa62b03f409cd077232885ae3fab6f95912db78035a41db", size = 63863, upload-time = "2025-04-01T12:59:12.09Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e4/663a37d23b3a47a641f74556bb42c04b26c46b95fb8a65c11421cb0ccb0d/libusb_package-1.0.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:95bbf9872674318a23450cd92053eee01683eeae6b6aa76eba30ee5f37c3765b", size = 59502, upload-time = "2025-04-01T12:59:13.489Z" }, + { url = "https://files.pythonhosted.org/packages/a7/93/c99ea3b13539c501c41e605645693346e08cfcb7747025ee640502f7460d/libusb_package-1.0.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36a1c48779c8763fc6bc0331fda668c93b58d55934236d0393d3ec026875f7cd", size = 70247, upload-time = "2025-04-01T14:53:00.28Z" }, + { url = "https://files.pythonhosted.org/packages/2f/c4/84c7af13453e840ba2e3e9f247c9855035077a7214c1f0f273e1df5a845f/libusb_package-1.0.26.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:209efb9a78ac652afc2332b0a63ef2e423202fa3a1bebe5fe3c499e0922afc03", size = 74537, upload-time = "2025-04-01T14:53:01.995Z" }, + { url = "https://files.pythonhosted.org/packages/79/f8/933f70e9a1e05e0d25fb7fb6a5a4512ba7845203b11afc163cfdc98e9b88/libusb_package-1.0.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:433e89dd1f9f9a4149b975247cf1d493170454945fec54b4db9fe61c9e6b861f", size = 70652, upload-time = "2025-04-01T14:53:03.346Z" }, + { url = "https://files.pythonhosted.org/packages/ae/96/77f873c2a3a84b93439a973c70ecc53d2b9ae14cb45b4ba710b89d822228/libusb_package-1.0.26.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7e6fcad72db04b30c8495ac0df6a9b1a4ec8705930bfa2160cc9b018f14101a1", size = 71861, upload-time = "2025-04-01T14:53:04.507Z" }, + { url = "https://files.pythonhosted.org/packages/ba/6e/64f83de4274e4a10ad28a03ff7879d3765c5d7efe0e5c833938318a7de20/libusb_package-1.0.26.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:65ee502c4999ded1c71e38769b0a89152c1e03e43b0d35919f3e32a8cbc7cd99", size = 76476, upload-time = "2025-04-01T14:53:05.511Z" }, + { url = "https://files.pythonhosted.org/packages/ad/56/3792e6a41776d85a4113e75c256879355261b5dd1ed22eb55fd8bc924125/libusb_package-1.0.26.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1f6d012df4942c91e6833dd251bd90c1242496a30c81020e43b98df85c66fa30", size = 71037, upload-time = "2025-04-01T14:53:06.642Z" }, + { url = "https://files.pythonhosted.org/packages/ce/f2/99091fdc38e916cc9e254912d1131496ac56ab82506548f6e1fc2eea8429/libusb_package-1.0.26.3-cp310-cp310-win32.whl", hash = "sha256:55c3988f622745a4874ac4face117da19969b82d51250e5334cd176f516bcb57", size = 77642, upload-time = "2025-04-01T12:58:00.114Z" }, + { url = "https://files.pythonhosted.org/packages/c1/9a/7bc9f60e563e535bf80b125d0d7541ad07ecb0160965d48cb8b6dccc2cf6/libusb_package-1.0.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:ba5e87e70833e5fff977d7bf12b7107df427ee21a8021d59520e1fdf14a32368", size = 90594, upload-time = "2025-04-01T12:58:01.799Z" }, + { url = "https://files.pythonhosted.org/packages/c6/bf/3fe9d322e2dcd0437ae2bd6a039117965702ed473ca59d2d6a1c39838009/libusb_package-1.0.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:60e15d7d3e4aab31794da95641bc28c4ffec9e24f50891ce33f75794b8f531f3", size = 63864, upload-time = "2025-04-01T12:59:14.567Z" }, + { url = "https://files.pythonhosted.org/packages/bc/70/df0348c11e6aaead4a66cc59840e102ddf64baf8e4b2c1ad5cff1ca83554/libusb_package-1.0.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d93a6137609cf72dc5db69bc337ddf96520231e395beeff69fa77a923090003", size = 59502, upload-time = "2025-04-01T12:59:15.863Z" }, + { url = "https://files.pythonhosted.org/packages/27/67/6c84eebc9fcdf7f26704b5d32b51b3ee5bf4e9090d61286941257bdc8702/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fafb69c5fd42b241fbd20493d014328c507d34e1b7ceb883a20ef14565b26898", size = 70247, upload-time = "2025-04-01T14:53:07.606Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/cbcc42ca4b3d8778bf081b96e6e6288a437d82a4cc4e9b982bef40a88856/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c206cd8a30565a0cede3ba426929e70a37e7b769e41a5ac7f00ca6737dc5d", size = 74537, upload-time = "2025-04-01T14:53:08.61Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0f/fd203fb1fa5eda1d446f345d84205f23533767e6ef837a7c77a2599d5783/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a2041331c087d5887969405837f86c8422120fe9ba3e6faa44bf4810f07b71", size = 70653, upload-time = "2025-04-01T14:53:09.576Z" }, + { url = "https://files.pythonhosted.org/packages/79/ef/dcc682cb4b29c4d4cdb23df65825c6276753184f6a7b4338c54a59a54c20/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:48b536a1279ee0dbf70b898cffd16cd661774d2c8bbec8ff7178a5bc20196af3", size = 71859, upload-time = "2025-04-01T14:53:10.987Z" }, + { url = "https://files.pythonhosted.org/packages/62/4d/323d5ac4ba339362e4b148c291fbc6e7ee04c6395d5fec967b32432db5c5/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3f273e33ff1810242f81ea3a0286e25887d99d99019ba83e08be0d1ca456cc05", size = 76476, upload-time = "2025-04-01T14:53:12.019Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3b/506db7f6cbe5dc2f38c14b272b8faf4d43e5559ac99d4dce1a41026ec925/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:67476093601e1ea58a6130426795b906acd8d18d51c84e29a3a69548a5dfcf5d", size = 71037, upload-time = "2025-04-01T14:53:13.42Z" }, + { url = "https://files.pythonhosted.org/packages/3e/40/2538763c06e07bbbe0a5c8830779ef1ed1cea845264a91973bf31b9ecce5/libusb_package-1.0.26.3-cp311-cp311-win32.whl", hash = "sha256:8f3eed2852ee4f08847a221749a98d0f4f3962f8bed967e2253327db1171ba60", size = 77642, upload-time = "2025-04-01T12:58:03.106Z" }, + { url = "https://files.pythonhosted.org/packages/a4/46/0cd5ea91c5bbe6293c0936c96915051e31750f72e9556718af666af3fe45/libusb_package-1.0.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:b48b5f5b17c7ac5e315e233f9ee801f730aac6183eb53a3226b01245d7bcfe00", size = 90592, upload-time = "2025-04-01T12:58:04.103Z" }, + { url = "https://files.pythonhosted.org/packages/2e/f6/83e13936b5799360eae8f0e31b5b298dd092451b91136d7cd13852777954/libusb_package-1.0.26.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c9404298485762a4e73b416e8a3208d33aa3274fb9b870c2a1cacba7e2918f19", size = 62045, upload-time = "2025-04-01T12:59:16.817Z" }, + { url = "https://files.pythonhosted.org/packages/33/97/86ed73880b6734c9383be5f34061b541e8fe5bd0303580b1f5abe2962d58/libusb_package-1.0.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8126f6711318dad4cb2805ea20cd47b895a847207087d8fdb032e082dd7a2e24", size = 59502, upload-time = "2025-04-01T12:59:17.72Z" }, + { url = "https://files.pythonhosted.org/packages/95/f7/27b67b8fe63450abf0b0b66aacf75d5d64cdf30317e214409ceb534f34b4/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11c219366e4a2368117b9a9807261f3506b5623531f8b8ce41af5bbaec8156a0", size = 70247, upload-time = "2025-04-01T14:53:14.387Z" }, + { url = "https://files.pythonhosted.org/packages/8c/11/613543f9c6dab5a82eefd0c78d52d08b5d9eb93a0362151fbedf74b32541/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8809a50d8ab84297344c54e862027090c0d73b14abef843a8b5f783313f49457", size = 74537, upload-time = "2025-04-01T14:53:15.345Z" }, + { url = "https://files.pythonhosted.org/packages/f0/43/5a2331615693b56221a902869fb2094d9a0b9a764a8706c8ba16e915f77c/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a83067c3dfdbb3856badb4532eaea22e8502b52ce4245f5ab46acf93d7fbd471", size = 70652, upload-time = "2025-04-01T14:53:16.319Z" }, + { url = "https://files.pythonhosted.org/packages/44/1a/186d4ec86421b69feb45e214edb5301fbcb9e8dc9df963678aeff1a447d5/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b56be087ea9cde8e50fb02740a4f0cefb6f63c61ac2e7812a9244487614a3973", size = 71860, upload-time = "2025-04-01T14:53:17.87Z" }, + { url = "https://files.pythonhosted.org/packages/4b/3c/8cebdad822d7bfcb683a77d5fd113fbc6f72516cfb7c1c3a274fefafa8e9/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea0f6bf40e54b1671e763e40c9dbed46bf7f596a4cd98b7c827e147f176d8c97", size = 76476, upload-time = "2025-04-01T14:53:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/49/5f/30c625b6c4ecd14871644c1d16e97d7c971f82a0f87a9cfa81022f85bcfc/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b40f77df991c6db8621de9575504886eca03a00277e521a4d64b66cbef8f6997", size = 71037, upload-time = "2025-04-01T14:53:21.359Z" }, + { url = "https://files.pythonhosted.org/packages/7f/e9/3aa3ff3242867b7f22ee3ce28d0e93ff88547f170ca1b8a6edc59660d974/libusb_package-1.0.26.3-cp312-cp312-win32.whl", hash = "sha256:6eee99c9fde137443869c8604d0c01b2127a9545ebc59d06a3376cf1d891e786", size = 77642, upload-time = "2025-04-01T12:58:05.471Z" }, + { url = "https://files.pythonhosted.org/packages/15/0e/913ddb1849f828fc385438874c34541939d9b06c0e5616f48f24cddd24de/libusb_package-1.0.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:5e09c0b6b3cd475841cffe78e46e91df58f0c6c02ea105ea1a4d0755a07c8006", size = 90593, upload-time = "2025-04-01T12:58:06.798Z" }, + { url = "https://files.pythonhosted.org/packages/b4/b8/23bc7f3f53b4a5b1027c721ec3eb42324ca1ec56355f0d0851307adc7c6c/libusb_package-1.0.26.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:04c4505e2ca68d3dc6938f116ff9bf82daffb06c1a97aba08293a84715a998da", size = 62045, upload-time = "2025-04-01T12:59:18.698Z" }, + { url = "https://files.pythonhosted.org/packages/a2/f8/e3be96d0604070488ddc5ce5af1976992e1f4a00e6441c94edf807f274d5/libusb_package-1.0.26.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4961cdb3c622aa9f858d3e4f99a58ce5e822a97c22abc77040fd806cb5fa4c66", size = 59502, upload-time = "2025-04-01T12:59:19.632Z" }, + { url = "https://files.pythonhosted.org/packages/24/d5/df1508df5e6776ac8a09a2858991df29bc96ea6a0d1f90240b1c4d59b45d/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16182670e0c23235521b447054c5a01600bd8f1eed3bb08eedbb0d9f8a43249f", size = 70247, upload-time = "2025-04-01T14:53:22.328Z" }, + { url = "https://files.pythonhosted.org/packages/65/01/4cc9eed12b9214c088cfa8055ece3b1db970404400be9d7e3dda68d198f2/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75ea57b2cc903d28ec1d4b909902df442cbf21949d80d5b3d8b9dac36ac45d1a", size = 74537, upload-time = "2025-04-01T14:53:23.306Z" }, + { url = "https://files.pythonhosted.org/packages/99/83/9eb317f706f588f4b6679bddb8abee3b115ce53dc3fa560cca59910f8807/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d30b51b128ef5112fff73268b4696fea00b5676b3f39a5ee859bd76cb3ace5", size = 70651, upload-time = "2025-04-01T14:53:24.33Z" }, + { url = "https://files.pythonhosted.org/packages/22/49/85d3b307b4a20cf0150ab381e6e0385e5b78cb5dede8bade0a2d655d3fd3/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5c098dcfcfa8000cab42f33e19628c8fdb16111670db381048b2993651f2413b", size = 71860, upload-time = "2025-04-01T14:53:25.752Z" }, + { url = "https://files.pythonhosted.org/packages/da/7a/2271a5ae542d9036d9254415ae745d5c5d01a08d56d13054b2439bf9d392/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:93169aeab0657255fe6c9f757cf408f559db13827a1d122fc89239994d7d51f1", size = 76477, upload-time = "2025-04-01T14:53:27.564Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9d/d06d53994bb164564ec142ef631a4afa31e324994cf223f169ecca127f3a/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:63257653ee1ee06aa836e942f4bb89a1d7a0c6ae3d6183647a9011e585ffa1e3", size = 71036, upload-time = "2025-04-01T14:53:29.011Z" }, + { url = "https://files.pythonhosted.org/packages/32/3d/97f775a1d582548b1eb2a42444c58813e5fd93d568fc3b9ace59f64df527/libusb_package-1.0.26.3-cp313-cp313-win32.whl", hash = "sha256:05db4cc801db2e6373a808725748a701509f9450fecf393fbebab61c45d50b50", size = 77642, upload-time = "2025-04-01T12:58:07.774Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c4/d5234607697ca60593fbef88428a154317ac31f5c58ee23337b8a9360e91/libusb_package-1.0.26.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cd4aec825dac2b4fa5d23b37f6d72e63a1127987e5a073dabeb7b73528623a3", size = 90593, upload-time = "2025-04-01T12:58:08.676Z" }, + { url = "https://files.pythonhosted.org/packages/9f/20/f5293a167b4e910badc64272131a8bb8dbd80f10dfd843eb07846aafaef2/libusb_package-1.0.26.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6a62bf7fa20fe704ed0413e74d620b37bdfe6b084478d23cc85b1f10708f2596", size = 62194, upload-time = "2025-04-01T12:59:26.137Z" }, + { url = "https://files.pythonhosted.org/packages/28/e5/1ceae06e6c965847d89be36de58908354c35faf641cd4c6071c9f06a7e9b/libusb_package-1.0.26.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab40d6b295bcfbe37f280268ea0d0a1ef4b1d795025fe41b3dda48e07eb0fc8e", size = 59506, upload-time = "2025-04-01T12:59:27.081Z" }, + { url = "https://files.pythonhosted.org/packages/6e/74/8afb1a05fda665abebac3bb44a7738f23437cac11081e44a929b51afee6a/libusb_package-1.0.26.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a125d72cca545950ae357aa6d7f0f33dfb39f16b895691cf3f8c9b772bc7e31", size = 70255, upload-time = "2025-04-01T14:53:48.956Z" }, + { url = "https://files.pythonhosted.org/packages/35/46/5e6be05f302e887055a277bbb5cc1db6be9af01319b35f1a9663211b075c/libusb_package-1.0.26.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:229d9f26af5828512828154d6bae4214ef5016a9401dd022477e06d0df5153e7", size = 74543, upload-time = "2025-04-01T14:53:49.979Z" }, + { url = "https://files.pythonhosted.org/packages/16/e4/51a81cc69ba4eefdd9a291cc5e6596a8f7d8c7f2378273917bf64465412d/libusb_package-1.0.26.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b8b862f190c244f29699d783f044e3d816fed84e39bca9a3c3731140f0b1b39", size = 70658, upload-time = "2025-04-01T14:53:51.132Z" }, + { url = "https://files.pythonhosted.org/packages/15/14/2c85379880d475f12ee74a27b02a2ffe435d863f8045fe80e5c246c30f23/libusb_package-1.0.26.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fadaad1181784713948f9cbb7ad1cab8f2b307e784e2e162ed80ba5d2f745901", size = 90602, upload-time = "2025-04-01T12:58:16.828Z" }, +] + +[[package]] +name = "log-throttling" +version = "0.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/be/09fda383d82a7b91f12ff5002bc909e101769c802ff3b1d2cb9f533d1a2f/log-throttling-0.0.3.tar.gz", hash = "sha256:df714e1448cd9cb4c916cf668ab88323032e61ece733548708d996ecf63190b9", size = 3533, upload-time = "2022-03-08T16:29:23.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/6e/995ebad4ab08250b4afe1d91fe3086b863ed9bb74539d90485250a50f08a/log_throttling-0.0.3-py3-none-any.whl", hash = "sha256:a82508f489dd44a60b737a0339c784dd8ee2b9db16bdcf587a8ae1012a7f6ffc", size = 4081, upload-time = "2022-03-08T16:29:21.443Z" }, +] + +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/77/d5/becbe1e2569b474a23f0c672ead8a29ac50b2dc1d5b9de184831bda8d14c/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607", size = 8634365, upload-time = "2025-09-22T04:00:45.672Z" }, + { url = "https://files.pythonhosted.org/packages/28/66/1ced58f12e804644426b85d0bb8a4478ca77bc1761455da310505f1a3526/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938", size = 4650793, upload-time = "2025-09-22T04:00:47.783Z" }, + { url = "https://files.pythonhosted.org/packages/11/84/549098ffea39dfd167e3f174b4ce983d0eed61f9d8d25b7bf2a57c3247fc/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d", size = 4944362, upload-time = "2025-09-22T04:00:49.845Z" }, + { url = "https://files.pythonhosted.org/packages/ac/bd/f207f16abf9749d2037453d56b643a7471d8fde855a231a12d1e095c4f01/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438", size = 5083152, upload-time = "2025-09-22T04:00:51.709Z" }, + { url = "https://files.pythonhosted.org/packages/15/ae/bd813e87d8941d52ad5b65071b1affb48da01c4ed3c9c99e40abb266fbff/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964", size = 5023539, upload-time = "2025-09-22T04:00:53.593Z" }, + { url = "https://files.pythonhosted.org/packages/02/cd/9bfef16bd1d874fbe0cb51afb00329540f30a3283beb9f0780adbb7eec03/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d", size = 5344853, upload-time = "2025-09-22T04:00:55.524Z" }, + { url = "https://files.pythonhosted.org/packages/b8/89/ea8f91594bc5dbb879734d35a6f2b0ad50605d7fb419de2b63d4211765cc/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7", size = 5225133, upload-time = "2025-09-22T04:00:57.269Z" }, + { url = "https://files.pythonhosted.org/packages/b9/37/9c735274f5dbec726b2db99b98a43950395ba3d4a1043083dba2ad814170/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178", size = 4677944, upload-time = "2025-09-22T04:00:59.052Z" }, + { url = "https://files.pythonhosted.org/packages/20/28/7dfe1ba3475d8bfca3878365075abe002e05d40dfaaeb7ec01b4c587d533/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553", size = 5284535, upload-time = "2025-09-22T04:01:01.335Z" }, + { url = "https://files.pythonhosted.org/packages/e7/cf/5f14bc0de763498fc29510e3532bf2b4b3a1c1d5d0dff2e900c16ba021ef/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb", size = 5067343, upload-time = "2025-09-22T04:01:03.13Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b0/bb8275ab5472f32b28cfbbcc6db7c9d092482d3439ca279d8d6fa02f7025/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a", size = 4725419, upload-time = "2025-09-22T04:01:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/25/4c/7c222753bc72edca3b99dbadba1b064209bc8ed4ad448af990e60dcce462/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c", size = 5275008, upload-time = "2025-09-22T04:01:07.327Z" }, + { url = "https://files.pythonhosted.org/packages/6c/8c/478a0dc6b6ed661451379447cdbec77c05741a75736d97e5b2b729687828/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7", size = 5248906, upload-time = "2025-09-22T04:01:09.452Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d9/5be3a6ab2784cdf9accb0703b65e1b64fcdd9311c9f007630c7db0cfcce1/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46", size = 3610357, upload-time = "2025-09-22T04:01:11.102Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7d/ca6fb13349b473d5732fb0ee3eec8f6c80fc0688e76b7d79c1008481bf1f/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078", size = 4036583, upload-time = "2025-09-22T04:01:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a2/51363b5ecd3eab46563645f3a2c3836a2fc67d01a1b87c5017040f39f567/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285", size = 3680591, upload-time = "2025-09-22T04:01:14.874Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, + { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, + { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, + { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, + { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, + { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, + { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, + { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, + { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" }, + { url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" }, + { url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" }, + { url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" }, + { url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" }, + { url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" }, + { url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" }, + { url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" }, + { url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" }, + { url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" }, + { url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" }, + { url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" }, + { url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" }, + { url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" }, + { url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" }, + { url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/0b/11/29d08bc103a62c0eba8016e7ed5aeebbf1e4312e83b0b1648dd203b0e87d/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700", size = 3949829, upload-time = "2025-09-22T04:04:45.608Z" }, + { url = "https://files.pythonhosted.org/packages/12/b3/52ab9a3b31e5ab8238da241baa19eec44d2ab426532441ee607165aebb52/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee", size = 4226277, upload-time = "2025-09-22T04:04:47.754Z" }, + { url = "https://files.pythonhosted.org/packages/a0/33/1eaf780c1baad88224611df13b1c2a9dfa460b526cacfe769103ff50d845/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f", size = 4330433, upload-time = "2025-09-22T04:04:49.907Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c1/27428a2ff348e994ab4f8777d3a0ad510b6b92d37718e5887d2da99952a2/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9", size = 4272119, upload-time = "2025-09-22T04:04:51.801Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d0/3020fa12bcec4ab62f97aab026d57c2f0cfd480a558758d9ca233bb6a79d/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a", size = 4417314, upload-time = "2025-09-22T04:04:55.024Z" }, + { url = "https://files.pythonhosted.org/packages/6c/77/d7f491cbc05303ac6801651aabeb262d43f319288c1ea96c66b1d2692ff3/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e", size = 3518768, upload-time = "2025-09-22T04:04:57.097Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, + { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, + { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, + { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, + { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, + { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, + { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, + { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, + { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, +] + +[[package]] +name = "meshcat" +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipython", version = "8.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "ipython", version = "9.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, + { name = "pillow" }, + { name = "pyngrok" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "u-msgpack-python" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/af/c2/fae203e8e2119d4c793c9d7d2b8d1fea10752bb39b7b330beb8e67b6117c/meshcat-0.3.2.tar.gz", hash = "sha256:2cfe17cde4fe85d072a3de018a9dabf5626f80c255fff2ce63b26a48d2484ad9", size = 611361, upload-time = "2021-11-07T20:31:55.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/c3/5f2b53fd7d43abb8c67015c737569303f39f43aa2b5a4c0add860be5d7e8/meshcat-0.3.2-py3-none-any.whl", hash = "sha256:cba0465d0e29658c48bb65d27f5c8e04ff0a1ac8ce916d65621146c06258a1c7", size = 2640524, upload-time = "2021-11-07T20:31:53.033Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "mujoco" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "etils", extra = ["epath"] }, + { name = "glfw" }, + { name = "numpy" }, + { name = "pyopengl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/c6/76716fd205ccd0afbaef8b355555ace70347bd02c921d14e05e68eab3dbb/mujoco-3.3.0.tar.gz", hash = "sha256:0fb12ab715bc2b6d2394a6330b8c3a1dd95b0f3ba812bfe4f6c91e0a1ca3ad0f", size = 801447, upload-time = "2025-02-27T19:16:18.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/f4/21ff1dc849ff6ab8f2fc29d6d6286ab5e03c25ac7cced3bcbbe052c257be/mujoco-3.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:676285e5a752e5b937fc79ff56cad6d62021992e6800d8085ab316c67d7b0ee4", size = 6484740, upload-time = "2025-02-27T19:14:36.642Z" }, + { url = "https://files.pythonhosted.org/packages/ca/3b/22acd7de2cf66839a3e49b57cc428ab6816764f128209a80578403eac83d/mujoco-3.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6991fe6b255eabf5c62c8a3dffa2e04a51bd74d04de42869c322da1c4279562", size = 6512230, upload-time = "2025-02-27T19:14:40.481Z" }, + { url = "https://files.pythonhosted.org/packages/38/5b/b257c5a6435258a4ce908befa7131b94991ecf95639a58e14daf616d5edd/mujoco-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dd0db1edaabf4a1beccdacfe9c2c313eb47b25bc4016d9a2f97771d0e9dfa89", size = 6261748, upload-time = "2025-02-27T19:14:45.42Z" }, + { url = "https://files.pythonhosted.org/packages/71/75/f9c7fcf11f878213c2bd5af69dd6d73914efe3a60ac031c6e3e305a392db/mujoco-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:946ee6c90c4f6c4ef26502cc8a469b3dc7bd7286d8efb3dc935fa0bf8a3a11e5", size = 6549401, upload-time = "2025-02-27T19:14:49.209Z" }, + { url = "https://files.pythonhosted.org/packages/f4/b3/aec72a24b473394c4f6ed1cc9734f11721dd8eda354c85a768e3e9bf1019/mujoco-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:d84988f3c7e2dc2238a84c565f8c30b7e66caddd9d95b4f0d291902b6af749f3", size = 4835623, upload-time = "2025-02-27T19:14:52.732Z" }, + { url = "https://files.pythonhosted.org/packages/11/aa/a0b20e86e9944fdbdbea004974df1426f4bc532c9711112012e89a56a389/mujoco-3.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:d61157a53356c790ef73d4ec918288c2dd7d0da26eaa1de8f56cffbdcd1ca275", size = 6498398, upload-time = "2025-02-27T19:14:59.241Z" }, + { url = "https://files.pythonhosted.org/packages/b5/12/5a158a125114e35409e60dedeb694bf80d7e3a02c99edc8734ed352baff2/mujoco-3.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:60025a554e444a85d3183714115f48ea4582c5c654f120c5f7652e22260b0069", size = 6524031, upload-time = "2025-02-27T19:15:04.301Z" }, + { url = "https://files.pythonhosted.org/packages/81/85/f7dbcc704710e304cd1220fcdb505e5f0d142c741850efaf33950ab5bc51/mujoco-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff984aaec2006effe12fbb8bc29fbc0abb82b4332891307d99e637791067e912", size = 6276343, upload-time = "2025-02-27T19:15:08.446Z" }, + { url = "https://files.pythonhosted.org/packages/05/9e/a0cd11d0501421d547d74ad0de092912c2e4952b9663f7807e32a9cbcf1b/mujoco-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1403630afb922ab2cb7aa7310b5cb596a5568ee4250f96e663c9f365353cab00", size = 6565173, upload-time = "2025-02-27T19:15:14.112Z" }, + { url = "https://files.pythonhosted.org/packages/03/56/f5d8e2ac2df979044cb18c8862de7be9c2247921f8f7b06d45d3daf99c15/mujoco-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:436d863747fea327393a46f04d7aeaea6acf27b961b54dbdde32a823e90355eb", size = 4860052, upload-time = "2025-02-27T19:15:18.631Z" }, + { url = "https://files.pythonhosted.org/packages/11/6f/218bf9c8480340d640d4f8e09c0295bfd02cc08610bd6798fad12ebc9cc0/mujoco-3.3.0-cp312-cp312-macosx_10_16_x86_64.whl", hash = "sha256:32a7671069799e69f51bf515f6f97d8b2c852a0de065129033347e616fe4e9ed", size = 6588848, upload-time = "2025-02-27T19:15:22.124Z" }, + { url = "https://files.pythonhosted.org/packages/42/3b/f17690dee3f3f3771e9953ffe634d0a1649af44c609c8b201325b9a7fbe6/mujoco-3.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f435f34ea8c41711e68c635ada89c7347e9d53a330c2ff748723a96495d8710", size = 6493393, upload-time = "2025-02-27T19:15:26.398Z" }, + { url = "https://files.pythonhosted.org/packages/db/d5/89feffffdc085a6e3a31eea46a86efdd5a4d3421dacfba742f75e3df3319/mujoco-3.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f526587b05879842e7380feda0a207455e78cdc05c8672c77d292383c145ab7e", size = 6283111, upload-time = "2025-02-27T19:15:30.509Z" }, + { url = "https://files.pythonhosted.org/packages/cc/7b/dfedcfd4a8db4d861747e34e47d96dbcbb994db47b6bd626ed3f25935b81/mujoco-3.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607df8af9e01831d624fc5ffcb6376899fb47c1e999a0e38b8388622da712f64", size = 6639670, upload-time = "2025-02-27T19:15:33.889Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e2/7865204cbe00a2c319bf39a918c975a2cfb931ff2715348a815bdb7b453e/mujoco-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e8811d854a5f4b3340ba11220781427659d5a87ced2d60688e476db8f3f6188", size = 4905647, upload-time = "2025-02-27T19:15:37.421Z" }, + { url = "https://files.pythonhosted.org/packages/26/bc/0ee22fa1451b7e5b6194973c2427e58ddb347b52519ac1ecd75d7040859f/mujoco-3.3.0-cp313-cp313-macosx_10_16_x86_64.whl", hash = "sha256:f4ffdc689319a8d5e692ef19634893d29e2b88fc76b43493a958463047cd9a05", size = 6589087, upload-time = "2025-02-27T19:15:40.84Z" }, + { url = "https://files.pythonhosted.org/packages/d5/14/7c1bd9cfabf757bcb76dcec2b3ab556243450e587aeb639574653305a4e9/mujoco-3.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a748b12f2f39e381770bbf2674ddc4d3c63c74c3c0020efbc98afe712c8e358e", size = 6493094, upload-time = "2025-02-27T19:15:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/98/f0/38d6a12b44d4636afc189c1eb4c95c49bfe4184801dcc3a54ef15382abd5/mujoco-3.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9de3d8d4c17b7831c4e1d760f9b19d4cf4c072014733489ed0a0eed32aad4348", size = 6283044, upload-time = "2025-02-27T19:15:47.815Z" }, + { url = "https://files.pythonhosted.org/packages/57/92/7753403daa094fefcb8ce586a42170d79cd944c7eb466eb99d9220dec124/mujoco-3.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7955b8b0b9803fb41a1a800eb305fd26612cba3d5fa2beda2f886d9816283894", size = 6640054, upload-time = "2025-02-27T19:15:51.942Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9f/48c8dad4b4edae9188e6bf5afdd614c73eb20f65bc9206be01c982564349/mujoco-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:7a0133c7a843e3ad9c48f436b09cd87df934421fbc751283f51eec79647d31e6", size = 4906759, upload-time = "2025-02-27T19:15:56.42Z" }, +] + +[[package]] +name = "multidict" +version = "6.6.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/7f/0652e6ed47ab288e3756ea9c0df8b14950781184d4bd7883f4d87dd41245/multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd", size = 101843, upload-time = "2025-08-11T12:08:48.217Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/6b/86f353088c1358e76fd30b0146947fddecee812703b604ee901e85cd2a80/multidict-6.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8aa6f0bd8125ddd04a6593437bad6a7e70f300ff4180a531654aa2ab3f6d58f", size = 77054, upload-time = "2025-08-11T12:06:02.99Z" }, + { url = "https://files.pythonhosted.org/packages/19/5d/c01dc3d3788bb877bd7f5753ea6eb23c1beeca8044902a8f5bfb54430f63/multidict-6.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9e5853bbd7264baca42ffc53391b490d65fe62849bf2c690fa3f6273dbcd0cb", size = 44914, upload-time = "2025-08-11T12:06:05.264Z" }, + { url = "https://files.pythonhosted.org/packages/46/44/964dae19ea42f7d3e166474d8205f14bb811020e28bc423d46123ddda763/multidict-6.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0af5f9dee472371e36d6ae38bde009bd8ce65ac7335f55dcc240379d7bed1495", size = 44601, upload-time = "2025-08-11T12:06:06.627Z" }, + { url = "https://files.pythonhosted.org/packages/31/20/0616348a1dfb36cb2ab33fc9521de1f27235a397bf3f59338e583afadd17/multidict-6.6.4-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:d24f351e4d759f5054b641c81e8291e5d122af0fca5c72454ff77f7cbe492de8", size = 224821, upload-time = "2025-08-11T12:06:08.06Z" }, + { url = "https://files.pythonhosted.org/packages/14/26/5d8923c69c110ff51861af05bd27ca6783011b96725d59ccae6d9daeb627/multidict-6.6.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db6a3810eec08280a172a6cd541ff4a5f6a97b161d93ec94e6c4018917deb6b7", size = 242608, upload-time = "2025-08-11T12:06:09.697Z" }, + { url = "https://files.pythonhosted.org/packages/5c/cc/e2ad3ba9459aa34fa65cf1f82a5c4a820a2ce615aacfb5143b8817f76504/multidict-6.6.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a1b20a9d56b2d81e2ff52ecc0670d583eaabaa55f402e8d16dd062373dbbe796", size = 222324, upload-time = "2025-08-11T12:06:10.905Z" }, + { url = "https://files.pythonhosted.org/packages/19/db/4ed0f65701afbc2cb0c140d2d02928bb0fe38dd044af76e58ad7c54fd21f/multidict-6.6.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8c9854df0eaa610a23494c32a6f44a3a550fb398b6b51a56e8c6b9b3689578db", size = 253234, upload-time = "2025-08-11T12:06:12.658Z" }, + { url = "https://files.pythonhosted.org/packages/94/c1/5160c9813269e39ae14b73debb907bfaaa1beee1762da8c4fb95df4764ed/multidict-6.6.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4bb7627fd7a968f41905a4d6343b0d63244a0623f006e9ed989fa2b78f4438a0", size = 251613, upload-time = "2025-08-11T12:06:13.97Z" }, + { url = "https://files.pythonhosted.org/packages/05/a9/48d1bd111fc2f8fb98b2ed7f9a115c55a9355358432a19f53c0b74d8425d/multidict-6.6.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caebafea30ed049c57c673d0b36238b1748683be2593965614d7b0e99125c877", size = 241649, upload-time = "2025-08-11T12:06:15.204Z" }, + { url = "https://files.pythonhosted.org/packages/85/2a/f7d743df0019408768af8a70d2037546a2be7b81fbb65f040d76caafd4c5/multidict-6.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ad887a8250eb47d3ab083d2f98db7f48098d13d42eb7a3b67d8a5c795f224ace", size = 239238, upload-time = "2025-08-11T12:06:16.467Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b8/4f4bb13323c2d647323f7919201493cf48ebe7ded971717bfb0f1a79b6bf/multidict-6.6.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ed8358ae7d94ffb7c397cecb62cbac9578a83ecefc1eba27b9090ee910e2efb6", size = 233517, upload-time = "2025-08-11T12:06:18.107Z" }, + { url = "https://files.pythonhosted.org/packages/33/29/4293c26029ebfbba4f574febd2ed01b6f619cfa0d2e344217d53eef34192/multidict-6.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ecab51ad2462197a4c000b6d5701fc8585b80eecb90583635d7e327b7b6923eb", size = 243122, upload-time = "2025-08-11T12:06:19.361Z" }, + { url = "https://files.pythonhosted.org/packages/20/60/a1c53628168aa22447bfde3a8730096ac28086704a0d8c590f3b63388d0c/multidict-6.6.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c5c97aa666cf70e667dfa5af945424ba1329af5dd988a437efeb3a09430389fb", size = 248992, upload-time = "2025-08-11T12:06:20.661Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3b/55443a0c372f33cae5d9ec37a6a973802884fa0ab3586659b197cf8cc5e9/multidict-6.6.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9a950b7cf54099c1209f455ac5970b1ea81410f2af60ed9eb3c3f14f0bfcf987", size = 243708, upload-time = "2025-08-11T12:06:21.891Z" }, + { url = "https://files.pythonhosted.org/packages/7c/60/a18c6900086769312560b2626b18e8cca22d9e85b1186ba77f4755b11266/multidict-6.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:163c7ea522ea9365a8a57832dea7618e6cbdc3cd75f8c627663587459a4e328f", size = 237498, upload-time = "2025-08-11T12:06:23.206Z" }, + { url = "https://files.pythonhosted.org/packages/11/3d/8bdd8bcaff2951ce2affccca107a404925a2beafedd5aef0b5e4a71120a6/multidict-6.6.4-cp310-cp310-win32.whl", hash = "sha256:17d2cbbfa6ff20821396b25890f155f40c986f9cfbce5667759696d83504954f", size = 41415, upload-time = "2025-08-11T12:06:24.77Z" }, + { url = "https://files.pythonhosted.org/packages/c0/53/cab1ad80356a4cd1b685a254b680167059b433b573e53872fab245e9fc95/multidict-6.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:ce9a40fbe52e57e7edf20113a4eaddfacac0561a0879734e636aa6d4bb5e3fb0", size = 46046, upload-time = "2025-08-11T12:06:25.893Z" }, + { url = "https://files.pythonhosted.org/packages/cf/9a/874212b6f5c1c2d870d0a7adc5bb4cfe9b0624fa15cdf5cf757c0f5087ae/multidict-6.6.4-cp310-cp310-win_arm64.whl", hash = "sha256:01d0959807a451fe9fdd4da3e139cb5b77f7328baf2140feeaf233e1d777b729", size = 43147, upload-time = "2025-08-11T12:06:27.534Z" }, + { url = "https://files.pythonhosted.org/packages/6b/7f/90a7f01e2d005d6653c689039977f6856718c75c5579445effb7e60923d1/multidict-6.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c7a0e9b561e6460484318a7612e725df1145d46b0ef57c6b9866441bf6e27e0c", size = 76472, upload-time = "2025-08-11T12:06:29.006Z" }, + { url = "https://files.pythonhosted.org/packages/54/a3/bed07bc9e2bb302ce752f1dabc69e884cd6a676da44fb0e501b246031fdd/multidict-6.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6bf2f10f70acc7a2446965ffbc726e5fc0b272c97a90b485857e5c70022213eb", size = 44634, upload-time = "2025-08-11T12:06:30.374Z" }, + { url = "https://files.pythonhosted.org/packages/a7/4b/ceeb4f8f33cf81277da464307afeaf164fb0297947642585884f5cad4f28/multidict-6.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66247d72ed62d5dd29752ffc1d3b88f135c6a8de8b5f63b7c14e973ef5bda19e", size = 44282, upload-time = "2025-08-11T12:06:31.958Z" }, + { url = "https://files.pythonhosted.org/packages/03/35/436a5da8702b06866189b69f655ffdb8f70796252a8772a77815f1812679/multidict-6.6.4-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:105245cc6b76f51e408451a844a54e6823bbd5a490ebfe5bdfc79798511ceded", size = 229696, upload-time = "2025-08-11T12:06:33.087Z" }, + { url = "https://files.pythonhosted.org/packages/b6/0e/915160be8fecf1fca35f790c08fb74ca684d752fcba62c11daaf3d92c216/multidict-6.6.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cbbc54e58b34c3bae389ef00046be0961f30fef7cb0dd9c7756aee376a4f7683", size = 246665, upload-time = "2025-08-11T12:06:34.448Z" }, + { url = "https://files.pythonhosted.org/packages/08/ee/2f464330acd83f77dcc346f0b1a0eaae10230291450887f96b204b8ac4d3/multidict-6.6.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:56c6b3652f945c9bc3ac6c8178cd93132b8d82dd581fcbc3a00676c51302bc1a", size = 225485, upload-time = "2025-08-11T12:06:35.672Z" }, + { url = "https://files.pythonhosted.org/packages/71/cc/9a117f828b4d7fbaec6adeed2204f211e9caf0a012692a1ee32169f846ae/multidict-6.6.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b95494daf857602eccf4c18ca33337dd2be705bccdb6dddbfc9d513e6addb9d9", size = 257318, upload-time = "2025-08-11T12:06:36.98Z" }, + { url = "https://files.pythonhosted.org/packages/25/77/62752d3dbd70e27fdd68e86626c1ae6bccfebe2bb1f84ae226363e112f5a/multidict-6.6.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e5b1413361cef15340ab9dc61523e653d25723e82d488ef7d60a12878227ed50", size = 254689, upload-time = "2025-08-11T12:06:38.233Z" }, + { url = "https://files.pythonhosted.org/packages/00/6e/fac58b1072a6fc59af5e7acb245e8754d3e1f97f4f808a6559951f72a0d4/multidict-6.6.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e167bf899c3d724f9662ef00b4f7fef87a19c22b2fead198a6f68b263618df52", size = 246709, upload-time = "2025-08-11T12:06:39.517Z" }, + { url = "https://files.pythonhosted.org/packages/01/ef/4698d6842ef5e797c6db7744b0081e36fb5de3d00002cc4c58071097fac3/multidict-6.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aaea28ba20a9026dfa77f4b80369e51cb767c61e33a2d4043399c67bd95fb7c6", size = 243185, upload-time = "2025-08-11T12:06:40.796Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c9/d82e95ae1d6e4ef396934e9b0e942dfc428775f9554acf04393cce66b157/multidict-6.6.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8c91cdb30809a96d9ecf442ec9bc45e8cfaa0f7f8bdf534e082c2443a196727e", size = 237838, upload-time = "2025-08-11T12:06:42.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/cf/f94af5c36baaa75d44fab9f02e2a6bcfa0cd90acb44d4976a80960759dbc/multidict-6.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a0ccbfe93ca114c5d65a2471d52d8829e56d467c97b0e341cf5ee45410033b3", size = 246368, upload-time = "2025-08-11T12:06:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/4a/fe/29f23460c3d995f6a4b678cb2e9730e7277231b981f0b234702f0177818a/multidict-6.6.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:55624b3f321d84c403cb7d8e6e982f41ae233d85f85db54ba6286f7295dc8a9c", size = 253339, upload-time = "2025-08-11T12:06:45.597Z" }, + { url = "https://files.pythonhosted.org/packages/29/b6/fd59449204426187b82bf8a75f629310f68c6adc9559dc922d5abe34797b/multidict-6.6.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4a1fb393a2c9d202cb766c76208bd7945bc194eba8ac920ce98c6e458f0b524b", size = 246933, upload-time = "2025-08-11T12:06:46.841Z" }, + { url = "https://files.pythonhosted.org/packages/19/52/d5d6b344f176a5ac3606f7a61fb44dc746e04550e1a13834dff722b8d7d6/multidict-6.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:43868297a5759a845fa3a483fb4392973a95fb1de891605a3728130c52b8f40f", size = 242225, upload-time = "2025-08-11T12:06:48.588Z" }, + { url = "https://files.pythonhosted.org/packages/ec/d3/5b2281ed89ff4d5318d82478a2a2450fcdfc3300da48ff15c1778280ad26/multidict-6.6.4-cp311-cp311-win32.whl", hash = "sha256:ed3b94c5e362a8a84d69642dbeac615452e8af9b8eb825b7bc9f31a53a1051e2", size = 41306, upload-time = "2025-08-11T12:06:49.95Z" }, + { url = "https://files.pythonhosted.org/packages/74/7d/36b045c23a1ab98507aefd44fd8b264ee1dd5e5010543c6fccf82141ccef/multidict-6.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:d8c112f7a90d8ca5d20213aa41eac690bb50a76da153e3afb3886418e61cb22e", size = 46029, upload-time = "2025-08-11T12:06:51.082Z" }, + { url = "https://files.pythonhosted.org/packages/0f/5e/553d67d24432c5cd52b49047f2d248821843743ee6d29a704594f656d182/multidict-6.6.4-cp311-cp311-win_arm64.whl", hash = "sha256:3bb0eae408fa1996d87247ca0d6a57b7fc1dcf83e8a5c47ab82c558c250d4adf", size = 43017, upload-time = "2025-08-11T12:06:52.243Z" }, + { url = "https://files.pythonhosted.org/packages/05/f6/512ffd8fd8b37fb2680e5ac35d788f1d71bbaf37789d21a820bdc441e565/multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8", size = 76516, upload-time = "2025-08-11T12:06:53.393Z" }, + { url = "https://files.pythonhosted.org/packages/99/58/45c3e75deb8855c36bd66cc1658007589662ba584dbf423d01df478dd1c5/multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3", size = 45394, upload-time = "2025-08-11T12:06:54.555Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/e8c4472a93a26e4507c0b8e1f0762c0d8a32de1328ef72fd704ef9cc5447/multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b", size = 43591, upload-time = "2025-08-11T12:06:55.672Z" }, + { url = "https://files.pythonhosted.org/packages/05/51/edf414f4df058574a7265034d04c935aa84a89e79ce90fcf4df211f47b16/multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287", size = 237215, upload-time = "2025-08-11T12:06:57.213Z" }, + { url = "https://files.pythonhosted.org/packages/c8/45/8b3d6dbad8cf3252553cc41abea09ad527b33ce47a5e199072620b296902/multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138", size = 258299, upload-time = "2025-08-11T12:06:58.946Z" }, + { url = "https://files.pythonhosted.org/packages/3c/e8/8ca2e9a9f5a435fc6db40438a55730a4bf4956b554e487fa1b9ae920f825/multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6", size = 242357, upload-time = "2025-08-11T12:07:00.301Z" }, + { url = "https://files.pythonhosted.org/packages/0f/84/80c77c99df05a75c28490b2af8f7cba2a12621186e0a8b0865d8e745c104/multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9", size = 268369, upload-time = "2025-08-11T12:07:01.638Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e9/920bfa46c27b05fb3e1ad85121fd49f441492dca2449c5bcfe42e4565d8a/multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c", size = 269341, upload-time = "2025-08-11T12:07:02.943Z" }, + { url = "https://files.pythonhosted.org/packages/af/65/753a2d8b05daf496f4a9c367fe844e90a1b2cac78e2be2c844200d10cc4c/multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402", size = 256100, upload-time = "2025-08-11T12:07:04.564Z" }, + { url = "https://files.pythonhosted.org/packages/09/54/655be13ae324212bf0bc15d665a4e34844f34c206f78801be42f7a0a8aaa/multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7", size = 253584, upload-time = "2025-08-11T12:07:05.914Z" }, + { url = "https://files.pythonhosted.org/packages/5c/74/ab2039ecc05264b5cec73eb018ce417af3ebb384ae9c0e9ed42cb33f8151/multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f", size = 251018, upload-time = "2025-08-11T12:07:08.301Z" }, + { url = "https://files.pythonhosted.org/packages/af/0a/ccbb244ac848e56c6427f2392741c06302bbfba49c0042f1eb3c5b606497/multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d", size = 251477, upload-time = "2025-08-11T12:07:10.248Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b0/0ed49bba775b135937f52fe13922bc64a7eaf0a3ead84a36e8e4e446e096/multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7", size = 263575, upload-time = "2025-08-11T12:07:11.928Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d9/7fb85a85e14de2e44dfb6a24f03c41e2af8697a6df83daddb0e9b7569f73/multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802", size = 259649, upload-time = "2025-08-11T12:07:13.244Z" }, + { url = "https://files.pythonhosted.org/packages/03/9e/b3a459bcf9b6e74fa461a5222a10ff9b544cb1cd52fd482fb1b75ecda2a2/multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24", size = 251505, upload-time = "2025-08-11T12:07:14.57Z" }, + { url = "https://files.pythonhosted.org/packages/86/a2/8022f78f041dfe6d71e364001a5cf987c30edfc83c8a5fb7a3f0974cff39/multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793", size = 41888, upload-time = "2025-08-11T12:07:15.904Z" }, + { url = "https://files.pythonhosted.org/packages/c7/eb/d88b1780d43a56db2cba24289fa744a9d216c1a8546a0dc3956563fd53ea/multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e", size = 46072, upload-time = "2025-08-11T12:07:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/9f/16/b929320bf5750e2d9d4931835a4c638a19d2494a5b519caaaa7492ebe105/multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364", size = 43222, upload-time = "2025-08-11T12:07:18.328Z" }, + { url = "https://files.pythonhosted.org/packages/3a/5d/e1db626f64f60008320aab00fbe4f23fc3300d75892a3381275b3d284580/multidict-6.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f46a6e8597f9bd71b31cc708195d42b634c8527fecbcf93febf1052cacc1f16e", size = 75848, upload-time = "2025-08-11T12:07:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/4c/aa/8b6f548d839b6c13887253af4e29c939af22a18591bfb5d0ee6f1931dae8/multidict-6.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:22e38b2bc176c5eb9c0a0e379f9d188ae4cd8b28c0f53b52bce7ab0a9e534657", size = 45060, upload-time = "2025-08-11T12:07:21.163Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c6/f5e97e5d99a729bc2aa58eb3ebfa9f1e56a9b517cc38c60537c81834a73f/multidict-6.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5df8afd26f162da59e218ac0eefaa01b01b2e6cd606cffa46608f699539246da", size = 43269, upload-time = "2025-08-11T12:07:22.392Z" }, + { url = "https://files.pythonhosted.org/packages/dc/31/d54eb0c62516776f36fe67f84a732f97e0b0e12f98d5685bebcc6d396910/multidict-6.6.4-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:49517449b58d043023720aa58e62b2f74ce9b28f740a0b5d33971149553d72aa", size = 237158, upload-time = "2025-08-11T12:07:23.636Z" }, + { url = "https://files.pythonhosted.org/packages/c4/1c/8a10c1c25b23156e63b12165a929d8eb49a6ed769fdbefb06e6f07c1e50d/multidict-6.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9408439537c5afdca05edd128a63f56a62680f4b3c234301055d7a2000220f", size = 257076, upload-time = "2025-08-11T12:07:25.049Z" }, + { url = "https://files.pythonhosted.org/packages/ad/86/90e20b5771d6805a119e483fd3d1e8393e745a11511aebca41f0da38c3e2/multidict-6.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87a32d20759dc52a9e850fe1061b6e41ab28e2998d44168a8a341b99ded1dba0", size = 240694, upload-time = "2025-08-11T12:07:26.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/49/484d3e6b535bc0555b52a0a26ba86e4d8d03fd5587d4936dc59ba7583221/multidict-6.6.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52e3c8d43cdfff587ceedce9deb25e6ae77daba560b626e97a56ddcad3756879", size = 266350, upload-time = "2025-08-11T12:07:27.94Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b4/aa4c5c379b11895083d50021e229e90c408d7d875471cb3abf721e4670d6/multidict-6.6.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ad8850921d3a8d8ff6fbef790e773cecfc260bbfa0566998980d3fa8f520bc4a", size = 267250, upload-time = "2025-08-11T12:07:29.303Z" }, + { url = "https://files.pythonhosted.org/packages/80/e5/5e22c5bf96a64bdd43518b1834c6d95a4922cc2066b7d8e467dae9b6cee6/multidict-6.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:497a2954adc25c08daff36f795077f63ad33e13f19bfff7736e72c785391534f", size = 254900, upload-time = "2025-08-11T12:07:30.764Z" }, + { url = "https://files.pythonhosted.org/packages/17/38/58b27fed927c07035abc02befacab42491e7388ca105e087e6e0215ead64/multidict-6.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:024ce601f92d780ca1617ad4be5ac15b501cc2414970ffa2bb2bbc2bd5a68fa5", size = 252355, upload-time = "2025-08-11T12:07:32.205Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a1/dad75d23a90c29c02b5d6f3d7c10ab36c3197613be5d07ec49c7791e186c/multidict-6.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a693fc5ed9bdd1c9e898013e0da4dcc640de7963a371c0bd458e50e046bf6438", size = 250061, upload-time = "2025-08-11T12:07:33.623Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1a/ac2216b61c7f116edab6dc3378cca6c70dc019c9a457ff0d754067c58b20/multidict-6.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:190766dac95aab54cae5b152a56520fd99298f32a1266d66d27fdd1b5ac00f4e", size = 249675, upload-time = "2025-08-11T12:07:34.958Z" }, + { url = "https://files.pythonhosted.org/packages/d4/79/1916af833b800d13883e452e8e0977c065c4ee3ab7a26941fbfdebc11895/multidict-6.6.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8f2a5ffdceab9dcd97c7a016deb2308531d5f0fced2bb0c9e1df45b3363d7", size = 261247, upload-time = "2025-08-11T12:07:36.588Z" }, + { url = "https://files.pythonhosted.org/packages/c5/65/d1f84fe08ac44a5fc7391cbc20a7cedc433ea616b266284413fd86062f8c/multidict-6.6.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:59e8d40ab1f5a8597abcef00d04845155a5693b5da00d2c93dbe88f2050f2812", size = 257960, upload-time = "2025-08-11T12:07:39.735Z" }, + { url = "https://files.pythonhosted.org/packages/13/b5/29ec78057d377b195ac2c5248c773703a6b602e132a763e20ec0457e7440/multidict-6.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:467fe64138cfac771f0e949b938c2e1ada2b5af22f39692aa9258715e9ea613a", size = 250078, upload-time = "2025-08-11T12:07:41.525Z" }, + { url = "https://files.pythonhosted.org/packages/c4/0e/7e79d38f70a872cae32e29b0d77024bef7834b0afb406ddae6558d9e2414/multidict-6.6.4-cp313-cp313-win32.whl", hash = "sha256:14616a30fe6d0a48d0a48d1a633ab3b8bec4cf293aac65f32ed116f620adfd69", size = 41708, upload-time = "2025-08-11T12:07:43.405Z" }, + { url = "https://files.pythonhosted.org/packages/9d/34/746696dffff742e97cd6a23da953e55d0ea51fa601fa2ff387b3edcfaa2c/multidict-6.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:40cd05eaeb39e2bc8939451f033e57feaa2ac99e07dbca8afe2be450a4a3b6cf", size = 45912, upload-time = "2025-08-11T12:07:45.082Z" }, + { url = "https://files.pythonhosted.org/packages/c7/87/3bac136181e271e29170d8d71929cdeddeb77f3e8b6a0c08da3a8e9da114/multidict-6.6.4-cp313-cp313-win_arm64.whl", hash = "sha256:f6eb37d511bfae9e13e82cb4d1af36b91150466f24d9b2b8a9785816deb16605", size = 43076, upload-time = "2025-08-11T12:07:46.746Z" }, + { url = "https://files.pythonhosted.org/packages/64/94/0a8e63e36c049b571c9ae41ee301ada29c3fee9643d9c2548d7d558a1d99/multidict-6.6.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6c84378acd4f37d1b507dfa0d459b449e2321b3ba5f2338f9b085cf7a7ba95eb", size = 82812, upload-time = "2025-08-11T12:07:48.402Z" }, + { url = "https://files.pythonhosted.org/packages/25/1a/be8e369dfcd260d2070a67e65dd3990dd635cbd735b98da31e00ea84cd4e/multidict-6.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0e0558693063c75f3d952abf645c78f3c5dfdd825a41d8c4d8156fc0b0da6e7e", size = 48313, upload-time = "2025-08-11T12:07:49.679Z" }, + { url = "https://files.pythonhosted.org/packages/26/5a/dd4ade298674b2f9a7b06a32c94ffbc0497354df8285f27317c66433ce3b/multidict-6.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3f8e2384cb83ebd23fd07e9eada8ba64afc4c759cd94817433ab8c81ee4b403f", size = 46777, upload-time = "2025-08-11T12:07:51.318Z" }, + { url = "https://files.pythonhosted.org/packages/89/db/98aa28bc7e071bfba611ac2ae803c24e96dd3a452b4118c587d3d872c64c/multidict-6.6.4-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f996b87b420995a9174b2a7c1a8daf7db4750be6848b03eb5e639674f7963773", size = 229321, upload-time = "2025-08-11T12:07:52.965Z" }, + { url = "https://files.pythonhosted.org/packages/c7/bc/01ddda2a73dd9d167bd85d0e8ef4293836a8f82b786c63fb1a429bc3e678/multidict-6.6.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc356250cffd6e78416cf5b40dc6a74f1edf3be8e834cf8862d9ed5265cf9b0e", size = 249954, upload-time = "2025-08-11T12:07:54.423Z" }, + { url = "https://files.pythonhosted.org/packages/06/78/6b7c0f020f9aa0acf66d0ab4eb9f08375bac9a50ff5e3edb1c4ccd59eafc/multidict-6.6.4-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dadf95aa862714ea468a49ad1e09fe00fcc9ec67d122f6596a8d40caf6cec7d0", size = 228612, upload-time = "2025-08-11T12:07:55.914Z" }, + { url = "https://files.pythonhosted.org/packages/00/44/3faa416f89b2d5d76e9d447296a81521e1c832ad6e40b92f990697b43192/multidict-6.6.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dd57515bebffd8ebd714d101d4c434063322e4fe24042e90ced41f18b6d3395", size = 257528, upload-time = "2025-08-11T12:07:57.371Z" }, + { url = "https://files.pythonhosted.org/packages/05/5f/77c03b89af0fcb16f018f668207768191fb9dcfb5e3361a5e706a11db2c9/multidict-6.6.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:967af5f238ebc2eb1da4e77af5492219fbd9b4b812347da39a7b5f5c72c0fa45", size = 256329, upload-time = "2025-08-11T12:07:58.844Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e9/ed750a2a9afb4f8dc6f13dc5b67b514832101b95714f1211cd42e0aafc26/multidict-6.6.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a4c6875c37aae9794308ec43e3530e4aa0d36579ce38d89979bbf89582002bb", size = 247928, upload-time = "2025-08-11T12:08:01.037Z" }, + { url = "https://files.pythonhosted.org/packages/1f/b5/e0571bc13cda277db7e6e8a532791d4403dacc9850006cb66d2556e649c0/multidict-6.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f683a551e92bdb7fac545b9c6f9fa2aebdeefa61d607510b3533286fcab67f5", size = 245228, upload-time = "2025-08-11T12:08:02.96Z" }, + { url = "https://files.pythonhosted.org/packages/f3/a3/69a84b0eccb9824491f06368f5b86e72e4af54c3067c37c39099b6687109/multidict-6.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:3ba5aaf600edaf2a868a391779f7a85d93bed147854925f34edd24cc70a3e141", size = 235869, upload-time = "2025-08-11T12:08:04.746Z" }, + { url = "https://files.pythonhosted.org/packages/a9/9d/28802e8f9121a6a0804fa009debf4e753d0a59969ea9f70be5f5fdfcb18f/multidict-6.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:580b643b7fd2c295d83cad90d78419081f53fd532d1f1eb67ceb7060f61cff0d", size = 243446, upload-time = "2025-08-11T12:08:06.332Z" }, + { url = "https://files.pythonhosted.org/packages/38/ea/6c98add069b4878c1d66428a5f5149ddb6d32b1f9836a826ac764b9940be/multidict-6.6.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:37b7187197da6af3ee0b044dbc9625afd0c885f2800815b228a0e70f9a7f473d", size = 252299, upload-time = "2025-08-11T12:08:07.931Z" }, + { url = "https://files.pythonhosted.org/packages/3a/09/8fe02d204473e14c0af3affd50af9078839dfca1742f025cca765435d6b4/multidict-6.6.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e1b93790ed0bc26feb72e2f08299691ceb6da5e9e14a0d13cc74f1869af327a0", size = 246926, upload-time = "2025-08-11T12:08:09.467Z" }, + { url = "https://files.pythonhosted.org/packages/37/3d/7b1e10d774a6df5175ecd3c92bff069e77bed9ec2a927fdd4ff5fe182f67/multidict-6.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a506a77ddee1efcca81ecbeae27ade3e09cdf21a8ae854d766c2bb4f14053f92", size = 243383, upload-time = "2025-08-11T12:08:10.981Z" }, + { url = "https://files.pythonhosted.org/packages/50/b0/a6fae46071b645ae98786ab738447de1ef53742eaad949f27e960864bb49/multidict-6.6.4-cp313-cp313t-win32.whl", hash = "sha256:f93b2b2279883d1d0a9e1bd01f312d6fc315c5e4c1f09e112e4736e2f650bc4e", size = 47775, upload-time = "2025-08-11T12:08:12.439Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0a/2436550b1520091af0600dff547913cb2d66fbac27a8c33bc1b1bccd8d98/multidict-6.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:6d46a180acdf6e87cc41dc15d8f5c2986e1e8739dc25dbb7dac826731ef381a4", size = 53100, upload-time = "2025-08-11T12:08:13.823Z" }, + { url = "https://files.pythonhosted.org/packages/97/ea/43ac51faff934086db9c072a94d327d71b7d8b40cd5dcb47311330929ef0/multidict-6.6.4-cp313-cp313t-win_arm64.whl", hash = "sha256:756989334015e3335d087a27331659820d53ba432befdef6a718398b0a8493ad", size = 45501, upload-time = "2025-08-11T12:08:15.173Z" }, + { url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" }, +] + +[[package]] +name = "mypy" +version = "1.18.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/77/8f0d0001ffad290cef2f7f216f96c814866248a0b92a722365ed54648e7e/mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b", size = 3448846, upload-time = "2025-09-19T00:11:10.519Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/6f/657961a0743cff32e6c0611b63ff1c1970a0b482ace35b069203bf705187/mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c", size = 12807973, upload-time = "2025-09-19T00:10:35.282Z" }, + { url = "https://files.pythonhosted.org/packages/10/e9/420822d4f661f13ca8900f5fa239b40ee3be8b62b32f3357df9a3045a08b/mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e", size = 11896527, upload-time = "2025-09-19T00:10:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/aa/73/a05b2bbaa7005f4642fcfe40fb73f2b4fb6bb44229bd585b5878e9a87ef8/mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b", size = 12507004, upload-time = "2025-09-19T00:11:05.411Z" }, + { url = "https://files.pythonhosted.org/packages/4f/01/f6e4b9f0d031c11ccbd6f17da26564f3a0f3c4155af344006434b0a05a9d/mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66", size = 13245947, upload-time = "2025-09-19T00:10:46.923Z" }, + { url = "https://files.pythonhosted.org/packages/d7/97/19727e7499bfa1ae0773d06afd30ac66a58ed7437d940c70548634b24185/mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428", size = 13499217, upload-time = "2025-09-19T00:09:39.472Z" }, + { url = "https://files.pythonhosted.org/packages/9f/4f/90dc8c15c1441bf31cf0f9918bb077e452618708199e530f4cbd5cede6ff/mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed", size = 9766753, upload-time = "2025-09-19T00:10:49.161Z" }, + { url = "https://files.pythonhosted.org/packages/88/87/cafd3ae563f88f94eec33f35ff722d043e09832ea8530ef149ec1efbaf08/mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f", size = 12731198, upload-time = "2025-09-19T00:09:44.857Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e0/1e96c3d4266a06d4b0197ace5356d67d937d8358e2ee3ffac71faa843724/mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341", size = 11817879, upload-time = "2025-09-19T00:09:47.131Z" }, + { url = "https://files.pythonhosted.org/packages/72/ef/0c9ba89eb03453e76bdac5a78b08260a848c7bfc5d6603634774d9cd9525/mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d", size = 12427292, upload-time = "2025-09-19T00:10:22.472Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/ec4a061dd599eb8179d5411d99775bec2a20542505988f40fc2fee781068/mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86", size = 13163750, upload-time = "2025-09-19T00:09:51.472Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5f/2cf2ceb3b36372d51568f2208c021870fe7834cf3186b653ac6446511839/mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37", size = 13351827, upload-time = "2025-09-19T00:09:58.311Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7d/2697b930179e7277529eaaec1513f8de622818696857f689e4a5432e5e27/mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8", size = 9757983, upload-time = "2025-09-19T00:10:09.071Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/dfdd2bc60c66611dd8335f463818514733bc763e4760dee289dcc33df709/mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34", size = 12908273, upload-time = "2025-09-19T00:10:58.321Z" }, + { url = "https://files.pythonhosted.org/packages/81/14/6a9de6d13a122d5608e1a04130724caf9170333ac5a924e10f670687d3eb/mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764", size = 11920910, upload-time = "2025-09-19T00:10:20.043Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a9/b29de53e42f18e8cc547e38daa9dfa132ffdc64f7250e353f5c8cdd44bee/mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893", size = 12465585, upload-time = "2025-09-19T00:10:33.005Z" }, + { url = "https://files.pythonhosted.org/packages/77/ae/6c3d2c7c61ff21f2bee938c917616c92ebf852f015fb55917fd6e2811db2/mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914", size = 13348562, upload-time = "2025-09-19T00:10:11.51Z" }, + { url = "https://files.pythonhosted.org/packages/4d/31/aec68ab3b4aebdf8f36d191b0685d99faa899ab990753ca0fee60fb99511/mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8", size = 13533296, upload-time = "2025-09-19T00:10:06.568Z" }, + { url = "https://files.pythonhosted.org/packages/9f/83/abcb3ad9478fca3ebeb6a5358bb0b22c95ea42b43b7789c7fb1297ca44f4/mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074", size = 9828828, upload-time = "2025-09-19T00:10:28.203Z" }, + { url = "https://files.pythonhosted.org/packages/5f/04/7f462e6fbba87a72bc8097b93f6842499c428a6ff0c81dd46948d175afe8/mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc", size = 12898728, upload-time = "2025-09-19T00:10:01.33Z" }, + { url = "https://files.pythonhosted.org/packages/99/5b/61ed4efb64f1871b41fd0b82d29a64640f3516078f6c7905b68ab1ad8b13/mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e", size = 11910758, upload-time = "2025-09-19T00:10:42.607Z" }, + { url = "https://files.pythonhosted.org/packages/3c/46/d297d4b683cc89a6e4108c4250a6a6b717f5fa96e1a30a7944a6da44da35/mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986", size = 12475342, upload-time = "2025-09-19T00:11:00.371Z" }, + { url = "https://files.pythonhosted.org/packages/83/45/4798f4d00df13eae3bfdf726c9244bcb495ab5bd588c0eed93a2f2dd67f3/mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d", size = 13338709, upload-time = "2025-09-19T00:11:03.358Z" }, + { url = "https://files.pythonhosted.org/packages/d7/09/479f7358d9625172521a87a9271ddd2441e1dab16a09708f056e97007207/mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba", size = 13529806, upload-time = "2025-09-19T00:10:26.073Z" }, + { url = "https://files.pythonhosted.org/packages/71/cf/ac0f2c7e9d0ea3c75cd99dff7aec1c9df4a1376537cb90e4c882267ee7e9/mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544", size = 9833262, upload-time = "2025-09-19T00:10:40.035Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0c/7d5300883da16f0063ae53996358758b2a2df2a09c72a5061fa79a1f5006/mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce", size = 12893775, upload-time = "2025-09-19T00:10:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/50/df/2cffbf25737bdb236f60c973edf62e3e7b4ee1c25b6878629e88e2cde967/mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d", size = 11936852, upload-time = "2025-09-19T00:10:51.631Z" }, + { url = "https://files.pythonhosted.org/packages/be/50/34059de13dd269227fb4a03be1faee6e2a4b04a2051c82ac0a0b5a773c9a/mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c", size = 12480242, upload-time = "2025-09-19T00:11:07.955Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" }, + { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" }, + { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nmcli" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/57/a4b743fe2a06014236c081db3396572b4177896735504fc00ce42ff55a89/nmcli-1.5.0.tar.gz", hash = "sha256:6261dbd6f48b8454b7efc992f4285a5c126613a91a965d2c6c2caf749dec4ddf", size = 14994, upload-time = "2024-12-07T06:40:58.043Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/76/db262236cd1dbb18b1f98762ecba67cc97b572c74409224e61bbf1ac0c6a/nmcli-1.5.0-py3-none-any.whl", hash = "sha256:55e8cba0b4650f8d0741c9c403f8e33c6ad270b66bc23f9dc830214ef37b8429", size = 18909, upload-time = "2024-12-07T06:40:56.205Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, +] + +[[package]] +name = "numpy" +version = "2.2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/b2/ce4b867d8cd9c0ee84938ae1e6a6f7926ebf928c9090d036fc3c6a04f946/numpy-2.2.5.tar.gz", hash = "sha256:a9c0d994680cd991b1cb772e8b297340085466a6fe964bc9d4e80f5e2f43c291", size = 20273920, upload-time = "2025-04-19T23:27:42.561Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/4e/3d9e6d16237c2aa5485695f0626cbba82f6481efca2e9132368dea3b885e/numpy-2.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f4a922da1729f4c40932b2af4fe84909c7a6e167e6e99f71838ce3a29f3fe26", size = 21252117, upload-time = "2025-04-19T22:31:01.142Z" }, + { url = "https://files.pythonhosted.org/packages/38/e4/db91349d4079cd15c02ff3b4b8882a529991d6aca077db198a2f2a670406/numpy-2.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6f91524d31b34f4a5fee24f5bc16dcd1491b668798b6d85585d836c1e633a6a", size = 14424615, upload-time = "2025-04-19T22:31:24.873Z" }, + { url = "https://files.pythonhosted.org/packages/f8/59/6e5b011f553c37b008bd115c7ba7106a18f372588fbb1b430b7a5d2c41ce/numpy-2.2.5-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:19f4718c9012e3baea91a7dba661dcab2451cda2550678dc30d53acb91a7290f", size = 5428691, upload-time = "2025-04-19T22:31:33.998Z" }, + { url = "https://files.pythonhosted.org/packages/a2/58/d5d70ebdac82b3a6ddf409b3749ca5786636e50fd64d60edb46442af6838/numpy-2.2.5-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:eb7fd5b184e5d277afa9ec0ad5e4eb562ecff541e7f60e69ee69c8d59e9aeaba", size = 6965010, upload-time = "2025-04-19T22:31:45.281Z" }, + { url = "https://files.pythonhosted.org/packages/dc/a8/c290394be346d4e7b48a40baf292626fd96ec56a6398ace4c25d9079bc6a/numpy-2.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6413d48a9be53e183eb06495d8e3b006ef8f87c324af68241bbe7a39e8ff54c3", size = 14369885, upload-time = "2025-04-19T22:32:06.557Z" }, + { url = "https://files.pythonhosted.org/packages/c2/70/fed13c70aabe7049368553e81d7ca40f305f305800a007a956d7cd2e5476/numpy-2.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7451f92eddf8503c9b8aa4fe6aa7e87fd51a29c2cfc5f7dbd72efde6c65acf57", size = 16418372, upload-time = "2025-04-19T22:32:31.716Z" }, + { url = "https://files.pythonhosted.org/packages/04/ab/c3c14f25ddaecd6fc58a34858f6a93a21eea6c266ba162fa99f3d0de12ac/numpy-2.2.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0bcb1d057b7571334139129b7f941588f69ce7c4ed15a9d6162b2ea54ded700c", size = 15883173, upload-time = "2025-04-19T22:32:55.106Z" }, + { url = "https://files.pythonhosted.org/packages/50/18/f53710a19042911c7aca824afe97c203728a34b8cf123e2d94621a12edc3/numpy-2.2.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36ab5b23915887543441efd0417e6a3baa08634308894316f446027611b53bf1", size = 18206881, upload-time = "2025-04-19T22:33:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ec/5b407bab82f10c65af5a5fe754728df03f960fd44d27c036b61f7b3ef255/numpy-2.2.5-cp310-cp310-win32.whl", hash = "sha256:422cc684f17bc963da5f59a31530b3936f57c95a29743056ef7a7903a5dbdf88", size = 6609852, upload-time = "2025-04-19T22:33:33.357Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f5/467ca8675c7e6c567f571d8db942cc10a87588bd9e20a909d8af4171edda/numpy-2.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:e4f0b035d9d0ed519c813ee23e0a733db81ec37d2e9503afbb6e54ccfdee0fa7", size = 12944922, upload-time = "2025-04-19T22:33:53.192Z" }, + { url = "https://files.pythonhosted.org/packages/f5/fb/e4e4c254ba40e8f0c78218f9e86304628c75b6900509b601c8433bdb5da7/numpy-2.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c42365005c7a6c42436a54d28c43fe0e01ca11eb2ac3cefe796c25a5f98e5e9b", size = 21256475, upload-time = "2025-04-19T22:34:24.174Z" }, + { url = "https://files.pythonhosted.org/packages/81/32/dd1f7084f5c10b2caad778258fdaeedd7fbd8afcd2510672811e6138dfac/numpy-2.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:498815b96f67dc347e03b719ef49c772589fb74b8ee9ea2c37feae915ad6ebda", size = 14461474, upload-time = "2025-04-19T22:34:46.578Z" }, + { url = "https://files.pythonhosted.org/packages/0e/65/937cdf238ef6ac54ff749c0f66d9ee2b03646034c205cea9b6c51f2f3ad1/numpy-2.2.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6411f744f7f20081b1b4e7112e0f4c9c5b08f94b9f086e6f0adf3645f85d3a4d", size = 5426875, upload-time = "2025-04-19T22:34:56.281Z" }, + { url = "https://files.pythonhosted.org/packages/25/17/814515fdd545b07306eaee552b65c765035ea302d17de1b9cb50852d2452/numpy-2.2.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9de6832228f617c9ef45d948ec1cd8949c482238d68b2477e6f642c33a7b0a54", size = 6969176, upload-time = "2025-04-19T22:35:07.518Z" }, + { url = "https://files.pythonhosted.org/packages/e5/32/a66db7a5c8b5301ec329ab36d0ecca23f5e18907f43dbd593c8ec326d57c/numpy-2.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:369e0d4647c17c9363244f3468f2227d557a74b6781cb62ce57cf3ef5cc7c610", size = 14374850, upload-time = "2025-04-19T22:35:31.347Z" }, + { url = "https://files.pythonhosted.org/packages/ad/c9/1bf6ada582eebcbe8978f5feb26584cd2b39f94ededeea034ca8f84af8c8/numpy-2.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:262d23f383170f99cd9191a7c85b9a50970fe9069b2f8ab5d786eca8a675d60b", size = 16430306, upload-time = "2025-04-19T22:35:57.573Z" }, + { url = "https://files.pythonhosted.org/packages/6a/f0/3f741863f29e128f4fcfdb99253cc971406b402b4584663710ee07f5f7eb/numpy-2.2.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aa70fdbdc3b169d69e8c59e65c07a1c9351ceb438e627f0fdcd471015cd956be", size = 15884767, upload-time = "2025-04-19T22:36:22.245Z" }, + { url = "https://files.pythonhosted.org/packages/98/d9/4ccd8fd6410f7bf2d312cbc98892e0e43c2fcdd1deae293aeb0a93b18071/numpy-2.2.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37e32e985f03c06206582a7323ef926b4e78bdaa6915095ef08070471865b906", size = 18219515, upload-time = "2025-04-19T22:36:49.822Z" }, + { url = "https://files.pythonhosted.org/packages/b1/56/783237243d4395c6dd741cf16eeb1a9035ee3d4310900e6b17e875d1b201/numpy-2.2.5-cp311-cp311-win32.whl", hash = "sha256:f5045039100ed58fa817a6227a356240ea1b9a1bc141018864c306c1a16d4175", size = 6607842, upload-time = "2025-04-19T22:37:01.624Z" }, + { url = "https://files.pythonhosted.org/packages/98/89/0c93baaf0094bdaaaa0536fe61a27b1dce8a505fa262a865ec142208cfe9/numpy-2.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:b13f04968b46ad705f7c8a80122a42ae8f620536ea38cf4bdd374302926424dd", size = 12949071, upload-time = "2025-04-19T22:37:21.098Z" }, + { url = "https://files.pythonhosted.org/packages/e2/f7/1fd4ff108cd9d7ef929b8882692e23665dc9c23feecafbb9c6b80f4ec583/numpy-2.2.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ee461a4eaab4f165b68780a6a1af95fb23a29932be7569b9fab666c407969051", size = 20948633, upload-time = "2025-04-19T22:37:52.4Z" }, + { url = "https://files.pythonhosted.org/packages/12/03/d443c278348371b20d830af155ff2079acad6a9e60279fac2b41dbbb73d8/numpy-2.2.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ec31367fd6a255dc8de4772bd1658c3e926d8e860a0b6e922b615e532d320ddc", size = 14176123, upload-time = "2025-04-19T22:38:15.058Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0b/5ca264641d0e7b14393313304da48b225d15d471250376f3fbdb1a2be603/numpy-2.2.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:47834cde750d3c9f4e52c6ca28a7361859fcaf52695c7dc3cc1a720b8922683e", size = 5163817, upload-time = "2025-04-19T22:38:24.885Z" }, + { url = "https://files.pythonhosted.org/packages/04/b3/d522672b9e3d28e26e1613de7675b441bbd1eaca75db95680635dd158c67/numpy-2.2.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2c1a1c6ccce4022383583a6ded7bbcda22fc635eb4eb1e0a053336425ed36dfa", size = 6698066, upload-time = "2025-04-19T22:38:35.782Z" }, + { url = "https://files.pythonhosted.org/packages/a0/93/0f7a75c1ff02d4b76df35079676b3b2719fcdfb39abdf44c8b33f43ef37d/numpy-2.2.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d75f338f5f79ee23548b03d801d28a505198297534f62416391857ea0479571", size = 14087277, upload-time = "2025-04-19T22:38:57.697Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d9/7c338b923c53d431bc837b5b787052fef9ae68a56fe91e325aac0d48226e/numpy-2.2.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a801fef99668f309b88640e28d261991bfad9617c27beda4a3aec4f217ea073", size = 16135742, upload-time = "2025-04-19T22:39:22.689Z" }, + { url = "https://files.pythonhosted.org/packages/2d/10/4dec9184a5d74ba9867c6f7d1e9f2e0fb5fe96ff2bf50bb6f342d64f2003/numpy-2.2.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:abe38cd8381245a7f49967a6010e77dbf3680bd3627c0fe4362dd693b404c7f8", size = 15581825, upload-time = "2025-04-19T22:39:45.794Z" }, + { url = "https://files.pythonhosted.org/packages/80/1f/2b6fcd636e848053f5b57712a7d1880b1565eec35a637fdfd0a30d5e738d/numpy-2.2.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5a0ac90e46fdb5649ab6369d1ab6104bfe5854ab19b645bf5cda0127a13034ae", size = 17899600, upload-time = "2025-04-19T22:40:13.427Z" }, + { url = "https://files.pythonhosted.org/packages/ec/87/36801f4dc2623d76a0a3835975524a84bd2b18fe0f8835d45c8eae2f9ff2/numpy-2.2.5-cp312-cp312-win32.whl", hash = "sha256:0cd48122a6b7eab8f06404805b1bd5856200e3ed6f8a1b9a194f9d9054631beb", size = 6312626, upload-time = "2025-04-19T22:40:25.223Z" }, + { url = "https://files.pythonhosted.org/packages/8b/09/4ffb4d6cfe7ca6707336187951992bd8a8b9142cf345d87ab858d2d7636a/numpy-2.2.5-cp312-cp312-win_amd64.whl", hash = "sha256:ced69262a8278547e63409b2653b372bf4baff0870c57efa76c5703fd6543282", size = 12645715, upload-time = "2025-04-19T22:40:44.528Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a0/0aa7f0f4509a2e07bd7a509042967c2fab635690d4f48c6c7b3afd4f448c/numpy-2.2.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:059b51b658f4414fff78c6d7b1b4e18283ab5fa56d270ff212d5ba0c561846f4", size = 20935102, upload-time = "2025-04-19T22:41:16.234Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e4/a6a9f4537542912ec513185396fce52cdd45bdcf3e9d921ab02a93ca5aa9/numpy-2.2.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:47f9ed103af0bc63182609044b0490747e03bd20a67e391192dde119bf43d52f", size = 14191709, upload-time = "2025-04-19T22:41:38.472Z" }, + { url = "https://files.pythonhosted.org/packages/be/65/72f3186b6050bbfe9c43cb81f9df59ae63603491d36179cf7a7c8d216758/numpy-2.2.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:261a1ef047751bb02f29dfe337230b5882b54521ca121fc7f62668133cb119c9", size = 5149173, upload-time = "2025-04-19T22:41:47.823Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e9/83e7a9432378dde5802651307ae5e9ea07bb72b416728202218cd4da2801/numpy-2.2.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4520caa3807c1ceb005d125a75e715567806fed67e315cea619d5ec6e75a4191", size = 6684502, upload-time = "2025-04-19T22:41:58.689Z" }, + { url = "https://files.pythonhosted.org/packages/ea/27/b80da6c762394c8ee516b74c1f686fcd16c8f23b14de57ba0cad7349d1d2/numpy-2.2.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d14b17b9be5f9c9301f43d2e2a4886a33b53f4e6fdf9ca2f4cc60aeeee76372", size = 14084417, upload-time = "2025-04-19T22:42:19.897Z" }, + { url = "https://files.pythonhosted.org/packages/aa/fc/ebfd32c3e124e6a1043e19c0ab0769818aa69050ce5589b63d05ff185526/numpy-2.2.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ba321813a00e508d5421104464510cc962a6f791aa2fca1c97b1e65027da80d", size = 16133807, upload-time = "2025-04-19T22:42:44.433Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9b/4cc171a0acbe4666f7775cfd21d4eb6bb1d36d3a0431f48a73e9212d2278/numpy-2.2.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4cbdef3ddf777423060c6f81b5694bad2dc9675f110c4b2a60dc0181543fac7", size = 15575611, upload-time = "2025-04-19T22:43:09.928Z" }, + { url = "https://files.pythonhosted.org/packages/a3/45/40f4135341850df48f8edcf949cf47b523c404b712774f8855a64c96ef29/numpy-2.2.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54088a5a147ab71a8e7fdfd8c3601972751ded0739c6b696ad9cb0343e21ab73", size = 17895747, upload-time = "2025-04-19T22:43:36.983Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4c/b32a17a46f0ffbde8cc82df6d3daeaf4f552e346df143e1b188a701a8f09/numpy-2.2.5-cp313-cp313-win32.whl", hash = "sha256:c8b82a55ef86a2d8e81b63da85e55f5537d2157165be1cb2ce7cfa57b6aef38b", size = 6309594, upload-time = "2025-04-19T22:47:10.523Z" }, + { url = "https://files.pythonhosted.org/packages/13/ae/72e6276feb9ef06787365b05915bfdb057d01fceb4a43cb80978e518d79b/numpy-2.2.5-cp313-cp313-win_amd64.whl", hash = "sha256:d8882a829fd779f0f43998e931c466802a77ca1ee0fe25a3abe50278616b1471", size = 12638356, upload-time = "2025-04-19T22:47:30.253Z" }, + { url = "https://files.pythonhosted.org/packages/79/56/be8b85a9f2adb688e7ded6324e20149a03541d2b3297c3ffc1a73f46dedb/numpy-2.2.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8b025c351b9f0e8b5436cf28a07fa4ac0204d67b38f01433ac7f9b870fa38c6", size = 20963778, upload-time = "2025-04-19T22:44:09.251Z" }, + { url = "https://files.pythonhosted.org/packages/ff/77/19c5e62d55bff507a18c3cdff82e94fe174957bad25860a991cac719d3ab/numpy-2.2.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dfa94b6a4374e7851bbb6f35e6ded2120b752b063e6acdd3157e4d2bb922eba", size = 14207279, upload-time = "2025-04-19T22:44:31.383Z" }, + { url = "https://files.pythonhosted.org/packages/75/22/aa11f22dc11ff4ffe4e849d9b63bbe8d4ac6d5fae85ddaa67dfe43be3e76/numpy-2.2.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:97c8425d4e26437e65e1d189d22dff4a079b747ff9c2788057bfb8114ce1e133", size = 5199247, upload-time = "2025-04-19T22:44:40.361Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6c/12d5e760fc62c08eded0394f62039f5a9857f758312bf01632a81d841459/numpy-2.2.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:352d330048c055ea6db701130abc48a21bec690a8d38f8284e00fab256dc1376", size = 6711087, upload-time = "2025-04-19T22:44:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/ef/94/ece8280cf4218b2bee5cec9567629e61e51b4be501e5c6840ceb593db945/numpy-2.2.5-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b4c0773b6ada798f51f0f8e30c054d32304ccc6e9c5d93d46cb26f3d385ab19", size = 14059964, upload-time = "2025-04-19T22:45:12.451Z" }, + { url = "https://files.pythonhosted.org/packages/39/41/c5377dac0514aaeec69115830a39d905b1882819c8e65d97fc60e177e19e/numpy-2.2.5-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55f09e00d4dccd76b179c0f18a44f041e5332fd0e022886ba1c0bbf3ea4a18d0", size = 16121214, upload-time = "2025-04-19T22:45:37.734Z" }, + { url = "https://files.pythonhosted.org/packages/db/54/3b9f89a943257bc8e187145c6bc0eb8e3d615655f7b14e9b490b053e8149/numpy-2.2.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02f226baeefa68f7d579e213d0f3493496397d8f1cff5e2b222af274c86a552a", size = 15575788, upload-time = "2025-04-19T22:46:01.908Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c4/2e407e85df35b29f79945751b8f8e671057a13a376497d7fb2151ba0d290/numpy-2.2.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c26843fd58f65da9491165072da2cccc372530681de481ef670dcc8e27cfb066", size = 17893672, upload-time = "2025-04-19T22:46:28.585Z" }, + { url = "https://files.pythonhosted.org/packages/29/7e/d0b44e129d038dba453f00d0e29ebd6eaf2f06055d72b95b9947998aca14/numpy-2.2.5-cp313-cp313t-win32.whl", hash = "sha256:1a161c2c79ab30fe4501d5a2bbfe8b162490757cf90b7f05be8b80bc02f7bb8e", size = 6377102, upload-time = "2025-04-19T22:46:39.949Z" }, + { url = "https://files.pythonhosted.org/packages/63/be/b85e4aa4bf42c6502851b971f1c326d583fcc68227385f92089cf50a7b45/numpy-2.2.5-cp313-cp313t-win_amd64.whl", hash = "sha256:d403c84991b5ad291d3809bace5e85f4bbf44a04bdc9a88ed2bb1807b3360bb8", size = 12750096, upload-time = "2025-04-19T22:47:00.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/e4/5ef5ef1d4308f96961198b2323bfc7c7afb0ccc0d623b01c79bc87ab496d/numpy-2.2.5-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b4ea7e1cff6784e58fe281ce7e7f05036b3e1c89c6f922a6bfbc0a7e8768adbe", size = 21083404, upload-time = "2025-04-19T22:48:01.605Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5f/bde9238e8e977652a16a4b114ed8aa8bb093d718c706eeecb5f7bfa59572/numpy-2.2.5-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d7543263084a85fbc09c704b515395398d31d6395518446237eac219eab9e55e", size = 6828578, upload-time = "2025-04-19T22:48:13.118Z" }, + { url = "https://files.pythonhosted.org/packages/ef/7f/813f51ed86e559ab2afb6a6f33aa6baf8a560097e25e4882a938986c76c2/numpy-2.2.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0255732338c4fdd00996c0421884ea8a3651eea555c3a56b84892b66f696eb70", size = 16234796, upload-time = "2025-04-19T22:48:37.102Z" }, + { url = "https://files.pythonhosted.org/packages/68/67/1175790323026d3337cc285cc9c50eca637d70472b5e622529df74bb8f37/numpy-2.2.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d2e3bdadaba0e040d1e7ab39db73e0afe2c74ae277f5614dad53eadbecbbb169", size = 12859001, upload-time = "2025-04-19T22:48:57.665Z" }, +] + +[[package]] +name = "numpy-stl" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/80/96366d1b69223d4ca55fca30f158096df169b00aa6b4dd963025980e7ede/numpy_stl-3.2.0.tar.gz", hash = "sha256:5a20c3f79cddaa0abc6a4b99f5486aceed4f88152f29b19a57acc844e183fd4d", size = 824382, upload-time = "2024-11-25T17:15:43.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/2c/e17b8814050427929077639d35a42187a006922600d4840475bdc5f64ebb/numpy_stl-3.2.0-py3-none-any.whl", hash = "sha256:697c81b107231362460aaedf4647e81ba54f54f59c896772fea7904c9c439da5", size = 20775, upload-time = "2024-11-25T17:15:41.346Z" }, +] + +[[package]] +name = "onnxruntime" +version = "1.22.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coloredlogs" }, + { name = "flatbuffers" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "protobuf" }, + { name = "sympy" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/b9/664a1ffee62fa51529fac27b37409d5d28cadee8d97db806fcba68339b7e/onnxruntime-1.22.1-cp310-cp310-macosx_13_0_universal2.whl", hash = "sha256:80e7f51da1f5201c1379b8d6ef6170505cd800e40da216290f5e06be01aadf95", size = 34319864, upload-time = "2025-07-10T19:15:15.371Z" }, + { url = "https://files.pythonhosted.org/packages/b9/64/bc7221e92c994931024e22b22401b962c299e991558c3d57f7e34538b4b9/onnxruntime-1.22.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89ddfdbbdaf7e3a59515dee657f6515601d55cb21a0f0f48c81aefc54ff1b73", size = 14472246, upload-time = "2025-07-10T19:15:19.403Z" }, + { url = "https://files.pythonhosted.org/packages/84/57/901eddbfb59ac4d008822b236450d5765cafcd450c787019416f8d3baf11/onnxruntime-1.22.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bddc75868bcf6f9ed76858a632f65f7b1846bdcefc6d637b1e359c2c68609964", size = 16459905, upload-time = "2025-07-10T19:15:21.749Z" }, + { url = "https://files.pythonhosted.org/packages/de/90/d6a1eb9b47e66a18afe7d1cf7cf0b2ef966ffa6f44d9f32d94c2be2860fb/onnxruntime-1.22.1-cp310-cp310-win_amd64.whl", hash = "sha256:01e2f21b2793eb0c8642d2be3cee34cc7d96b85f45f6615e4e220424158877ce", size = 12689001, upload-time = "2025-07-10T19:15:23.848Z" }, + { url = "https://files.pythonhosted.org/packages/82/ff/4a1a6747e039ef29a8d4ee4510060e9a805982b6da906a3da2306b7a3be6/onnxruntime-1.22.1-cp311-cp311-macosx_13_0_universal2.whl", hash = "sha256:f4581bccb786da68725d8eac7c63a8f31a89116b8761ff8b4989dc58b61d49a0", size = 34324148, upload-time = "2025-07-10T19:15:26.584Z" }, + { url = "https://files.pythonhosted.org/packages/0b/05/9f1929723f1cca8c9fb1b2b97ac54ce61362c7201434d38053ea36ee4225/onnxruntime-1.22.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ae7526cf10f93454beb0f751e78e5cb7619e3b92f9fc3bd51aa6f3b7a8977e5", size = 14473779, upload-time = "2025-07-10T19:15:30.183Z" }, + { url = "https://files.pythonhosted.org/packages/59/f3/c93eb4167d4f36ea947930f82850231f7ce0900cb00e1a53dc4995b60479/onnxruntime-1.22.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f6effa1299ac549a05c784d50292e3378dbbf010346ded67400193b09ddc2f04", size = 16460799, upload-time = "2025-07-10T19:15:33.005Z" }, + { url = "https://files.pythonhosted.org/packages/a8/01/e536397b03e4462d3260aee5387e6f606c8fa9d2b20b1728f988c3c72891/onnxruntime-1.22.1-cp311-cp311-win_amd64.whl", hash = "sha256:f28a42bb322b4ca6d255531bb334a2b3e21f172e37c1741bd5e66bc4b7b61f03", size = 12689881, upload-time = "2025-07-10T19:15:35.501Z" }, + { url = "https://files.pythonhosted.org/packages/48/70/ca2a4d38a5deccd98caa145581becb20c53684f451e89eb3a39915620066/onnxruntime-1.22.1-cp312-cp312-macosx_13_0_universal2.whl", hash = "sha256:a938d11c0dc811badf78e435daa3899d9af38abee950d87f3ab7430eb5b3cf5a", size = 34342883, upload-time = "2025-07-10T19:15:38.223Z" }, + { url = "https://files.pythonhosted.org/packages/29/e5/00b099b4d4f6223b610421080d0eed9327ef9986785c9141819bbba0d396/onnxruntime-1.22.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:984cea2a02fcc5dfea44ade9aca9fe0f7a8a2cd6f77c258fc4388238618f3928", size = 14473861, upload-time = "2025-07-10T19:15:42.911Z" }, + { url = "https://files.pythonhosted.org/packages/0a/50/519828a5292a6ccd8d5cd6d2f72c6b36ea528a2ef68eca69647732539ffa/onnxruntime-1.22.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d39a530aff1ec8d02e365f35e503193991417788641b184f5b1e8c9a6d5ce8d", size = 16475713, upload-time = "2025-07-10T19:15:45.452Z" }, + { url = "https://files.pythonhosted.org/packages/5d/54/7139d463bb0a312890c9a5db87d7815d4a8cce9e6f5f28d04f0b55fcb160/onnxruntime-1.22.1-cp312-cp312-win_amd64.whl", hash = "sha256:6a64291d57ea966a245f749eb970f4fa05a64d26672e05a83fdb5db6b7d62f87", size = 12690910, upload-time = "2025-07-10T19:15:47.478Z" }, + { url = "https://files.pythonhosted.org/packages/e0/39/77cefa829740bd830915095d8408dce6d731b244e24b1f64fe3df9f18e86/onnxruntime-1.22.1-cp313-cp313-macosx_13_0_universal2.whl", hash = "sha256:d29c7d87b6cbed8fecfd09dca471832384d12a69e1ab873e5effbb94adc3e966", size = 34342026, upload-time = "2025-07-10T19:15:50.266Z" }, + { url = "https://files.pythonhosted.org/packages/d2/a6/444291524cb52875b5de980a6e918072514df63a57a7120bf9dfae3aeed1/onnxruntime-1.22.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:460487d83b7056ba98f1f7bac80287224c31d8149b15712b0d6f5078fcc33d0f", size = 14474014, upload-time = "2025-07-10T19:15:53.991Z" }, + { url = "https://files.pythonhosted.org/packages/87/9d/45a995437879c18beff26eacc2322f4227224d04c6ac3254dce2e8950190/onnxruntime-1.22.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b0c37070268ba4e02a1a9d28560cd00cd1e94f0d4f275cbef283854f861a65fa", size = 16475427, upload-time = "2025-07-10T19:15:56.067Z" }, + { url = "https://files.pythonhosted.org/packages/4c/06/9c765e66ad32a7e709ce4cb6b95d7eaa9cb4d92a6e11ea97c20ffecaf765/onnxruntime-1.22.1-cp313-cp313-win_amd64.whl", hash = "sha256:70980d729145a36a05f74b573435531f55ef9503bcda81fc6c3d6b9306199982", size = 12690841, upload-time = "2025-07-10T19:15:58.337Z" }, + { url = "https://files.pythonhosted.org/packages/52/8c/02af24ee1c8dce4e6c14a1642a7a56cebe323d2fa01d9a360a638f7e4b75/onnxruntime-1.22.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33a7980bbc4b7f446bac26c3785652fe8730ed02617d765399e89ac7d44e0f7d", size = 14479333, upload-time = "2025-07-10T19:16:00.544Z" }, + { url = "https://files.pythonhosted.org/packages/5d/15/d75fd66aba116ce3732bb1050401394c5ec52074c4f7ee18db8838dd4667/onnxruntime-1.22.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7e823624b015ea879d976cbef8bfaed2f7e2cc233d7506860a76dd37f8f381", size = 16477261, upload-time = "2025-07-10T19:16:03.226Z" }, +] + +[[package]] +name = "onshape-to-robot" +version = "1.7.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, + { name = "commentjson" }, + { name = "numpy" }, + { name = "numpy-stl" }, + { name = "python-dotenv" }, + { name = "requests" }, + { name = "transforms3d" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/99/be262505d2a41a0bb7267c3037b4a4ed58460cf0f84408aa23f998d02c7f/onshape_to_robot-1.7.6.tar.gz", hash = "sha256:71aa33710f58ddba566fd6f2b17b02506794eb9c5032f4adbae34ce7cf168780", size = 48227, upload-time = "2025-06-17T22:09:32.856Z" } + +[[package]] +name = "opencv-python" +version = "4.12.0.88" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/71/25c98e634b6bdeca4727c7f6d6927b056080668c5008ad3c8fc9e7f8f6ec/opencv-python-4.12.0.88.tar.gz", hash = "sha256:8b738389cede219405f6f3880b851efa3415ccd674752219377353f017d2994d", size = 95373294, upload-time = "2025-07-07T09:20:52.389Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/68/3da40142e7c21e9b1d4e7ddd6c58738feb013203e6e4b803d62cdd9eb96b/opencv_python-4.12.0.88-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:f9a1f08883257b95a5764bf517a32d75aec325319c8ed0f89739a57fae9e92a5", size = 37877727, upload-time = "2025-07-07T09:13:31.47Z" }, + { url = "https://files.pythonhosted.org/packages/33/7c/042abe49f58d6ee7e1028eefc3334d98ca69b030e3b567fe245a2b28ea6f/opencv_python-4.12.0.88-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:812eb116ad2b4de43ee116fcd8991c3a687f099ada0b04e68f64899c09448e81", size = 57326471, upload-time = "2025-07-07T09:13:41.26Z" }, + { url = "https://files.pythonhosted.org/packages/62/3a/440bd64736cf8116f01f3b7f9f2e111afb2e02beb2ccc08a6458114a6b5d/opencv_python-4.12.0.88-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:51fd981c7df6af3e8f70b1556696b05224c4e6b6777bdd2a46b3d4fb09de1a92", size = 45887139, upload-time = "2025-07-07T09:13:50.761Z" }, + { url = "https://files.pythonhosted.org/packages/68/1f/795e7f4aa2eacc59afa4fb61a2e35e510d06414dd5a802b51a012d691b37/opencv_python-4.12.0.88-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:092c16da4c5a163a818f120c22c5e4a2f96e0db4f24e659c701f1fe629a690f9", size = 67041680, upload-time = "2025-07-07T09:14:01.995Z" }, + { url = "https://files.pythonhosted.org/packages/02/96/213fea371d3cb2f1d537612a105792aa0a6659fb2665b22cad709a75bd94/opencv_python-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:ff554d3f725b39878ac6a2e1fa232ec509c36130927afc18a1719ebf4fbf4357", size = 30284131, upload-time = "2025-07-07T09:14:08.819Z" }, + { url = "https://files.pythonhosted.org/packages/fa/80/eb88edc2e2b11cd2dd2e56f1c80b5784d11d6e6b7f04a1145df64df40065/opencv_python-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:d98edb20aa932fd8ebd276a72627dad9dc097695b3d435a4257557bbb49a79d2", size = 39000307, upload-time = "2025-07-07T09:14:16.641Z" }, +] + +[[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 = "parso" +version = "0.8.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/5d/45a3553a253ac8763f3561371432a90bdbe6000fbdcf1397ffe502aa206c/pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860", size = 5316554, upload-time = "2025-07-01T09:13:39.342Z" }, + { url = "https://files.pythonhosted.org/packages/7c/c8/67c12ab069ef586a25a4a79ced553586748fad100c77c0ce59bb4983ac98/pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad", size = 4686548, upload-time = "2025-07-01T09:13:41.835Z" }, + { url = "https://files.pythonhosted.org/packages/2f/bd/6741ebd56263390b382ae4c5de02979af7f8bd9807346d068700dd6d5cf9/pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0", size = 5859742, upload-time = "2025-07-03T13:09:47.439Z" }, + { url = "https://files.pythonhosted.org/packages/ca/0b/c412a9e27e1e6a829e6ab6c2dca52dd563efbedf4c9c6aa453d9a9b77359/pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b", size = 7633087, upload-time = "2025-07-03T13:09:51.796Z" }, + { url = "https://files.pythonhosted.org/packages/59/9d/9b7076aaf30f5dd17e5e5589b2d2f5a5d7e30ff67a171eb686e4eecc2adf/pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50", size = 5963350, upload-time = "2025-07-01T09:13:43.865Z" }, + { url = "https://files.pythonhosted.org/packages/f0/16/1a6bf01fb622fb9cf5c91683823f073f053005c849b1f52ed613afcf8dae/pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae", size = 6631840, upload-time = "2025-07-01T09:13:46.161Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e6/6ff7077077eb47fde78739e7d570bdcd7c10495666b6afcd23ab56b19a43/pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9", size = 6074005, upload-time = "2025-07-01T09:13:47.829Z" }, + { url = "https://files.pythonhosted.org/packages/c3/3a/b13f36832ea6d279a697231658199e0a03cd87ef12048016bdcc84131601/pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e", size = 6708372, upload-time = "2025-07-01T09:13:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/6c/e4/61b2e1a7528740efbc70b3d581f33937e38e98ef3d50b05007267a55bcb2/pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6", size = 6277090, upload-time = "2025-07-01T09:13:53.915Z" }, + { url = "https://files.pythonhosted.org/packages/a9/d3/60c781c83a785d6afbd6a326ed4d759d141de43aa7365725cbcd65ce5e54/pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f", size = 6985988, upload-time = "2025-07-01T09:13:55.699Z" }, + { url = "https://files.pythonhosted.org/packages/9f/28/4f4a0203165eefb3763939c6789ba31013a2e90adffb456610f30f613850/pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f", size = 2422899, upload-time = "2025-07-01T09:13:57.497Z" }, + { url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531, upload-time = "2025-07-01T09:13:59.203Z" }, + { url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560, upload-time = "2025-07-01T09:14:01.101Z" }, + { url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978, upload-time = "2025-07-03T13:09:55.638Z" }, + { url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168, upload-time = "2025-07-03T13:10:00.37Z" }, + { url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053, upload-time = "2025-07-01T09:14:04.491Z" }, + { url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273, upload-time = "2025-07-01T09:14:06.235Z" }, + { url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043, upload-time = "2025-07-01T09:14:07.978Z" }, + { url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516, upload-time = "2025-07-01T09:14:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768, upload-time = "2025-07-01T09:14:11.921Z" }, + { url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055, upload-time = "2025-07-01T09:14:13.623Z" }, + { url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079, upload-time = "2025-07-01T09:14:15.268Z" }, + { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, + { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, + { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, + { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, + { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, + { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, + { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, + { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, + { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, + { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, + { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, + { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, + { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8b/209bd6b62ce8367f47e68a218bffac88888fdf2c9fcf1ecadc6c3ec1ebc7/pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967", size = 5270556, upload-time = "2025-07-01T09:16:09.961Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e6/231a0b76070c2cfd9e260a7a5b504fb72da0a95279410fa7afd99d9751d6/pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe", size = 4654625, upload-time = "2025-07-01T09:16:11.913Z" }, + { url = "https://files.pythonhosted.org/packages/13/f4/10cf94fda33cb12765f2397fc285fa6d8eb9c29de7f3185165b702fc7386/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c", size = 4874207, upload-time = "2025-07-03T13:11:10.201Z" }, + { url = "https://files.pythonhosted.org/packages/72/c9/583821097dc691880c92892e8e2d41fe0a5a3d6021f4963371d2f6d57250/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25", size = 6583939, upload-time = "2025-07-03T13:11:15.68Z" }, + { url = "https://files.pythonhosted.org/packages/3b/8e/5c9d410f9217b12320efc7c413e72693f48468979a013ad17fd690397b9a/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27", size = 4957166, upload-time = "2025-07-01T09:16:13.74Z" }, + { url = "https://files.pythonhosted.org/packages/62/bb/78347dbe13219991877ffb3a91bf09da8317fbfcd4b5f9140aeae020ad71/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a", size = 5581482, upload-time = "2025-07-01T09:16:16.107Z" }, + { url = "https://files.pythonhosted.org/packages/d9/28/1000353d5e61498aaeaaf7f1e4b49ddb05f2c6575f9d4f9f914a3538b6e1/pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f", size = 6984596, upload-time = "2025-07-01T09:16:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566, upload-time = "2025-07-01T09:16:19.801Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618, upload-time = "2025-07-01T09:16:21.818Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248, upload-time = "2025-07-03T13:11:20.738Z" }, + { url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963, upload-time = "2025-07-03T13:11:26.283Z" }, + { url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170, upload-time = "2025-07-01T09:16:23.762Z" }, + { url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505, upload-time = "2025-07-01T09:16:25.593Z" }, + { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598, upload-time = "2025-07-01T09:16:27.732Z" }, +] + +[[package]] +name = "pin" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, + { name = "cmeel-boost" }, + { name = "cmeel-urdfdom" }, + { name = "coal-library" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/00/0e2b8344ea7af3185909ddc91876abe0274d5b1257caf191414732495c9d/pin-3.4.0.tar.gz", hash = "sha256:95c8e9c707dad9c412247874ca3f8ac77f0d5f51e49f02856f88146478e2660b", size = 99748596, upload-time = "2025-02-13T01:08:55.83Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/4f/29ec215bab0de9c5b017ad4ad81aca8ba2dbba9d7bcefb38ce18dd1871f6/pin-3.4.0-0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e3ea1fa363908c8ac9f541bd3c136cb02d720fe3e85760459bc0f9152a9018ea", size = 14580514, upload-time = "2025-02-13T01:07:18.987Z" }, + { url = "https://files.pythonhosted.org/packages/64/58/b04a646078c8fba139e8b33314e1b28e5b0e6f00844fee72d25933553d66/pin-3.4.0-0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c5cc929c8c8849c20a00410426aad002fdf44af9467d077962d75332d2097ab", size = 13218379, upload-time = "2025-02-13T01:07:22.872Z" }, + { url = "https://files.pythonhosted.org/packages/03/fc/d15717bc94a92a561b18834e392b1dced81420dfaf08f197fa6cb8eba205/pin-3.4.0-0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ace2c10302fccd3d3e9dc7214b6b9e307cb88df84ebe365e46462e71ef3857ae", size = 17434017, upload-time = "2025-02-13T01:07:26.018Z" }, + { url = "https://files.pythonhosted.org/packages/08/89/bba3b9277ab96dc922f0b901befde0e53392e914754942d5ce1a1ef53d97/pin-3.4.0-0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:f0feb5a2325e9156e790d4f39c55cab812937e87c6d73a18f027d4afccc4b997", size = 17813130, upload-time = "2025-02-13T01:07:32.019Z" }, + { url = "https://files.pythonhosted.org/packages/17/7b/5e4e451a5c1106a651009cecaa469408bfec5962be9890aef8a4c6f8efdf/pin-3.4.0-0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:07f06f104c503aa72c134eac308c07ecc704c5f47dc5e4c6edaa31f9b42e5a28", size = 14580686, upload-time = "2025-02-13T01:07:36.383Z" }, + { url = "https://files.pythonhosted.org/packages/34/d7/549c1439d4ec7a505f6a4464743263868c3f2018daebc838af7976291d35/pin-3.4.0-0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:88e2fac5896c23f76e5d5fa49f023581baa9e703bfea26a0bb72750d07313d78", size = 13217948, upload-time = "2025-02-13T01:07:40.473Z" }, + { url = "https://files.pythonhosted.org/packages/18/8a/dc016fa16ae73d2d9fd3828bb6ee654479c155d644356523ffc0f0e2f749/pin-3.4.0-0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b041f7ef2ef18a4be7cb228662cf0d7061edd2ddc5cf30b54f1344dc0c491d38", size = 17432538, upload-time = "2025-02-13T01:07:43.516Z" }, + { url = "https://files.pythonhosted.org/packages/12/a0/df562a0e531531fc13db2e18d1b71691fc5f8ae174e026b38b4c771f4dc4/pin-3.4.0-0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8987a784028ade6145c0b5844a20accbb63bc8501f8d7260d67df6a0228678f1", size = 17812580, upload-time = "2025-02-13T01:07:47.452Z" }, + { url = "https://files.pythonhosted.org/packages/47/07/bd33ac55ed1ef54b0301c939d24b32dd3194a72bf3a6e3be2de815cba21e/pin-3.4.0-0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6a20fc936311039698cac062db89e48c5494c4953a989372b7981d741844324a", size = 14653652, upload-time = "2025-02-13T01:07:51.617Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ab/ead22716b69fd6a703c7d81b325c3f20a1af44cdbf5d0e9295a7ffc8a5ba/pin-3.4.0-0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5abd2c19a6bb63617aa951c722cb3bce7b633bca119a541baab1123a8d48c32", size = 13265144, upload-time = "2025-02-13T01:07:55.375Z" }, + { url = "https://files.pythonhosted.org/packages/59/af/c3ec76c2ba38ae4d419a091c34fd7976ea4f1ee3f36baf6242abb21a19e5/pin-3.4.0-0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e0547ea1665e8477968a22791216bcd3b70cd0c1c0091d417564ffabd1bb435e", size = 17298971, upload-time = "2025-02-13T01:07:58.72Z" }, + { url = "https://files.pythonhosted.org/packages/db/a4/72ba496b491dc0892af2bb9c98bf615c6ff2ea9690a63f1154f906b960f3/pin-3.4.0-0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:37941641077550264ef8e0f8a529f368414296e27b9f649467e185ab05445960", size = 17711678, upload-time = "2025-02-13T01:08:02.631Z" }, + { url = "https://files.pythonhosted.org/packages/03/3b/1f7021c8c81098dcef3dafaee8f0eae25520a9ea5277d15dff58e55f9796/pin-3.4.0-0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:964e055b147afb1705263c8ea1a9c574a2babd92d3b637f5255de4abbbdd4970", size = 14653665, upload-time = "2025-02-13T01:08:06.704Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e2/7a05c42df807b2070682cc2c1e86dce2964e6ef443bb385fca943a9c63ef/pin-3.4.0-0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c35af977fb85878ad6281b9b2d06bcfbcf353cd8b1a0f97342de55f2dd3ab70f", size = 13265140, upload-time = "2025-02-13T01:08:09.674Z" }, + { url = "https://files.pythonhosted.org/packages/1b/02/022f77ea0433f7a7153a711681a8b5520ba453b5e56c904274df30540f59/pin-3.4.0-0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:ba80feba64744da94d41ef64e430aeaf358085647061b90b57641d0108326363", size = 17298972, upload-time = "2025-02-13T01:08:14.036Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6a/87ffcfb152f24f8e8e3b0f2b4435f23b70786589f86fc2bb3f03d36c3fa4/pin-3.4.0-0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:66534969e155ac4bbdd9b96e96b076ef45d4d46d98e0c12ea9468d738f7b7ea2", size = 17711687, upload-time = "2025-02-13T01:08:20.651Z" }, +] + +[[package]] +name = "pip" +version = "25.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, +] + +[[package]] +name = "placo" +version = "0.9.14" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, + { name = "eiquadprog" }, + { name = "ischedule" }, + { name = "meshcat" }, + { name = "pin" }, + { name = "rhoban-cmeel-jsoncpp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/45/293c9afc05a018bd2e2d6ec88a44958f09724686c826f576b04775d0d19b/placo-0.9.14.tar.gz", hash = "sha256:2ac04ede402a60fdfff240bd06dbb01fcd7b291bdb7b2d1d5ef595e7ca581b74", size = 136457, upload-time = "2025-07-07T23:43:26.547Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/49/16f21051e19d8adc1bdc1393db05f08bde7663201376ff644b5619b5ea6c/placo-0.9.14-0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ed75678b1c0ca4c0cf614a16a60684247236f64b51781ae445eb941f96c74f79", size = 1684593, upload-time = "2025-07-07T23:42:45.863Z" }, + { url = "https://files.pythonhosted.org/packages/19/10/c77194ac946a6ebb0a283bc43e76758a9edf082c68a33b9b2d8c6e2e5362/placo-0.9.14-0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f2331d03d15dbdbf9a648f98b9434d359737367945e43bd8d8172c10fdbca899", size = 1549964, upload-time = "2025-07-07T23:42:47.965Z" }, + { url = "https://files.pythonhosted.org/packages/94/c5/e13748b59c751ae2e49edf28e8c97728714a7f1972bcb07a3d2d1976109f/placo-0.9.14-0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a182ff80ed09156d3ed6bd16c15163a44a67e4ab982df4644528703eae0b39f5", size = 2112464, upload-time = "2025-07-07T23:42:49.959Z" }, + { url = "https://files.pythonhosted.org/packages/e4/a9/78e031655a661a5f835387ecf9314b0965daffbcbb02c3f1a9e190fd887b/placo-0.9.14-0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:eb183ec0ec89c186e9b1cef7ee70878a27b0d5567d7673708a34753d6620ccab", size = 2177921, upload-time = "2025-07-07T23:42:51.462Z" }, + { url = "https://files.pythonhosted.org/packages/96/da/d10aaa6e9f596f61fcd08d17ccd58f20572f4361150b0ff557153e510e19/placo-0.9.14-0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1732cdada774c8a9dab70f5f8e8c361d8d2c62928d3b8d103811b2a2319bf1cd", size = 1684579, upload-time = "2025-07-07T23:42:54.211Z" }, + { url = "https://files.pythonhosted.org/packages/e1/94/8650034a283e2ca9b4b3eb95539368cd83d6bb624ed6f08cf4d7badb7345/placo-0.9.14-0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b870f0afe186776438d3f89df4e78618c077a771fa76250026964db67e125f7f", size = 1549950, upload-time = "2025-07-07T23:42:55.765Z" }, + { url = "https://files.pythonhosted.org/packages/33/f9/becef66e3b712cd8613b1132cb2337b53c8ea3714b550cfe558f80dc34a9/placo-0.9.14-0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:97f12f6f29608d301a92c108a948ed9e2a40ca12b5f046969572cdba13e67d52", size = 2111904, upload-time = "2025-07-07T23:42:57.609Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4f/3ec87720b6971af0430de17735666beabae6374066281dc71d908f049f56/placo-0.9.14-0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:878a39f4f45e728785891271a332a26181a0f7fa57a825dc7ac239f35ab4c091", size = 2178050, upload-time = "2025-07-07T23:42:59.123Z" }, + { url = "https://files.pythonhosted.org/packages/95/a8/03f3ab9d44b6aa754b652f1d652dd65ec94a4d3ec0432720d8b88a1605fe/placo-0.9.14-0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e41150e03a303f4c90f8a6138330caca21d520160021b7b9e14b90e2dbbcaf58", size = 1705653, upload-time = "2025-07-07T23:43:00.836Z" }, + { url = "https://files.pythonhosted.org/packages/14/39/e892d5c1ad42302490846dc5e6e3881d9d335bbeac18be1415b3ac4be58e/placo-0.9.14-0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03c1fe072f7d0075ab2a4ea85b3fb62fedf7e2c4d9613f96a156a576d29255e2", size = 1564825, upload-time = "2025-07-07T23:43:02.724Z" }, + { url = "https://files.pythonhosted.org/packages/1f/70/d5a0a079770a8cc4eaa977aa7438ff7861ce2227d0949ea1b5b3651caf0b/placo-0.9.14-0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ad96c8f3b5b0cf757048daed3e57b83765c402a27e5608a28496ed12cfad9692", size = 2092058, upload-time = "2025-07-07T23:43:04.109Z" }, + { url = "https://files.pythonhosted.org/packages/27/9f/a80f6ffed0bf7b383aea8ae94668bc7d0046f5909692c0af8c0e10ecc9d1/placo-0.9.14-0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:84ed219527c8868b4f520080c97280183ff311428d0e97225c53de8822c3783e", size = 2163101, upload-time = "2025-07-07T23:43:05.649Z" }, + { url = "https://files.pythonhosted.org/packages/09/d6/14fb3749b99be2ccd7d2329df2a20ab7709ce7245dc7930c65babafd6dd6/placo-0.9.14-0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:3d0d4638f685591d8263c2fb66861255816784b995ba2ba9d7cc6882d957e4cb", size = 1705647, upload-time = "2025-07-07T23:43:07.092Z" }, + { url = "https://files.pythonhosted.org/packages/d7/2e/be6081a1d2aec95e7436700f5e8b008328e5ae2390b07ad650e84687e32c/placo-0.9.14-0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:460a211febf9310074407e59ba3c8be52289148cc4f86868949ba9c462f381d2", size = 1564819, upload-time = "2025-07-07T23:43:08.961Z" }, + { url = "https://files.pythonhosted.org/packages/63/43/b18d82fa0237e0ec6598a7f47f0ffbc007b9c3913d8d76099cffcf9d5de1/placo-0.9.14-0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7b57831c2db2e808fd63c807149699c312d3ae09e1d6e10c9df3d12b2c66dee7", size = 2092073, upload-time = "2025-07-07T23:43:10.437Z" }, + { url = "https://files.pythonhosted.org/packages/72/a1/d92bf06980fb4c265394e797751059fdb7256ef425e6f8399697172374f4/placo-0.9.14-0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1d56205d66dd49672de18c23ef8e8fe6e5321b3d88ca4844e7117a47acaf9ce1", size = 2163105, upload-time = "2025-07-07T23:43:12.502Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, +] + +[[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 = "pollen-bmi088-imu-library" +version = "1.0.0rc1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ahrs" }, + { name = "numpy" }, + { name = "smbus3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/ca/f74143ec89fbc502c7d9fc6a4d20a7f56fad822389716daee5e2bfe9e364/pollen_bmi088_imu_library-1.0.0rc1.tar.gz", hash = "sha256:6a82eafa448807a87c7a9e1ed8ef395b0ce5f2f57fa536b5b3a3f428e72d8fcf", size = 3273, upload-time = "2025-10-30T08:57:43.422Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/0a/86991b5db3acb88bbe83ba1e586c1c401830c8dc3b95cb6e0637e60cd26d/pollen_bmi088_imu_library-1.0.0rc1-py3-none-any.whl", hash = "sha256:d13e7297a3042879c36b48f78c6d0e8426af2c5ca31efe312003c7cf74b657c8", size = 3748, upload-time = "2025-10-30T08:57:42.136Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/29/7cf5bbc236333876e4b41f56e06857a87937ce4bf91e117a6991a2dbb02a/pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16", size = 193792, upload-time = "2025-08-09T18:56:14.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/a5/987a405322d78a73b66e39e4a90e4ef156fd7141bf71df987e50717c321b/pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8", size = 220965, upload-time = "2025-08-09T18:56:13.192Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "propcache" +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, + { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, + { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, + { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, + { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, + { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, + { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, + { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, + { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, + { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, + { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, + { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, + { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, + { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, + { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, + { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, + { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, + { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, + { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, + { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, + { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, + { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, + { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, + { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, + { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, + { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, + { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, + { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, + { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, + { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, + { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, + { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, + { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, + { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, + { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, + { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, + { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, + { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, + { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, + { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, + { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, + { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, + { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, + { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, + { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, + { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, + { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, + { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, + { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, +] + +[[package]] +name = "protobuf" +version = "6.32.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/df/fb4a8eeea482eca989b51cffd274aac2ee24e825f0bf3cbce5281fa1567b/protobuf-6.32.0.tar.gz", hash = "sha256:a81439049127067fc49ec1d36e25c6ee1d1a2b7be930675f919258d03c04e7d2", size = 440614, upload-time = "2025-08-14T21:21:25.015Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/18/df8c87da2e47f4f1dcc5153a81cd6bca4e429803f4069a299e236e4dd510/protobuf-6.32.0-cp310-abi3-win32.whl", hash = "sha256:84f9e3c1ff6fb0308dbacb0950d8aa90694b0d0ee68e75719cb044b7078fe741", size = 424409, upload-time = "2025-08-14T21:21:12.366Z" }, + { url = "https://files.pythonhosted.org/packages/e1/59/0a820b7310f8139bd8d5a9388e6a38e1786d179d6f33998448609296c229/protobuf-6.32.0-cp310-abi3-win_amd64.whl", hash = "sha256:a8bdbb2f009cfc22a36d031f22a625a38b615b5e19e558a7b756b3279723e68e", size = 435735, upload-time = "2025-08-14T21:21:15.046Z" }, + { url = "https://files.pythonhosted.org/packages/cc/5b/0d421533c59c789e9c9894683efac582c06246bf24bb26b753b149bd88e4/protobuf-6.32.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d52691e5bee6c860fff9a1c86ad26a13afbeb4b168cd4445c922b7e2cf85aaf0", size = 426449, upload-time = "2025-08-14T21:21:16.687Z" }, + { url = "https://files.pythonhosted.org/packages/ec/7b/607764ebe6c7a23dcee06e054fd1de3d5841b7648a90fd6def9a3bb58c5e/protobuf-6.32.0-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:501fe6372fd1c8ea2a30b4d9be8f87955a64d6be9c88a973996cef5ef6f0abf1", size = 322869, upload-time = "2025-08-14T21:21:18.282Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/2e730bd1c25392fc32e3268e02446f0d77cb51a2c3a8486b1798e34d5805/protobuf-6.32.0-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:75a2aab2bd1aeb1f5dc7c5f33bcb11d82ea8c055c9becbb41c26a8c43fd7092c", size = 322009, upload-time = "2025-08-14T21:21:19.893Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f2/80ffc4677aac1bc3519b26bc7f7f5de7fce0ee2f7e36e59e27d8beb32dd1/protobuf-6.32.0-py3-none-any.whl", hash = "sha256:ba377e5b67b908c8f3072a57b63e2c6a4cbd18aea4ed98d2584350dbf46f2783", size = 169287, upload-time = "2025-08-14T21:21:23.515Z" }, +] + +[[package]] +name = "psutil" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" }, + { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" }, + { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" }, + { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pyarrow" +version = "21.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/c2/ea068b8f00905c06329a3dfcd40d0fcc2b7d0f2e355bdb25b65e0a0e4cd4/pyarrow-21.0.0.tar.gz", hash = "sha256:5051f2dccf0e283ff56335760cbc8622cf52264d67e359d5569541ac11b6d5bc", size = 1133487, upload-time = "2025-07-18T00:57:31.761Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/d9/110de31880016e2afc52d8580b397dbe47615defbf09ca8cf55f56c62165/pyarrow-21.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e563271e2c5ff4d4a4cbeb2c83d5cf0d4938b891518e676025f7268c6fe5fe26", size = 31196837, upload-time = "2025-07-18T00:54:34.755Z" }, + { url = "https://files.pythonhosted.org/packages/df/5f/c1c1997613abf24fceb087e79432d24c19bc6f7259cab57c2c8e5e545fab/pyarrow-21.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:fee33b0ca46f4c85443d6c450357101e47d53e6c3f008d658c27a2d020d44c79", size = 32659470, upload-time = "2025-07-18T00:54:38.329Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ed/b1589a777816ee33ba123ba1e4f8f02243a844fed0deec97bde9fb21a5cf/pyarrow-21.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7be45519b830f7c24b21d630a31d48bcebfd5d4d7f9d3bdb49da9cdf6d764edb", size = 41055619, upload-time = "2025-07-18T00:54:42.172Z" }, + { url = "https://files.pythonhosted.org/packages/44/28/b6672962639e85dc0ac36f71ab3a8f5f38e01b51343d7aa372a6b56fa3f3/pyarrow-21.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:26bfd95f6bff443ceae63c65dc7e048670b7e98bc892210acba7e4995d3d4b51", size = 42733488, upload-time = "2025-07-18T00:54:47.132Z" }, + { url = "https://files.pythonhosted.org/packages/f8/cc/de02c3614874b9089c94eac093f90ca5dfa6d5afe45de3ba847fd950fdf1/pyarrow-21.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bd04ec08f7f8bd113c55868bd3fc442a9db67c27af098c5f814a3091e71cc61a", size = 43329159, upload-time = "2025-07-18T00:54:51.686Z" }, + { url = "https://files.pythonhosted.org/packages/a6/3e/99473332ac40278f196e105ce30b79ab8affab12f6194802f2593d6b0be2/pyarrow-21.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9b0b14b49ac10654332a805aedfc0147fb3469cbf8ea951b3d040dab12372594", size = 45050567, upload-time = "2025-07-18T00:54:56.679Z" }, + { url = "https://files.pythonhosted.org/packages/7b/f5/c372ef60593d713e8bfbb7e0c743501605f0ad00719146dc075faf11172b/pyarrow-21.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:9d9f8bcb4c3be7738add259738abdeddc363de1b80e3310e04067aa1ca596634", size = 26217959, upload-time = "2025-07-18T00:55:00.482Z" }, + { url = "https://files.pythonhosted.org/packages/94/dc/80564a3071a57c20b7c32575e4a0120e8a330ef487c319b122942d665960/pyarrow-21.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c077f48aab61738c237802836fc3844f85409a46015635198761b0d6a688f87b", size = 31243234, upload-time = "2025-07-18T00:55:03.812Z" }, + { url = "https://files.pythonhosted.org/packages/ea/cc/3b51cb2db26fe535d14f74cab4c79b191ed9a8cd4cbba45e2379b5ca2746/pyarrow-21.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:689f448066781856237eca8d1975b98cace19b8dd2ab6145bf49475478bcaa10", size = 32714370, upload-time = "2025-07-18T00:55:07.495Z" }, + { url = "https://files.pythonhosted.org/packages/24/11/a4431f36d5ad7d83b87146f515c063e4d07ef0b7240876ddb885e6b44f2e/pyarrow-21.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:479ee41399fcddc46159a551705b89c05f11e8b8cb8e968f7fec64f62d91985e", size = 41135424, upload-time = "2025-07-18T00:55:11.461Z" }, + { url = "https://files.pythonhosted.org/packages/74/dc/035d54638fc5d2971cbf1e987ccd45f1091c83bcf747281cf6cc25e72c88/pyarrow-21.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:40ebfcb54a4f11bcde86bc586cbd0272bac0d516cfa539c799c2453768477569", size = 42823810, upload-time = "2025-07-18T00:55:16.301Z" }, + { url = "https://files.pythonhosted.org/packages/2e/3b/89fced102448a9e3e0d4dded1f37fa3ce4700f02cdb8665457fcc8015f5b/pyarrow-21.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8d58d8497814274d3d20214fbb24abcad2f7e351474357d552a8d53bce70c70e", size = 43391538, upload-time = "2025-07-18T00:55:23.82Z" }, + { url = "https://files.pythonhosted.org/packages/fb/bb/ea7f1bd08978d39debd3b23611c293f64a642557e8141c80635d501e6d53/pyarrow-21.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:585e7224f21124dd57836b1530ac8f2df2afc43c861d7bf3d58a4870c42ae36c", size = 45120056, upload-time = "2025-07-18T00:55:28.231Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0b/77ea0600009842b30ceebc3337639a7380cd946061b620ac1a2f3cb541e2/pyarrow-21.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:555ca6935b2cbca2c0e932bedd853e9bc523098c39636de9ad4693b5b1df86d6", size = 26220568, upload-time = "2025-07-18T00:55:32.122Z" }, + { url = "https://files.pythonhosted.org/packages/ca/d4/d4f817b21aacc30195cf6a46ba041dd1be827efa4a623cc8bf39a1c2a0c0/pyarrow-21.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3a302f0e0963db37e0a24a70c56cf91a4faa0bca51c23812279ca2e23481fccd", size = 31160305, upload-time = "2025-07-18T00:55:35.373Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9c/dcd38ce6e4b4d9a19e1d36914cb8e2b1da4e6003dd075474c4cfcdfe0601/pyarrow-21.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:b6b27cf01e243871390474a211a7922bfbe3bda21e39bc9160daf0da3fe48876", size = 32684264, upload-time = "2025-07-18T00:55:39.303Z" }, + { url = "https://files.pythonhosted.org/packages/4f/74/2a2d9f8d7a59b639523454bec12dba35ae3d0a07d8ab529dc0809f74b23c/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e72a8ec6b868e258a2cd2672d91f2860ad532d590ce94cdf7d5e7ec674ccf03d", size = 41108099, upload-time = "2025-07-18T00:55:42.889Z" }, + { url = "https://files.pythonhosted.org/packages/ad/90/2660332eeb31303c13b653ea566a9918484b6e4d6b9d2d46879a33ab0622/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b7ae0bbdc8c6674259b25bef5d2a1d6af5d39d7200c819cf99e07f7dfef1c51e", size = 42829529, upload-time = "2025-07-18T00:55:47.069Z" }, + { url = "https://files.pythonhosted.org/packages/33/27/1a93a25c92717f6aa0fca06eb4700860577d016cd3ae51aad0e0488ac899/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:58c30a1729f82d201627c173d91bd431db88ea74dcaa3885855bc6203e433b82", size = 43367883, upload-time = "2025-07-18T00:55:53.069Z" }, + { url = "https://files.pythonhosted.org/packages/05/d9/4d09d919f35d599bc05c6950095e358c3e15148ead26292dfca1fb659b0c/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:072116f65604b822a7f22945a7a6e581cfa28e3454fdcc6939d4ff6090126623", size = 45133802, upload-time = "2025-07-18T00:55:57.714Z" }, + { url = "https://files.pythonhosted.org/packages/71/30/f3795b6e192c3ab881325ffe172e526499eb3780e306a15103a2764916a2/pyarrow-21.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf56ec8b0a5c8c9d7021d6fd754e688104f9ebebf1bf4449613c9531f5346a18", size = 26203175, upload-time = "2025-07-18T00:56:01.364Z" }, + { url = "https://files.pythonhosted.org/packages/16/ca/c7eaa8e62db8fb37ce942b1ea0c6d7abfe3786ca193957afa25e71b81b66/pyarrow-21.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e99310a4ebd4479bcd1964dff9e14af33746300cb014aa4a3781738ac63baf4a", size = 31154306, upload-time = "2025-07-18T00:56:04.42Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e8/e87d9e3b2489302b3a1aea709aaca4b781c5252fcb812a17ab6275a9a484/pyarrow-21.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:d2fe8e7f3ce329a71b7ddd7498b3cfac0eeb200c2789bd840234f0dc271a8efe", size = 32680622, upload-time = "2025-07-18T00:56:07.505Z" }, + { url = "https://files.pythonhosted.org/packages/84/52/79095d73a742aa0aba370c7942b1b655f598069489ab387fe47261a849e1/pyarrow-21.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f522e5709379d72fb3da7785aa489ff0bb87448a9dc5a75f45763a795a089ebd", size = 41104094, upload-time = "2025-07-18T00:56:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/89/4b/7782438b551dbb0468892a276b8c789b8bbdb25ea5c5eb27faadd753e037/pyarrow-21.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:69cbbdf0631396e9925e048cfa5bce4e8c3d3b41562bbd70c685a8eb53a91e61", size = 42825576, upload-time = "2025-07-18T00:56:15.569Z" }, + { url = "https://files.pythonhosted.org/packages/b3/62/0f29de6e0a1e33518dec92c65be0351d32d7ca351e51ec5f4f837a9aab91/pyarrow-21.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:731c7022587006b755d0bdb27626a1a3bb004bb56b11fb30d98b6c1b4718579d", size = 43368342, upload-time = "2025-07-18T00:56:19.531Z" }, + { url = "https://files.pythonhosted.org/packages/90/c7/0fa1f3f29cf75f339768cc698c8ad4ddd2481c1742e9741459911c9ac477/pyarrow-21.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc56bc708f2d8ac71bd1dcb927e458c93cec10b98eb4120206a4091db7b67b99", size = 45131218, upload-time = "2025-07-18T00:56:23.347Z" }, + { url = "https://files.pythonhosted.org/packages/01/63/581f2076465e67b23bc5a37d4a2abff8362d389d29d8105832e82c9c811c/pyarrow-21.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:186aa00bca62139f75b7de8420f745f2af12941595bbbfa7ed3870ff63e25636", size = 26087551, upload-time = "2025-07-18T00:56:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ab/357d0d9648bb8241ee7348e564f2479d206ebe6e1c47ac5027c2e31ecd39/pyarrow-21.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:a7a102574faa3f421141a64c10216e078df467ab9576684d5cd696952546e2da", size = 31290064, upload-time = "2025-07-18T00:56:30.214Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8a/5685d62a990e4cac2043fc76b4661bf38d06efed55cf45a334b455bd2759/pyarrow-21.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:1e005378c4a2c6db3ada3ad4c217b381f6c886f0a80d6a316fe586b90f77efd7", size = 32727837, upload-time = "2025-07-18T00:56:33.935Z" }, + { url = "https://files.pythonhosted.org/packages/fc/de/c0828ee09525c2bafefd3e736a248ebe764d07d0fd762d4f0929dbc516c9/pyarrow-21.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:65f8e85f79031449ec8706b74504a316805217b35b6099155dd7e227eef0d4b6", size = 41014158, upload-time = "2025-07-18T00:56:37.528Z" }, + { url = "https://files.pythonhosted.org/packages/6e/26/a2865c420c50b7a3748320b614f3484bfcde8347b2639b2b903b21ce6a72/pyarrow-21.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:3a81486adc665c7eb1a2bde0224cfca6ceaba344a82a971ef059678417880eb8", size = 42667885, upload-time = "2025-07-18T00:56:41.483Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f9/4ee798dc902533159250fb4321267730bc0a107d8c6889e07c3add4fe3a5/pyarrow-21.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fc0d2f88b81dcf3ccf9a6ae17f89183762c8a94a5bdcfa09e05cfe413acf0503", size = 43276625, upload-time = "2025-07-18T00:56:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/5a/da/e02544d6997037a4b0d22d8e5f66bc9315c3671371a8b18c79ade1cefe14/pyarrow-21.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6299449adf89df38537837487a4f8d3bd91ec94354fdd2a7d30bc11c48ef6e79", size = 44951890, upload-time = "2025-07-18T00:56:52.568Z" }, + { url = "https://files.pythonhosted.org/packages/e5/4e/519c1bc1876625fe6b71e9a28287c43ec2f20f73c658b9ae1d485c0c206e/pyarrow-21.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:222c39e2c70113543982c6b34f3077962b44fca38c0bd9e68bb6781534425c10", size = 26371006, upload-time = "2025-07-18T00:56:56.379Z" }, +] + +[[package]] +name = "pycairo" +version = "1.28.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/d9/412da520de9052b7e80bfc810ec10f5cb3dbfa4aa3e23c2820dc61cdb3d0/pycairo-1.28.0.tar.gz", hash = "sha256:26ec5c6126781eb167089a123919f87baa2740da2cca9098be8b3a6b91cc5fbc", size = 662477, upload-time = "2025-04-14T20:11:08.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/67/6e5d6328c6037f0479017f51e97f5cbb79a68ed6e93f671dac17cb47bf2e/pycairo-1.28.0-cp310-cp310-win32.whl", hash = "sha256:53e6dbc98456f789965dad49ef89ce2c62f9a10fc96c8d084e14da0ffb73d8a6", size = 750438, upload-time = "2025-04-14T20:10:43.722Z" }, + { url = "https://files.pythonhosted.org/packages/00/79/e941186c2275333643504f57711b157ba17e81a2be805346585ad7fd382e/pycairo-1.28.0-cp310-cp310-win_amd64.whl", hash = "sha256:c8ab91a75025f984bc327ada335c787efb61c929ea0512063793cb36cee503d4", size = 841526, upload-time = "2025-04-14T20:10:45.557Z" }, + { url = "https://files.pythonhosted.org/packages/84/4b/3495baabd3c830bf80bf112a0e645342bfe8f3fc05ed6423444adf62d496/pycairo-1.28.0-cp310-cp310-win_arm64.whl", hash = "sha256:e955328c1a5147bf71ee94e206413ce15e12630296a79788fcd246c80e5337b8", size = 691866, upload-time = "2025-04-16T19:30:17.73Z" }, + { url = "https://files.pythonhosted.org/packages/c9/94/47d75f4eaac865f32e0550ed42869f8b3c4036f8e2b1e6163e9548f4d44f/pycairo-1.28.0-cp311-cp311-win32.whl", hash = "sha256:0fee15f5d72b13ba5fd065860312493dc1bca6ff2dce200ee9d704e11c94e60a", size = 750441, upload-time = "2025-04-14T20:10:48.311Z" }, + { url = "https://files.pythonhosted.org/packages/aa/02/1169a2917b043998585f9dd0f36da618947fdf9b6cc0e9ff9852aa4d548b/pycairo-1.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:6339979bfec8b58a06476094a9a5c104bd5a99932ddaff16ca0d9203d2f4482c", size = 841536, upload-time = "2025-04-14T20:10:51.112Z" }, + { url = "https://files.pythonhosted.org/packages/eb/99/13031086fb4d4ea71568d9ce74e03afbb2e18047f1e6b4e8674851f0414f/pycairo-1.28.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6ae15392e28ebfc0b35d8dc05d395d3b6be4bad9ad4caecf0fa12c8e7150225", size = 691895, upload-time = "2025-04-16T19:30:20.724Z" }, + { url = "https://files.pythonhosted.org/packages/a9/d7/206d7945aac5c6c889e7fea4011410d1311455a1d8dfce66106d8d700b7f/pycairo-1.28.0-cp312-cp312-win32.whl", hash = "sha256:c00cfbb7f30eb7ca1d48886712932e2d91e8835a8496f4e423878296ceba573e", size = 750594, upload-time = "2025-04-14T20:10:53.72Z" }, + { url = "https://files.pythonhosted.org/packages/2e/ba/259fc9a4d3afdad1e5b9db52b9d8a5df67f70dd787167185e8ec8a1af007/pycairo-1.28.0-cp312-cp312-win_amd64.whl", hash = "sha256:d50d190f5033992b55050b9f337ee42a45c3568445d5e5d7987bab96c278d8a6", size = 841767, upload-time = "2025-04-14T20:10:56.711Z" }, + { url = "https://files.pythonhosted.org/packages/c0/08/aa0903612ea0e8686ad6af58d4fb9cbab8ee0b0831201cddf7abd578d045/pycairo-1.28.0-cp312-cp312-win_arm64.whl", hash = "sha256:957e0340ee1c279d197d4f7cfa96f6d8b48e453eec711fca999748d752468ff4", size = 691687, upload-time = "2025-04-16T19:30:23.729Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/c3e5ed55781dfe1b31eb4a2482aeae707671f3d36b0ea53a1722f4a3dfe9/pycairo-1.28.0-cp313-cp313-win32.whl", hash = "sha256:d13352429d8a08a1cb3607767d23d2fb32e4c4f9faa642155383980ec1478c24", size = 750594, upload-time = "2025-04-14T20:10:59.284Z" }, + { url = "https://files.pythonhosted.org/packages/8b/1c/ebadd290748aff3b6bc35431114d41e7a42f40a4b988c2aaf2dfed5d8156/pycairo-1.28.0-cp313-cp313-win_amd64.whl", hash = "sha256:082aef6b3a9dcc328fa648d38ed6b0a31c863e903ead57dd184b2e5f86790140", size = 841774, upload-time = "2025-04-14T20:11:01.79Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ce/a3f5f1946613cd8a4654322b878c59f273c6e9b01dfadadd3f609070e0b9/pycairo-1.28.0-cp313-cp313-win_arm64.whl", hash = "sha256:026afd53b75291917a7412d9fe46dcfbaa0c028febd46ff1132d44a53ac2c8b6", size = 691675, upload-time = "2025-04-16T19:30:26.565Z" }, + { url = "https://files.pythonhosted.org/packages/96/1b/1f5da2b2e44b33a5b269ff28af710b0a7903001d9cf8a40d00fc944a5092/pycairo-1.28.0-cp314-cp314-win32.whl", hash = "sha256:d0ab30585f536101ad6f09052fc3895e2a437ba57531ea07223d0e076248025d", size = 766699, upload-time = "2025-07-24T06:36:07.267Z" }, + { url = "https://files.pythonhosted.org/packages/c9/91/1d5f18bd3ed469b1de8f83bfbf8bd67d23439f075151b66740fd35356190/pycairo-1.28.0-cp314-cp314-win_amd64.whl", hash = "sha256:94f2ed204999ab95a0671a0fa948ffbb9f3d6fb8731fe787917f6d022d9c1c0f", size = 868725, upload-time = "2025-07-24T06:36:09.597Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.7" +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/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" }, + { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" }, + { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" }, + { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" }, + { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" }, + { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" }, + { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" }, + { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" }, + { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" }, + { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" }, + { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, + { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, + { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, + { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, + { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, + { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, + { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" }, + { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" }, + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, + { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" }, + { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" }, + { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" }, + { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" }, + { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" }, + { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" }, + { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" }, + { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, + { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, + { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, + { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, + { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, + { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, +] + +[[package]] +name = "pyee" +version = "11.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/10/88/c9a028db29f009170db6337a5096476a12448ffce437bbf91458fd5b5767/pyee-11.0.1.tar.gz", hash = "sha256:a642c51e3885a33ead087286e35212783a4e9b8d6514a10a5db4e57ac57b2b29", size = 27877, upload-time = "2023-10-14T17:50:00.259Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/40/bfe7fd2cb55ca7dbb4c56e9f0060567c3e84dd9bdf8a782261f1d2d7c32f/pyee-11.0.1-py3-none-any.whl", hash = "sha256:9bcc9647822234f42c228d88de63d0f9ffa881e87a87f9d36ddf5211f6ac977d", size = 15249, upload-time = "2023-10-14T17:49:57.906Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pygobject" +version = "3.46.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycairo" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/4a/f24ddf1d20cc4b56affc7921e29928559a06c922eb60077448392792b914/PyGObject-3.46.0.tar.gz", hash = "sha256:481437b05af0a66b7c366ea052710eb3aacbb979d22d30b797f7ec29347ab1e6", size = 723367, upload-time = "2023-09-10T09:56:26.737Z" } + +[[package]] +name = "pyngrok" +version = "7.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7b/64/e5646daaa4a84ecb368c09d42753f1c6e1a41b38579a36fda8ffe5716d9f/pyngrok-7.3.0.tar.gz", hash = "sha256:f2240e49b9dec9b27eba00f1444cd3cce7ac45d1bcc493a9b76ee63c2da9882c", size = 44266, upload-time = "2025-08-04T16:08:07.015Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/6b/664772910199399db3706243488eb3a986bd8435583caef9cf8359eecfaa/pyngrok-7.3.0-py3-none-any.whl", hash = "sha256:708c48276d3a887d4263f0f4bc8171e22d66df6cfa74a4857625c83160603166", size = 25394, upload-time = "2025-08-04T16:08:05.368Z" }, +] + +[[package]] +name = "pynput" +version = "1.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "evdev", marker = "'linux' in sys_platform" }, + { name = "pyobjc-framework-applicationservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, + { name = "python-xlib", marker = "'linux' in sys_platform" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f0/c3/dccf44c68225046df5324db0cc7d563a560635355b3e5f1d249468268a6f/pynput-1.8.1.tar.gz", hash = "sha256:70d7c8373ee98911004a7c938742242840a5628c004573d84ba849d4601df81e", size = 82289, upload-time = "2025-03-17T17:12:01.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/4f/ac3fa906ae8a375a536b12794128c5efacade9eaa917a35dfd27ce0c7400/pynput-1.8.1-py2.py3-none-any.whl", hash = "sha256:42dfcf27404459ca16ca889c8fb8ffe42a9fe54f722fd1a3e130728e59e768d2", size = 91693, upload-time = "2025-03-17T17:12:00.094Z" }, +] + +[[package]] +name = "pyobjc-core" +version = "11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/e9/0b85c81e2b441267bca707b5d89f56c2f02578ef8f3eafddf0e0c0b8848c/pyobjc_core-11.1.tar.gz", hash = "sha256:b63d4d90c5df7e762f34739b39cc55bc63dbcf9fb2fb3f2671e528488c7a87fe", size = 974602, upload-time = "2025-06-14T20:56:34.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/c5/9fa74ef6b83924e657c5098d37b36b66d1e16d13bc45c44248c6248e7117/pyobjc_core-11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4c7536f3e94de0a3eae6bb382d75f1219280aa867cdf37beef39d9e7d580173c", size = 676323, upload-time = "2025-06-14T20:44:44.675Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a7/55afc166d89e3fcd87966f48f8bca3305a3a2d7c62100715b9ffa7153a90/pyobjc_core-11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ec36680b5c14e2f73d432b03ba7c1457dc6ca70fa59fd7daea1073f2b4157d33", size = 671075, upload-time = "2025-06-14T20:44:46.594Z" }, + { url = "https://files.pythonhosted.org/packages/c0/09/e83228e878e73bf756749939f906a872da54488f18d75658afa7f1abbab1/pyobjc_core-11.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:765b97dea6b87ec4612b3212258024d8496ea23517c95a1c5f0735f96b7fd529", size = 677985, upload-time = "2025-06-14T20:44:48.375Z" }, + { url = "https://files.pythonhosted.org/packages/c5/24/12e4e2dae5f85fd0c0b696404ed3374ea6ca398e7db886d4f1322eb30799/pyobjc_core-11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:18986f83998fbd5d3f56d8a8428b2f3e0754fd15cef3ef786ca0d29619024f2c", size = 676431, upload-time = "2025-06-14T20:44:49.908Z" }, + { url = "https://files.pythonhosted.org/packages/f7/79/031492497624de4c728f1857181b06ce8c56444db4d49418fa459cba217c/pyobjc_core-11.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:8849e78cfe6595c4911fbba29683decfb0bf57a350aed8a43316976ba6f659d2", size = 719330, upload-time = "2025-06-14T20:44:51.621Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7d/6169f16a0c7ec15b9381f8bf33872baf912de2ef68d96c798ca4c6ee641f/pyobjc_core-11.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8cb9ed17a8d84a312a6e8b665dd22393d48336ea1d8277e7ad20c19a38edf731", size = 667203, upload-time = "2025-06-14T20:44:53.262Z" }, + { url = "https://files.pythonhosted.org/packages/49/0f/f5ab2b0e57430a3bec9a62b6153c0e79c05a30d77b564efdb9f9446eeac5/pyobjc_core-11.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:f2455683e807f8541f0d83fbba0f5d9a46128ab0d5cc83ea208f0bec759b7f96", size = 708807, upload-time = "2025-06-14T20:44:54.851Z" }, +] + +[[package]] +name = "pyobjc-framework-applicationservices" +version = "11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, + { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-framework-coretext" }, + { name = "pyobjc-framework-quartz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/3f/b33ce0cecc3a42f6c289dcbf9ff698b0d9e85f5796db2e9cb5dadccffbb9/pyobjc_framework_applicationservices-11.1.tar.gz", hash = "sha256:03fcd8c0c600db98fa8b85eb7b3bc31491701720c795e3f762b54e865138bbaf", size = 224842, upload-time = "2025-06-14T20:56:40.648Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/2b/b46566639b13354d348092f932b4debda2e8604c9b1b416eb3619676e997/pyobjc_framework_applicationservices-11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:89aa713f16f1de66efd82f3be77c632ad1068e51e0ef0c2b0237ac7c7f580814", size = 30991, upload-time = "2025-06-14T20:45:17.223Z" }, + { url = "https://files.pythonhosted.org/packages/39/2d/9fde6de0b2a95fbb3d77ba11b3cc4f289dd208f38cb3a28389add87c0f44/pyobjc_framework_applicationservices-11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cf45d15eddae36dec2330a9992fc852476b61c8f529874b9ec2805c768a75482", size = 30991, upload-time = "2025-06-14T20:45:18.169Z" }, + { url = "https://files.pythonhosted.org/packages/38/ec/46a5c710e2d7edf55105223c34fed5a7b7cc7aba7d00a3a7b0405d6a2d1a/pyobjc_framework_applicationservices-11.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f4a85ccd78bab84f7f05ac65ff9be117839dfc09d48c39edd65c617ed73eb01c", size = 31056, upload-time = "2025-06-14T20:45:18.925Z" }, + { url = "https://files.pythonhosted.org/packages/c4/06/c2a309e6f37bfa73a2a581d3301321b2033e25b249e2a01e417a3c34e799/pyobjc_framework_applicationservices-11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:385a89f4d0838c97a331e247519d9e9745aa3f7427169d18570e3c664076a63c", size = 31072, upload-time = "2025-06-14T20:45:19.707Z" }, + { url = "https://files.pythonhosted.org/packages/b4/5f/357bf498c27f1b4d48385860d8374b2569adc1522aabe32befd77089c070/pyobjc_framework_applicationservices-11.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f480fab20f3005e559c9d06c9a3874a1f1c60dde52c6d28a53ab59b45e79d55f", size = 31335, upload-time = "2025-06-14T20:45:20.462Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b6/797fdd81399fe8251196f29a621ba3f3f04d5c579d95fd304489f5558202/pyobjc_framework_applicationservices-11.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:e8dee91c6a14fd042f98819dc0ac4a182e0e816282565534032f0e544bfab143", size = 31196, upload-time = "2025-06-14T20:45:21.555Z" }, + { url = "https://files.pythonhosted.org/packages/68/45/47eba8d7cdf16d778240ed13fb405e8d712464170ed29d0463363a695194/pyobjc_framework_applicationservices-11.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:a0ce40a57a9b993793b6f72c4fd93f80618ef54a69d76a1da97b8360a2f3ffc5", size = 31446, upload-time = "2025-06-14T20:45:22.313Z" }, +] + +[[package]] +name = "pyobjc-framework-avfoundation" +version = "11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, + { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-framework-coreaudio" }, + { name = "pyobjc-framework-coremedia" }, + { name = "pyobjc-framework-quartz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/1f/90cdbce1d3b4861cbb17c12adf57daeec32477eb1df8d3f9ab8551bdadfb/pyobjc_framework_avfoundation-11.1.tar.gz", hash = "sha256:6663056cc6ca49af8de6d36a7fff498f51e1a9a7f1bde7afba718a8ceaaa7377", size = 832178, upload-time = "2025-06-14T20:56:46.329Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/b3/be739115eebb03ea38853ad2dcedf8a21da923415b0b6b4dc6f50c737863/pyobjc_framework_avfoundation-11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:09542590d1f3aa96d4d1a37712b98fd9657e250d9ea06ecdf2a8a59c837a2cb6", size = 70713, upload-time = "2025-06-14T20:45:51.427Z" }, + { url = "https://files.pythonhosted.org/packages/0f/48/31286b2b09a619d8047256d7180e0d511be71ab598e5f54f034977b59bbf/pyobjc_framework_avfoundation-11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a0ccbdba46b69dec1d12eea52eef56fcd63c492f73e41011bb72508b2aa2d0e", size = 70711, upload-time = "2025-06-14T20:45:52.461Z" }, + { url = "https://files.pythonhosted.org/packages/43/30/d5d03dd4a508bdaa2156ff379e9e109020de23cbb6316c5865d341aa6db1/pyobjc_framework_avfoundation-11.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94f065db4e87b1baebb5cf9f464cf9d82c5f903fff192001ebc974d9e3132c7e", size = 70746, upload-time = "2025-06-14T20:45:53.253Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/b8ced7700b0e931dc37d14b05e2bead28d2598c887832b3d697da55b1845/pyobjc_framework_avfoundation-11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e204d155a09c186601490e4402dcffb2845a5831079e389b47bd6a341fe5ee63", size = 70773, upload-time = "2025-06-14T20:45:54.059Z" }, + { url = "https://files.pythonhosted.org/packages/d6/4c/086f4713793aaabdb5134debbf1fdc6c7d4ef5a32a6b35529e2e69580ec8/pyobjc_framework_avfoundation-11.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:dd3965aad0b236b8ac12f216d688c1a22b963f63e7e4fdb7107dd6790e80ee12", size = 71352, upload-time = "2025-06-14T20:45:54.871Z" }, + { url = "https://files.pythonhosted.org/packages/a6/5f/d5c4b9812e22c6fdf234421f131efae7c3137e838bb9df9be8bb45cde97b/pyobjc_framework_avfoundation-11.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:1ab2108b652496b13b9758c295f0f6de53b6d12125cf574ddae84ce28044bce1", size = 71208, upload-time = "2025-06-14T20:45:56.057Z" }, + { url = "https://files.pythonhosted.org/packages/29/d0/dec23e1745a81f5576cba577fa7218d665f36250a8507eaaa83a84579abf/pyobjc_framework_avfoundation-11.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:5dd6ac6a57f86b7ed5ac0a965ce54328f6ce77816b4a1fbf0d85c06fb251867a", size = 71680, upload-time = "2025-06-14T20:45:57.091Z" }, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/c5/7a866d24bc026f79239b74d05e2cf3088b03263da66d53d1b4cf5207f5ae/pyobjc_framework_cocoa-11.1.tar.gz", hash = "sha256:87df76b9b73e7ca699a828ff112564b59251bb9bbe72e610e670a4dc9940d038", size = 5565335, upload-time = "2025-06-14T20:56:59.683Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/8f/67a7e166b615feb96385d886c6732dfb90afed565b8b1f34673683d73cd9/pyobjc_framework_cocoa-11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b27a5bdb3ab6cdeb998443ff3fce194ffae5f518c6a079b832dbafc4426937f9", size = 388187, upload-time = "2025-06-14T20:46:49.74Z" }, + { url = "https://files.pythonhosted.org/packages/90/43/6841046aa4e257b6276cd23e53cacedfb842ecaf3386bb360fa9cc319aa1/pyobjc_framework_cocoa-11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7b9a9b8ba07f5bf84866399e3de2aa311ed1c34d5d2788a995bdbe82cc36cfa0", size = 388177, upload-time = "2025-06-14T20:46:51.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/da/41c0f7edc92ead461cced7e67813e27fa17da3c5da428afdb4086c69d7ba/pyobjc_framework_cocoa-11.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806de56f06dfba8f301a244cce289d54877c36b4b19818e3b53150eb7c2424d0", size = 388983, upload-time = "2025-06-14T20:46:52.591Z" }, + { url = "https://files.pythonhosted.org/packages/4e/0b/a01477cde2a040f97e226f3e15e5ffd1268fcb6d1d664885a95ba592eca9/pyobjc_framework_cocoa-11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:54e93e1d9b0fc41c032582a6f0834befe1d418d73893968f3f450281b11603da", size = 389049, upload-time = "2025-06-14T20:46:53.757Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/64cf2661f6ab7c124d0486ec6d1d01a9bb2838a0d2a46006457d8c5e6845/pyobjc_framework_cocoa-11.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:fd5245ee1997d93e78b72703be1289d75d88ff6490af94462b564892e9266350", size = 393110, upload-time = "2025-06-14T20:46:54.894Z" }, + { url = "https://files.pythonhosted.org/packages/33/87/01e35c5a3c5bbdc93d5925366421e10835fcd7b23347b6c267df1b16d0b3/pyobjc_framework_cocoa-11.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:aede53a1afc5433e1e7d66568cc52acceeb171b0a6005407a42e8e82580b4fc0", size = 392644, upload-time = "2025-06-14T20:46:56.503Z" }, + { url = "https://files.pythonhosted.org/packages/c1/7c/54afe9ffee547c41e1161691e72067a37ed27466ac71c089bfdcd07ca70d/pyobjc_framework_cocoa-11.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:1b5de4e1757bb65689d6dc1f8d8717de9ec8587eb0c4831c134f13aba29f9b71", size = 396742, upload-time = "2025-06-14T20:46:57.64Z" }, +] + +[[package]] +name = "pyobjc-framework-coreaudio" +version = "11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, + { name = "pyobjc-framework-cocoa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/c0/4ab6005cf97e534725b0c14b110d4864b367c282b1c5b0d8f42aad74a83f/pyobjc_framework_coreaudio-11.1.tar.gz", hash = "sha256:b7b89540ae7efc6c1e3208ac838ef2acfc4d2c506dd629d91f6b3b3120e55c1b", size = 141032, upload-time = "2025-06-14T20:57:04.348Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/fd/59bcaa6436c27d3da4ea147da4e6f723606317e38e7101f8b191b687176d/pyobjc_framework_coreaudio-11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:551c8aac6fdfbd34c3e2d4ce90b36a411e81be20581b978fa4da1a495489792d", size = 35380, upload-time = "2025-06-14T20:47:13.306Z" }, + { url = "https://files.pythonhosted.org/packages/54/1d/81339c1087519a9f125396c717b85a05b49c2c54137bdf4ca01c1ccb6239/pyobjc_framework_coreaudio-11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:73a46f0db2fa8ca2e8c47c3ddcc2751e67a0f8600246a6718553b15ee0dbbdb6", size = 35383, upload-time = "2025-06-14T20:47:14.234Z" }, + { url = "https://files.pythonhosted.org/packages/3d/fe/c43521642db98a4ec29fa535781c1316342bb52d5fc709696cbb1e8ca6cd/pyobjc_framework_coreaudio-11.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2538d1242dab4e27efb346eafbad50594e7e95597fa7220f0bab2099c825da55", size = 36765, upload-time = "2025-06-14T20:47:15.344Z" }, + { url = "https://files.pythonhosted.org/packages/82/9b/24d03ace273585de2d04385f06b895ce92caf8f5af430b060618ebce9dbe/pyobjc_framework_coreaudio-11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f73d996df1e721931d9f78050e1708735a173dbe3a76d9c71fb36e04f7208478", size = 36779, upload-time = "2025-06-14T20:47:16.123Z" }, + { url = "https://files.pythonhosted.org/packages/91/23/aa78365e45d0d04fc37e21cf7d69dc0d11e17b564e83cb5bcd98e89cdf45/pyobjc_framework_coreaudio-11.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:67dae111b78d91c26c753dbfbccc3ea5498cfda3dfe83c6f3778628b435e1e7b", size = 38480, upload-time = "2025-06-14T20:47:16.911Z" }, + { url = "https://files.pythonhosted.org/packages/3e/58/fc6d752a68f28567fa6d6d6a229122c829e2251f79ec7304fe0572e0fdcd/pyobjc_framework_coreaudio-11.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:9527a16a2b88b37bace578d499f21229f9a33b9afdcdd35d4f44374cb8eb9ab6", size = 36910, upload-time = "2025-06-14T20:47:17.69Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4c/c1c5624418dea005d9965ba690d3649afc33371ade213841ab51922af751/pyobjc_framework_coreaudio-11.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:6ba8b67f185c0e3f26b17ae525cee3f411bc8d6e9c9a8bfd899a28f594623d2f", size = 38567, upload-time = "2025-06-14T20:47:18.45Z" }, +] + +[[package]] +name = "pyobjc-framework-coremedia" +version = "11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, + { name = "pyobjc-framework-cocoa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/95/5d/81513acd219df77a89176f1574d936b81ad6f6002225cabb64d55efb7e8d/pyobjc_framework_coremedia-11.1.tar.gz", hash = "sha256:82cdc087f61e21b761e677ea618a575d4c0dbe00e98230bf9cea540cff931db3", size = 216389, upload-time = "2025-06-14T20:57:09.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/09/5e/396621c2b29353a3cb6d2caa4116583bf1073aedaf2ef196fec85d983696/pyobjc_framework_coremedia-11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91231957d25b6d191983166cf218189b5a01e267dadde35eb3a4c359dc473ccb", size = 29113, upload-time = "2025-06-14T20:47:47.978Z" }, + { url = "https://files.pythonhosted.org/packages/32/48/811ccea77d2c0d8156a489e2900298502eb6648d9c041c7f0c514c8f8a29/pyobjc_framework_coremedia-11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aacf47006e1c6bf6124fb2b5016a8d5fd5cf504b6b488f9eba4e389ab0f0a051", size = 29118, upload-time = "2025-06-14T20:47:48.895Z" }, + { url = "https://files.pythonhosted.org/packages/2c/d1/b3d004d6a2d2188d196779d92fe8cfa2533f5722cd216fbc4f0cffc63b24/pyobjc_framework_coremedia-11.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ea5055298af91e463ffa7977d573530f9bada57b8f2968dcc76a75e339b9a598", size = 29015, upload-time = "2025-06-14T20:47:49.655Z" }, + { url = "https://files.pythonhosted.org/packages/1c/23/cafd29011d14eac27fc55770157ebb8e02ffed9f75e01f24e97616417c4c/pyobjc_framework_coremedia-11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7ecdb64c743ffe9fd3949c7cc9109891b9f399a0852717fcb969d33c4e7ba527", size = 29031, upload-time = "2025-06-14T20:47:50.395Z" }, + { url = "https://files.pythonhosted.org/packages/de/a6/ca85b7d9d000e8e2748bcacde356278cb90f6ca9aed54dce6a42d1716ba8/pyobjc_framework_coremedia-11.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:969ce357c616f6835f47e27d1e73964374cdb671476571dfd358894a8ced06f2", size = 29094, upload-time = "2025-06-14T20:47:51.318Z" }, + { url = "https://files.pythonhosted.org/packages/b8/3d/56d530cf504a6eef84f51c8f6f845af8b947f6108e41db5e0b5189d5a667/pyobjc_framework_coremedia-11.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:bf1da05c297776c297ab3489ebf18d954efdff530acbdd6e70c32be811e20ec6", size = 29043, upload-time = "2025-06-14T20:47:52.092Z" }, + { url = "https://files.pythonhosted.org/packages/a4/bc/b237ecd4954a0f07450469236ca45412edb7d8715ff7fc175ac519e7c472/pyobjc_framework_coremedia-11.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:aa942d9ad0cf5bc4d3ede8779c3fac2f04cf3857687f2fb8505bae3378d04b95", size = 29111, upload-time = "2025-06-14T20:47:53.083Z" }, +] + +[[package]] +name = "pyobjc-framework-coretext" +version = "11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, + { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-framework-quartz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/65/e9/d3231c4f87d07b8525401fd6ad3c56607c9e512c5490f0a7a6abb13acab6/pyobjc_framework_coretext-11.1.tar.gz", hash = "sha256:a29bbd5d85c77f46a8ee81d381b847244c88a3a5a96ac22f509027ceceaffaf6", size = 274702, upload-time = "2025-06-14T20:57:16.059Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/0c/0117d5353b1d18f8f8dd1e0f48374e4819cfcf3e8c34c676353e87320e8f/pyobjc_framework_coretext-11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:515be6beb48c084ee413c00c4e9fbd6e730c1b8a24270f4c618fc6c7ba0011ce", size = 30072, upload-time = "2025-06-14T20:48:33.341Z" }, + { url = "https://files.pythonhosted.org/packages/4c/59/d6cc5470157cfd328b2d1ee2c1b6f846a5205307fce17291b57236d9f46e/pyobjc_framework_coretext-11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4f4d2d2a6331fa64465247358d7aafce98e4fb654b99301a490627a073d021e", size = 30072, upload-time = "2025-06-14T20:48:34.248Z" }, + { url = "https://files.pythonhosted.org/packages/32/67/9cc5189c366e67dc3e5b5976fac73cc6405841095f795d3fa0d5fc43d76a/pyobjc_framework_coretext-11.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1597bf7234270ee1b9963bf112e9061050d5fb8e1384b3f50c11bde2fe2b1570", size = 30175, upload-time = "2025-06-14T20:48:35.023Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d1/6ec2ef4f8133177203a742d5db4db90bbb3ae100aec8d17f667208da84c9/pyobjc_framework_coretext-11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:37e051e8f12a0f47a81b8efc8c902156eb5bc3d8123c43e5bd4cebd24c222228", size = 30180, upload-time = "2025-06-14T20:48:35.766Z" }, + { url = "https://files.pythonhosted.org/packages/0a/84/d4a95e49f6af59503ba257fbed0471b6932f0afe8b3725c018dd3ba40150/pyobjc_framework_coretext-11.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:56a3a02202e0d50be3c43e781c00f9f1859ab9b73a8342ff56260b908e911e37", size = 30768, upload-time = "2025-06-14T20:48:36.869Z" }, + { url = "https://files.pythonhosted.org/packages/64/4c/16e1504e06a5cb23eec6276835ddddb087637beba66cf84b5c587eba99be/pyobjc_framework_coretext-11.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:15650ba99692d00953e91e53118c11636056a22c90d472020f7ba31500577bf5", size = 30155, upload-time = "2025-06-14T20:48:37.948Z" }, + { url = "https://files.pythonhosted.org/packages/ad/a4/cbfa9c874b2770fb1ba5c38c42b0e12a8b5aa177a5a86d0ad49b935aa626/pyobjc_framework_coretext-11.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:fb27f66a56660c31bb956191d64b85b95bac99cfb833f6e99622ca0ac4b3ba12", size = 30768, upload-time = "2025-06-14T20:48:38.734Z" }, +] + +[[package]] +name = "pyobjc-framework-quartz" +version = "11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, + { name = "pyobjc-framework-cocoa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/ac/6308fec6c9ffeda9942fef72724f4094c6df4933560f512e63eac37ebd30/pyobjc_framework_quartz-11.1.tar.gz", hash = "sha256:a57f35ccfc22ad48c87c5932818e583777ff7276605fef6afad0ac0741169f75", size = 3953275, upload-time = "2025-06-14T20:58:17.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/62/f8d9bb4cba92d5f220327cf1def2c2c5be324880d54ee57e7bea43aa28b2/pyobjc_framework_quartz-11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b5ef75c416b0209e25b2eb07a27bd7eedf14a8c6b2f968711969d45ceceb0f84", size = 215586, upload-time = "2025-06-14T20:53:34.018Z" }, + { url = "https://files.pythonhosted.org/packages/77/cb/38172fdb350b3f47e18d87c5760e50f4efbb4da6308182b5e1310ff0cde4/pyobjc_framework_quartz-11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2d501fe95ef15d8acf587cb7dc4ab4be3c5a84e2252017da8dbb7df1bbe7a72a", size = 215565, upload-time = "2025-06-14T20:53:35.262Z" }, + { url = "https://files.pythonhosted.org/packages/9b/37/ee6e0bdd31b3b277fec00e5ee84d30eb1b5b8b0e025095e24ddc561697d0/pyobjc_framework_quartz-11.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9ac806067541917d6119b98d90390a6944e7d9bd737f5c0a79884202327c9204", size = 216410, upload-time = "2025-06-14T20:53:36.346Z" }, + { url = "https://files.pythonhosted.org/packages/bd/27/4f4fc0e6a0652318c2844608dd7c41e49ba6006ee5fb60c7ae417c338357/pyobjc_framework_quartz-11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43a1138280571bbf44df27a7eef519184b5c4183a588598ebaaeb887b9e73e76", size = 216816, upload-time = "2025-06-14T20:53:37.358Z" }, + { url = "https://files.pythonhosted.org/packages/b8/8a/1d15e42496bef31246f7401aad1ebf0f9e11566ce0de41c18431715aafbc/pyobjc_framework_quartz-11.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b23d81c30c564adf6336e00b357f355b35aad10075dd7e837cfd52a9912863e5", size = 221941, upload-time = "2025-06-14T20:53:38.34Z" }, + { url = "https://files.pythonhosted.org/packages/32/a8/a3f84d06e567efc12c104799c7fd015f9bea272a75f799eda8b79e8163c6/pyobjc_framework_quartz-11.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:07cbda78b4a8fcf3a2d96e047a2ff01f44e3e1820f46f0f4b3b6d77ff6ece07c", size = 221312, upload-time = "2025-06-14T20:53:39.435Z" }, + { url = "https://files.pythonhosted.org/packages/76/ef/8c08d4f255bb3efe8806609d1f0b1ddd29684ab0f9ffb5e26d3ad7957b29/pyobjc_framework_quartz-11.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:39d02a3df4b5e3eee1e0da0fb150259476910d2a9aa638ab94153c24317a9561", size = 226353, upload-time = "2025-06-14T20:53:40.655Z" }, +] + +[[package]] +name = "pyopengl" +version = "3.1.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/16/912b7225d56284859cd9a672827f18be43f8012f8b7b932bc4bd959a298e/pyopengl-3.1.10.tar.gz", hash = "sha256:c4a02d6866b54eb119c8e9b3fb04fa835a95ab802dd96607ab4cdb0012df8335", size = 1915580, upload-time = "2025-08-18T02:33:01.76Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/e4/1ba6f44e491c4eece978685230dde56b14d51a0365bc1b774ddaa94d14cd/pyopengl-3.1.10-py3-none-any.whl", hash = "sha256:794a943daced39300879e4e47bd94525280685f42dbb5a998d336cfff151d74f", size = 3194996, upload-time = "2025-08-18T02:32:59.902Z" }, +] + +[[package]] +name = "pyreadline3" +version = "3.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/49/4cea918a08f02817aabae639e3d0ac046fef9f9180518a3ad394e22da148/pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7", size = 99839, upload-time = "2024-09-19T02:40:10.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6", size = 83178, upload-time = "2024-09-19T02:40:08.598Z" }, +] + +[[package]] +name = "pyserial" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/7d/ae3f0a63f41e4d2f6cb66a5b57197850f919f59e558159a4dd3a818f5082/pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", size = 159125, upload-time = "2020-11-23T03:59:15.045Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0", size = 90585, upload-time = "2020-11-23T03:59:13.41Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "python-utils" +version = "3.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/4c/ef8b7b1046d65c1f18ca31e5235c7d6627ca2b3f389ab1d44a74d22f5cc9/python_utils-3.9.1.tar.gz", hash = "sha256:eb574b4292415eb230f094cbf50ab5ef36e3579b8f09e9f2ba74af70891449a0", size = 35403, upload-time = "2024-11-26T00:38:58.736Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/69/31c82567719b34d8f6b41077732589104883771d182a9f4ff3e71430999a/python_utils-3.9.1-py2.py3-none-any.whl", hash = "sha256:0273d7363c7ad4b70999b2791d5ba6b55333d6f7a4e4c8b6b39fb82b5fab4613", size = 32078, upload-time = "2024-11-26T00:38:57.488Z" }, +] + +[[package]] +name = "python-xlib" +version = "0.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068, upload-time = "2022-12-25T18:53:00.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/b8/ff33610932e0ee81ae7f1269c890f697d56ff74b9f5b2ee5d9b7fa2c5355/python_xlib-0.33-py2.py3-none-any.whl", hash = "sha256:c3534038d42e0df2f1392a1b30a15a4ff5fdc2b86cfa94f072bf11b10a164398", size = 182185, upload-time = "2022-12-25T18:52:58.662Z" }, +] + +[[package]] +name = "pyusb" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/6b/ce3727395e52b7b76dfcf0c665e37d223b680b9becc60710d4bc08b7b7cb/pyusb-1.3.1.tar.gz", hash = "sha256:3af070b607467c1c164f49d5b0caabe8ac78dbed9298d703a8dbf9df4052d17e", size = 77281, upload-time = "2025-01-08T23:45:01.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/b8/27e6312e86408a44fe16bd28ee12dd98608b39f7e7e57884a24e8f29b573/pyusb-1.3.1-py3-none-any.whl", hash = "sha256:bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430", size = 58465, upload-time = "2025-01-08T23:45:00.029Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, + { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, + { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, + { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, + { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, + { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, + { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, + { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, + { url = "https://files.pythonhosted.org/packages/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328, upload-time = "2025-09-08T23:07:45.946Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803, upload-time = "2025-09-08T23:07:47.551Z" }, + { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836, upload-time = "2025-09-08T23:07:49.436Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c4/2a6fe5111a01005fc7af3878259ce17684fabb8852815eda6225620f3c59/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", size = 857038, upload-time = "2025-09-08T23:07:51.234Z" }, + { url = "https://files.pythonhosted.org/packages/cb/eb/bfdcb41d0db9cd233d6fb22dc131583774135505ada800ebf14dfb0a7c40/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", size = 1657531, upload-time = "2025-09-08T23:07:52.795Z" }, + { url = "https://files.pythonhosted.org/packages/ab/21/e3180ca269ed4a0de5c34417dfe71a8ae80421198be83ee619a8a485b0c7/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", size = 2034786, upload-time = "2025-09-08T23:07:55.047Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b1/5e21d0b517434b7f33588ff76c177c5a167858cc38ef740608898cd329f2/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", size = 1894220, upload-time = "2025-09-08T23:07:57.172Z" }, + { url = "https://files.pythonhosted.org/packages/03/f2/44913a6ff6941905efc24a1acf3d3cb6146b636c546c7406c38c49c403d4/pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", size = 567155, upload-time = "2025-09-08T23:07:59.05Z" }, + { url = "https://files.pythonhosted.org/packages/23/6d/d8d92a0eb270a925c9b4dd039c0b4dc10abc2fcbc48331788824ef113935/pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", size = 633428, upload-time = "2025-09-08T23:08:00.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/14/01afebc96c5abbbd713ecfc7469cfb1bc801c819a74ed5c9fad9a48801cb/pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", size = 559497, upload-time = "2025-09-08T23:08:02.15Z" }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, + { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, + { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, + { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, + { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, + { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" }, + { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" }, + { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" }, + { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" }, + { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" }, + { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" }, + { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, + { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265, upload-time = "2025-09-08T23:09:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208, upload-time = "2025-09-08T23:09:51.073Z" }, + { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747, upload-time = "2025-09-08T23:09:52.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cf/f2b3784d536250ffd4be70e049f3b60981235d70c6e8ce7e3ef21e1adb25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", size = 747371, upload-time = "2025-09-08T23:09:54.563Z" }, + { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" }, +] + +[[package]] +name = "reachy-mini" +version = "1.1.1" +source = { editable = "." } +dependencies = [ + { name = "aiohttp" }, + { name = "asgiref" }, + { name = "cv2-enumerate-cameras" }, + { name = "eclipse-zenoh" }, + { name = "fastapi" }, + { name = "huggingface-hub" }, + { name = "jinja2" }, + { name = "libusb-package" }, + { name = "log-throttling" }, + { name = "numpy" }, + { name = "opencv-python" }, + { name = "pip" }, + { name = "psutil" }, + { name = "pyserial" }, + { name = "pyusb" }, + { name = "reachy-mini-motor-controller" }, + { name = "reachy-mini-rust-kinematics" }, + { name = "scipy" }, + { name = "sounddevice" }, + { name = "soundfile" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[package.optional-dependencies] +dev = [ + { name = "mujoco" }, + { name = "mypy" }, + { name = "onshape-to-robot" }, + { name = "placo" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "rerun-sdk" }, + { name = "ruff" }, + { name = "rustypot" }, + { name = "types-requests" }, + { name = "urdf-parser-py" }, +] +examples = [ + { name = "pynput" }, +] +gstreamer = [ + { name = "gst-signalling" }, + { name = "pygobject" }, +] +mujoco = [ + { name = "mujoco" }, +] +nn-kinematics = [ + { name = "onnxruntime" }, +] +placo-kinematics = [ + { name = "placo" }, +] +rerun = [ + { name = "rerun-sdk" }, + { name = "urdf-parser-py" }, +] +wireless-version = [ + { name = "gpiozero" }, + { name = "lgpio" }, + { name = "nmcli" }, + { name = "pollen-bmi088-imu-library" }, + { name = "semver" }, +] + +[package.metadata] +requires-dist = [ + { name = "aiohttp" }, + { name = "asgiref" }, + { name = "cv2-enumerate-cameras", specifier = ">=1.2.1" }, + { name = "eclipse-zenoh", specifier = ">=1.4.0" }, + { name = "fastapi" }, + { name = "gpiozero", marker = "extra == 'wireless-version'", specifier = ">=2.0.0" }, + { name = "gst-signalling", marker = "extra == 'gstreamer'", specifier = ">=1.1.2" }, + { name = "huggingface-hub", specifier = "==0.34.4" }, + { name = "jinja2" }, + { name = "lgpio", marker = "extra == 'wireless-version'", specifier = ">=0.2.2.0" }, + { name = "libusb-package", specifier = ">=1.0.26.3" }, + { name = "log-throttling", specifier = "==0.0.3" }, + { name = "mujoco", marker = "extra == 'dev'", specifier = "==3.3.0" }, + { name = "mujoco", marker = "extra == 'mujoco'", specifier = "==3.3.0" }, + { name = "mypy", marker = "extra == 'dev'", specifier = "==1.18.2" }, + { name = "nmcli", marker = "extra == 'wireless-version'", specifier = ">=1.5" }, + { name = "numpy", specifier = ">=2.2.5" }, + { name = "onnxruntime", marker = "extra == 'nn-kinematics'", specifier = "==1.22.1" }, + { name = "onshape-to-robot", marker = "extra == 'dev'", specifier = "==1.7.6" }, + { name = "opencv-python", specifier = "<=5.0" }, + { name = "pip", specifier = ">=25" }, + { name = "placo", marker = "extra == 'dev'", specifier = "==0.9.14" }, + { name = "placo", marker = "extra == 'placo-kinematics'", specifier = "==0.9.14" }, + { name = "pollen-bmi088-imu-library", marker = "extra == 'wireless-version'" }, + { name = "pre-commit", marker = "extra == 'dev'" }, + { name = "psutil" }, + { name = "pygobject", marker = "extra == 'gstreamer'", specifier = ">=3.42.2,<=3.46.0" }, + { name = "pynput", marker = "extra == 'examples'" }, + { name = "pyserial" }, + { name = "pytest", marker = "extra == 'dev'" }, + { name = "pytest-asyncio", marker = "extra == 'dev'" }, + { name = "pyusb", specifier = ">=1.2.1" }, + { name = "reachy-mini-motor-controller", specifier = ">=1.4.2" }, + { name = "reachy-mini-rust-kinematics", specifier = ">=1.0.2" }, + { name = "rerun-sdk", marker = "extra == 'dev'", specifier = ">=0.27.2" }, + { name = "rerun-sdk", marker = "extra == 'rerun'", specifier = ">=0.27.2" }, + { name = "ruff", marker = "extra == 'dev'", specifier = "==0.12.0" }, + { name = "rustypot", marker = "extra == 'dev'", specifier = ">=1.4.0" }, + { name = "scipy", specifier = ">=1.15.3,<2.0.0" }, + { name = "semver", marker = "extra == 'wireless-version'", specifier = ">=3,<4" }, + { name = "sounddevice", specifier = "==0.5.1" }, + { name = "soundfile", specifier = "==0.13.1" }, + { name = "types-requests", marker = "extra == 'dev'" }, + { name = "urdf-parser-py", marker = "extra == 'dev'", specifier = "==0.0.4" }, + { name = "urdf-parser-py", marker = "extra == 'rerun'", specifier = "==0.0.4" }, + { name = "uvicorn", extras = ["standard"] }, +] +provides-extras = ["dev", "examples", "mujoco", "nn-kinematics", "placo-kinematics", "gstreamer", "rerun", "wireless-version"] + +[[package]] +name = "reachy-mini-motor-controller" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/8d/353b13636ebffae848c0d0b8c4bfc15c4673b059f62f9c310ee98986b0b7/reachy_mini_motor_controller-1.4.2.tar.gz", hash = "sha256:bd6e9f5c13394bc57478a09e76e01c28854ae0c80a9335a3a1b78dc80e0ee150", size = 28248, upload-time = "2025-11-25T17:56:55.263Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/54/1dfb498cea7c568a83878b77348abe4d93a1233dab22be566c45f89e154c/reachy_mini_motor_controller-1.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:193a11b9c5a3e85bb21305c09c67990c45c832bbb1d8ab836feb78700dadcd18", size = 586874, upload-time = "2025-11-25T17:56:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/3d/86/ca36d720dcc497c7557e467d6e891e26cd86ce0d44236750d689a6fa306d/reachy_mini_motor_controller-1.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8226ed36f5391112a1b0f1ca2658eee24e0e12233b33637b9ece83fa7e0f3e94", size = 572458, upload-time = "2025-11-25T17:56:16.317Z" }, + { url = "https://files.pythonhosted.org/packages/cd/46/41a03359e0c70cc34f73b569d3090d435c15ea248b01bf978a9eee259eaa/reachy_mini_motor_controller-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83607921aa369c8e0b3a89bd845c7f6989fc29e1847d46f01eb3af2f27f04b99", size = 641152, upload-time = "2025-11-25T17:55:55.287Z" }, + { url = "https://files.pythonhosted.org/packages/80/cb/9e395e02f47c301bc32ab085f48a9be9c741911b9d2fc0d1131d46a72660/reachy_mini_motor_controller-1.4.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a31e530b41514a81ad43db5ff31d4a77a6f91034d36d7646853beeaafa7a150d", size = 647600, upload-time = "2025-11-25T17:56:01.073Z" }, + { url = "https://files.pythonhosted.org/packages/ee/45/81b45006257c6de17db7b8420d9039f23367db56ba9a29a78962dc6bcf42/reachy_mini_motor_controller-1.4.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5216ee318c9f20d5bc15e8aa8c96d60b989cf4e4ebf762edf20f6de2ee32ecb", size = 695967, upload-time = "2025-11-25T17:56:06.522Z" }, + { url = "https://files.pythonhosted.org/packages/40/88/4db598e736ab2cf8528ac875982d60477a904949549d80ee25200e3559aa/reachy_mini_motor_controller-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e081f5960143880db1e900108a1065ebe789772de5fa2838a1fa9903dbec7d5", size = 662013, upload-time = "2025-11-25T17:56:11.125Z" }, + { url = "https://files.pythonhosted.org/packages/99/00/839e6a9aa5005b239a0b06543f413421471550a0c660c54ab841805fa6ec/reachy_mini_motor_controller-1.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:30acdae78c8ef86bbd28b86d644a13c3c3f5c1fafafc14af8de03e509f188c83", size = 824336, upload-time = "2025-11-25T17:56:29.28Z" }, + { url = "https://files.pythonhosted.org/packages/75/64/cb81d550f1c36c2d14405622bb9fd666f2c6c100b504ac48c2af34ef0ad4/reachy_mini_motor_controller-1.4.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ebb98062d9894790a6028370c35e44e996b67bc5668bd0e4ba2973800056ca64", size = 911952, upload-time = "2025-11-25T17:56:35.665Z" }, + { url = "https://files.pythonhosted.org/packages/af/b8/9187fe5a246d2643a65282e0ecf511e8abe88634054660b3611c883fee50/reachy_mini_motor_controller-1.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a4283b91055fa66de52cedcce198f3fb262e4a1404346713c19f93d92a06f21", size = 854328, upload-time = "2025-11-25T17:56:41.999Z" }, + { url = "https://files.pythonhosted.org/packages/35/92/3cd324b1f9934e1ca82af73addb54c0ed2e212e897b4b1e054c887672ce3/reachy_mini_motor_controller-1.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:aa3c60cdbe6f7977a5fb6aaa11ced374b931c730f1ae8f68e87345012f810f53", size = 816960, upload-time = "2025-11-25T17:56:48.487Z" }, + { url = "https://files.pythonhosted.org/packages/54/09/29e7bbfbdbb1de9001341219df98314b10887baf53d1580f3c3db51c6eca/reachy_mini_motor_controller-1.4.2-cp310-cp310-win32.whl", hash = "sha256:a391ca67ab2bcd981ea7139b6171f3ba7f5b3b495bd85655c8d804278cc2ea8e", size = 378120, upload-time = "2025-11-25T17:57:01.73Z" }, + { url = "https://files.pythonhosted.org/packages/56/48/0b4a252484518e261377304c77327daa710b93b8a23c1b378a5c92337268/reachy_mini_motor_controller-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:38a8c63167b1121a208a3fcae65c17b5222ae95acf80245791c3a51240506fff", size = 401212, upload-time = "2025-11-25T17:56:56.039Z" }, + { url = "https://files.pythonhosted.org/packages/87/20/ac97ac49969c02e0384888c73cccf0b50a7bba48b18842a96b082a8c8e89/reachy_mini_motor_controller-1.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f405d5f948abd26e423f156fc0d165b69ec964d3a4cbfa7d2d952313cc0ff972", size = 586684, upload-time = "2025-11-25T17:56:24.378Z" }, + { url = "https://files.pythonhosted.org/packages/68/21/796b9fd0616600b93d5b74ce2b4eb0f525f2773aae8635a8c0506a4145d7/reachy_mini_motor_controller-1.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:835e1d7e9383615b2684fb97cf18065f80498bb7d7d9ba980f8fe295cda68109", size = 572449, upload-time = "2025-11-25T17:56:17.627Z" }, + { url = "https://files.pythonhosted.org/packages/07/bd/661f6a44bd436c069d38ba0fdc1c1524178c4d039dcd4326fb1918bccf91/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8403bb4b6c23c088493967c8445e5cd1ec4784f5c2ae1dab289fb9ba456055b", size = 642034, upload-time = "2025-11-25T17:55:56.725Z" }, + { url = "https://files.pythonhosted.org/packages/cd/82/12b52b5eeee59387866db9370e43894f66dda8feedc15be38a6963be3e9a/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1cf6d2a6dc10b5f8acc4c61a89e2e201eca84c6be741becbf9775084d29fc6e", size = 647692, upload-time = "2025-11-25T17:56:02.499Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a0/4ad6ca320e303de61135219c3b9953b1ec1f7375181dbaaa98a43b65ecae/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a366aa59f9bde4f80f6c03757e431a3cea80f0b18992401169b484cf8928d14", size = 696265, upload-time = "2025-11-25T17:56:07.722Z" }, + { url = "https://files.pythonhosted.org/packages/8f/98/14cb24c497c295f91b11144bf639304116630de6862ba3095fe3a18dc3ff/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df475384deadcea1c8b430839addecb84126002d54649283cce5e6465d51b543", size = 660553, upload-time = "2025-11-25T17:56:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/c1/cb/9bc5c91075d5e551deb2d93fae89062bb94b5edd5f658b66c97c11c460d8/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e09e99bb325405f414013ce7d13f7ed36af5b9278dce2ee6bda9ea2affe6baf", size = 825331, upload-time = "2025-11-25T17:56:30.458Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/fd404636cb980604ed82dea5e7ec9c4de78a76324d36ff9efc55bb7549a7/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2f35c0b54ed396b8d9eb98dfe6dcc6d3b059433c2181030591dc84483531a25b", size = 911925, upload-time = "2025-11-25T17:56:36.802Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1c/6d48c4c3c5c9705e20265db04f040f42d1955cb0ded817e8915684999386/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:af23d02daff28470be0e775ce63666bea06ad24ce948649751f7122996d5363d", size = 854410, upload-time = "2025-11-25T17:56:43.296Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b8/55955b7b47c8ed65bda69a221cd4805bad3d07c3c95b7002e67deec43dff/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:610d74c3cfc28854137d00d206a6b4c4942a371376611781a244376fe3175277", size = 815823, upload-time = "2025-11-25T17:56:50.274Z" }, + { url = "https://files.pythonhosted.org/packages/12/7c/20672ab40d1d25cdddf49cb969bfa36043d9b760e4e82275a32853846192/reachy_mini_motor_controller-1.4.2-cp311-cp311-win32.whl", hash = "sha256:abe319839f78cc3e4e8ed0ced0bc519f97bfc1e6ff6b320dc8f84b772123237d", size = 377969, upload-time = "2025-11-25T17:57:02.781Z" }, + { url = "https://files.pythonhosted.org/packages/b5/5e/0725df6e698fe9a83eff0f86d61c5e62878c864ce521c1a1c12645409bc5/reachy_mini_motor_controller-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:d8f7ea29ca78ee86206989c30066e17b213f4cc8975f0a275f092588cd2debc8", size = 401027, upload-time = "2025-11-25T17:56:57.17Z" }, + { url = "https://files.pythonhosted.org/packages/e6/6a/af2786310d5ccf84a48ff0153c7be2346ef3730ca540b20d998020c36cb8/reachy_mini_motor_controller-1.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a41cc1bdc08b2fbba681804c6143319a6b4ef2d30093910f9776db01c5ba9595", size = 583808, upload-time = "2025-11-25T17:56:25.635Z" }, + { url = "https://files.pythonhosted.org/packages/dc/d3/6354fd9b34b89d2b5a639c56ae05f393d2ae7cef187bfcce60a71a40202d/reachy_mini_motor_controller-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af3cdd5197f57108044af81166dd755214f469c368e79221521b9a698da45223", size = 570332, upload-time = "2025-11-25T17:56:18.828Z" }, + { url = "https://files.pythonhosted.org/packages/da/eb/d30bc7517a2f7c860b95978af73beede33819e717978d5560f4b5b8a2953/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed2537a512098664d73a7575af763acd5446fc2325f37cf3b9b84d37368b5f7f", size = 641541, upload-time = "2025-11-25T17:55:58.117Z" }, + { url = "https://files.pythonhosted.org/packages/a4/63/8f9c091d0b210ebc6aa7762fa09155456a088df987d73dc39cda4fb9c241/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:554dd7392b9fef86cca8c12d5861d8f17e2eb7e1d69b49c65fbf54e1410f9567", size = 648054, upload-time = "2025-11-25T17:56:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/ac/15/a1bebc7acfcb02c12ba32e00dc1f9346fdf2468e441f983daf86ee4c7df3/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3f6ddd91e0228b3396f2c027f3e55eac0d3c4f280968ec73f2bdac37cdeda0", size = 696773, upload-time = "2025-11-25T17:56:08.895Z" }, + { url = "https://files.pythonhosted.org/packages/06/9f/a3ab6942383198e4c105075582c2355350ef33f90ef4f877105ada181e88/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0b357e49773bcd338e24ed17c4a93fb1890c97513c4cd07eec8c4f3ba06bc48", size = 660676, upload-time = "2025-11-25T17:56:13.77Z" }, + { url = "https://files.pythonhosted.org/packages/4c/09/7da09c39d2722d6323ed719de95f2f7777699b0049b81d25aaff9b0cc2db/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dd05b4bbf2aa30674b2955edf8fefbdb90b522077b3c549719afd4a1d2dd325b", size = 824841, upload-time = "2025-11-25T17:56:31.967Z" }, + { url = "https://files.pythonhosted.org/packages/97/68/2c4e8160a3d8e0e20a61ad491dccb9d17febbaa434da83e38060a7517fc9/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:377d47674a0429a01f509d9fe9b52365a715ca132bfdf4956a3b5bb219723941", size = 912195, upload-time = "2025-11-25T17:56:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/14/5f/a547e59efd62518afbb616c9e3bc2f057662fdd209f75b218ef1917bcd7b/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:742c1e077669c198a4261acf3213789ed679846a25714e74e9774984862bbc7a", size = 855751, upload-time = "2025-11-25T17:56:44.595Z" }, + { url = "https://files.pythonhosted.org/packages/76/58/8720be3e52e302052c6d10e3c0937271e8c376d6e5a10b2dac480c94c7f2/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9b2eb49965f2dba93a1d251b0beb4b22b81f5b18946d53ff8761097011ffaa43", size = 815778, upload-time = "2025-11-25T17:56:51.74Z" }, + { url = "https://files.pythonhosted.org/packages/aa/52/7af3228652ce3503243cbce68d736af00b11afd07f0f96effa6faaca677d/reachy_mini_motor_controller-1.4.2-cp312-cp312-win32.whl", hash = "sha256:e59bd6a1b89b94da835b1fbe3f483470ea0471fdb1b92d0d4bbb93a24ab7a1aa", size = 377018, upload-time = "2025-11-25T17:57:03.815Z" }, + { url = "https://files.pythonhosted.org/packages/a0/7a/090705f6e62ec10107ea20e78fd8b8f26f6421b9db49f7bf5e275084aa02/reachy_mini_motor_controller-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:ae99c65942130ce04a01d50dae359694a42fa91ede864ead0defd9a693b30b05", size = 399902, upload-time = "2025-11-25T17:56:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ac/fc016600786fbcdc8d048f7e42c946aa1a488e382e08b83e39934ee5f381/reachy_mini_motor_controller-1.4.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:43064e6c97be9f6fb2494ebf56dda18daa0366cd70b32ee548818c908d8b3564", size = 583599, upload-time = "2025-11-25T17:56:27.042Z" }, + { url = "https://files.pythonhosted.org/packages/07/c7/c79c33cf46bbe6301fef5520445649ce10a85a30754fce975df41f7b80b7/reachy_mini_motor_controller-1.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ebe3f763c011ecd3dc4bd017dfc886ecaf455d9866cab1ce8b81116d22eb6a3d", size = 570309, upload-time = "2025-11-25T17:56:20.391Z" }, + { url = "https://files.pythonhosted.org/packages/78/e0/d301987769c1504549c06cf0ce8e132df48bde0f47d28a8768c25b7ed8ae/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c86146d3631dd73efb77d591f8a33c288b9ad394d3a6805c0685f3c5ec05266f", size = 641472, upload-time = "2025-11-25T17:55:59.645Z" }, + { url = "https://files.pythonhosted.org/packages/ff/52/7884ee1c04b480f8e34b4c97697a0977d314a22f6766fd5e246dfbddb404/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36052e08d331ae768f4b562e950eaa767ae4ee8a91e9334498c1bcbafe841514", size = 648510, upload-time = "2025-11-25T17:56:05.286Z" }, + { url = "https://files.pythonhosted.org/packages/03/56/619bb25bb31f96d6172d1bfd5bbf516b5985b595f6e1c7c82481fff95c55/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b2ac6712f7a5493bb3be276fa53bb9b9e4770f13783f26ff0a18e7fc6f800d4", size = 697241, upload-time = "2025-11-25T17:56:09.99Z" }, + { url = "https://files.pythonhosted.org/packages/5a/b2/c82a31cf252ff6fb4d4c59a208d8375159cc796326812b7e946eea5c00a4/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fcb404dc2021175d4339fb3a8f9334cd999bf8a0369e0dacb02c430edf46a0b", size = 660207, upload-time = "2025-11-25T17:56:15.23Z" }, + { url = "https://files.pythonhosted.org/packages/83/6e/b2d9aecc4144cffcee14b023da20b8850a11cd35375561a7e60be7132e10/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f482f61eecdeb72a7722399d0d549872a239023c263968f9e2ffac9ee69687dc", size = 824941, upload-time = "2025-11-25T17:56:33.129Z" }, + { url = "https://files.pythonhosted.org/packages/c0/68/72b7d8a405fe7b1785b2caaaf917958dc6691015f6c15089bfee8b35f65d/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:88e1a5c1d4afe4e695d589715f0628536fe7399ec6d2751025dd785f4282a62e", size = 912805, upload-time = "2025-11-25T17:56:39.585Z" }, + { url = "https://files.pythonhosted.org/packages/c0/62/4ce77e08ea5dc428835202723671026f52d46e20ee2642af24ecd2c64858/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2d5c9e2645d7c6b29a8a46b4ecef72540bb2c0f983349cfcaf7c681386e7a002", size = 856256, upload-time = "2025-11-25T17:56:45.894Z" }, + { url = "https://files.pythonhosted.org/packages/71/a6/c031586c9dd8fc735b427c5fcdd20d9360c02a6c61ab3cbb59589ad15d9d/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffb5331150c0cdfac9910d341e82d788bc173e473e893e3f8e54938ede1e3523", size = 815565, upload-time = "2025-11-25T17:56:52.837Z" }, + { url = "https://files.pythonhosted.org/packages/c6/e3/5316b60491ecf3384b1b51db49317bc175561411edcc83fe1398b68736f4/reachy_mini_motor_controller-1.4.2-cp313-cp313-win32.whl", hash = "sha256:6edcf88f5d4c1bf3948328a6f65cd4518fda8cefbe55fb884fda088f363c2b60", size = 377394, upload-time = "2025-11-25T17:57:05.059Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/41f4efca4abaf31bff5fa891ae0f594623539afd936abea51e0e546a6700/reachy_mini_motor_controller-1.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:602cf3294f54ceae4fa84d006aa0e97dcfcd99f7ee556cbbcf3546ac42fe8fb3", size = 399788, upload-time = "2025-11-25T17:56:59.383Z" }, + { url = "https://files.pythonhosted.org/packages/3a/0b/3b118d1ed20da22c3844c88247a78f6fdee679fff149d0e1ee64fc5d8aa8/reachy_mini_motor_controller-1.4.2-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:aedcbebb270c3e6ad8898aac321f82a3d3060898ee33d75ae181b0f1df278f93", size = 581082, upload-time = "2025-11-25T17:56:28.189Z" }, + { url = "https://files.pythonhosted.org/packages/5a/e7/c24da5194f16714d6f2a67fefaba817e2a22f68f58269500fa4495d6a29e/reachy_mini_motor_controller-1.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4d8d7626e3655a96266cc88d9ae1327c8b42512b61e8acaeb782d8d3352125c2", size = 567918, upload-time = "2025-11-25T17:56:21.842Z" }, + { url = "https://files.pythonhosted.org/packages/89/69/cc9a51e04c1523213a8f4121bb1c454293d287f8c0fc4998e2640d053169/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8b27d6769f12a4bf75b8b6cb0e0dc20d154bc1422ff9e046f530434050552b86", size = 823910, upload-time = "2025-11-25T17:56:34.482Z" }, + { url = "https://files.pythonhosted.org/packages/cd/76/1f283234ec0fb1b349a24930485a9c584d94f064eb4d3d2e32e5607ec64e/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:07118c8cafed873541fb716928a3d4f807ac6ac7f769d7307faa4cd9bead6e6d", size = 910812, upload-time = "2025-11-25T17:56:40.804Z" }, + { url = "https://files.pythonhosted.org/packages/5c/22/771e3e02872c319f999c5e0830787c926d2b74b976c71f041d5429c4f785/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:d552fdf890c3040232b2db783fc03ffcee230b633208e62b7a4265fa5d076598", size = 856433, upload-time = "2025-11-25T17:56:47.095Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a3/c897ed4e7a43d205d43a985669dfbbc3943d1df8a101038c5384f34b9617/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4b250a7763a72d6864ef4cdcec088d56e4d17947a10493f7347f2001502f05ed", size = 816617, upload-time = "2025-11-25T17:56:54.099Z" }, + { url = "https://files.pythonhosted.org/packages/03/67/63dc13fe0fad1bafe12122b10479b2e22bb4562e58ed45e14f18b3f076c5/reachy_mini_motor_controller-1.4.2-cp314-cp314-win32.whl", hash = "sha256:d9a6be4852cb8cbec2e19d2037234dce39defce653f3af9d4a46cd56d624c617", size = 376862, upload-time = "2025-11-25T17:57:06.232Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/0c4b6fc4a761ad8bd362f571d3693c94aa0c15121e122f1c01e3f38bc873/reachy_mini_motor_controller-1.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:aa7b6ca1b6db09e6249fdb5a31376974e82928292950cd7df4480cbd5707a425", size = 400104, upload-time = "2025-11-25T17:57:00.616Z" }, +] + +[[package]] +name = "reachy-mini-rust-kinematics" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/82/485aa2f28973eee6198b2af0db9e76314fd909076f06782228fa686f0e3d/reachy_mini_rust_kinematics-1.0.2.tar.gz", hash = "sha256:ca14f9193c73a53612a32cd0bfb9abecb13343bc94fe5feb95f54736b7f3cd64", size = 17187, upload-time = "2025-10-22T08:35:50.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/22/e3733bb138a59790d4355ecefb7ca2fd5cd2cd6af05bf26fa7ad24b6ace5/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:0137084968573589d1958372e140097441e4a8562ac44b7b94407d2fd1b05aa0", size = 303531, upload-time = "2025-10-22T08:34:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/8f/cf/1297187d79bc8268ca352702dac152a577ca96d25188767c1e4c43e51b5b/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c6457a28dd48a958d9ecf84a119736ae8cd0cfe7d002a518afe90ca8d4c1f4e", size = 279068, upload-time = "2025-10-22T08:34:43.331Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d9/e62dff886e73ecce02ad81dcfaf95e315d32f9134cf1db14c78a0a8dd851/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76067037701db3e4ef9bb99dca34d06cf4ffc6952f63d05d815db090ebb49330", size = 312732, upload-time = "2025-10-22T08:34:01.097Z" }, + { url = "https://files.pythonhosted.org/packages/b7/27/6915e8c2e97cb97569742e9f77865b27887b3ad916d5b70c8c034785e2fe/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ee7cb4a450cabe1265974be1cbf784ee85bab605d05a3173fe290e008f166e8", size = 321001, upload-time = "2025-10-22T08:34:13.385Z" }, + { url = "https://files.pythonhosted.org/packages/dc/77/b6a7b46bc18f3c042d6591cdd0cf733ffbe938d73993ebf9e172105913cc/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d77ace8803a4fabbcf2696c31a9b2ac0136a3c9db83ac83613782934fc6c94d", size = 337679, upload-time = "2025-10-22T08:34:34.543Z" }, + { url = "https://files.pythonhosted.org/packages/05/1d/ff2d5c5c9cc9f992983e07d455316e88f5ab2bea2f0859610c25737c0c87/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1515cc1028a472357cdf8005ee6a4e3ede919db6205af96bee215d6af967920", size = 351670, upload-time = "2025-10-22T08:34:24.985Z" }, + { url = "https://files.pythonhosted.org/packages/b8/4d/e3b34b00019d20b5dedd51e2a03500ea1fcb2bd2957b53ce730a9ac4c4cc/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:40b03c1a09a3aef083df78bdc0b160f1b1e18cb660c7f134817b82b3d8a7de88", size = 493329, upload-time = "2025-10-22T08:34:59.959Z" }, + { url = "https://files.pythonhosted.org/packages/6a/75/acab41d132e7237bb06535f2b4a999f7a231fbee37ec368f7567454f73f9/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:5ff289e4df686ed764b16df1e67d9f94da90422c2784baf0502bf67bd89e27ac", size = 585106, upload-time = "2025-10-22T08:35:13.636Z" }, + { url = "https://files.pythonhosted.org/packages/ef/12/3eead1dd55587c3072827717ec28fbf029a5c8bf7bdf877a8a0dd1292123/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3b8c3af089ee5452f29912ec9e41840a7db99f96e482a7d837b8c21a2cdfc8cf", size = 526581, upload-time = "2025-10-22T08:35:26.295Z" }, + { url = "https://files.pythonhosted.org/packages/47/62/5b6f069a373c2c16046094d5054b28932d932cf701675089caed3e7eb7f1/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e96d478a9acec92dc1c44e7b490b43e45cf182c327fde44f1e42ca377445aae2", size = 499068, upload-time = "2025-10-22T08:35:37.591Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c2/fe92dbbee923d0b42fb2c44a6c9876490ef71cd6eb74fb63c73358f9726d/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-win32.whl", hash = "sha256:5c2f0c442c3b4f5a351c9e780b5886259c093a711579ea6e59f3658838450bec", size = 176754, upload-time = "2025-10-22T08:35:57.424Z" }, + { url = "https://files.pythonhosted.org/packages/04/ab/c4a3541e681249deba417c7bbec819f4c44ab532bbc244f8e5cb6eea549d/reachy_mini_rust_kinematics-1.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:b3aef57e7ff74e5dac8db7e299f9c15c7a2e9934466ab2456d129bb8244edd08", size = 187313, upload-time = "2025-10-22T08:35:50.932Z" }, + { url = "https://files.pythonhosted.org/packages/2e/fd/c3801f0579da40147c7cadc1226bc3f5b7413cc590b13f53822674a910f7/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b9fe481d3ae29415e9be3358493bd6d26add4b494650384c650181595da10204", size = 303080, upload-time = "2025-10-22T08:34:54.167Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5f/1b28508a05fde9bf80277222991273721462afa84a7a0ede6227692b6a75/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58c87c6cb62a020f325caf8344f003ba4ebb783e20f417c6d89e3b63a72bc8a1", size = 278691, upload-time = "2025-10-22T08:34:44.295Z" }, + { url = "https://files.pythonhosted.org/packages/de/22/9b4c4b007085db8fb329656146742414e64051d9deb8e108020fbb3aafa8/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af2f330760b5519dcf556c728ddaa889fbc1b5ef6d76a4f3ef2eee1ddd032cb4", size = 312649, upload-time = "2025-10-22T08:34:02.52Z" }, + { url = "https://files.pythonhosted.org/packages/c1/e7/b50b441d287e72864e32b1049ab6d740158a8330deba5ec2cfa62d5125e0/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d8bffa448b0a75a570c5b8625344de3a755bca7f3a7450b045df153cef0cb402", size = 321102, upload-time = "2025-10-22T08:34:14.669Z" }, + { url = "https://files.pythonhosted.org/packages/3b/4b/cddf709a7012450d3255d7ab6ee6a1216e761664657ffe68806712d95c42/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27ae0811ccc4132f9b034771af061c513bcb0bd18a73dad1d16abc6bad366caa", size = 337443, upload-time = "2025-10-22T08:34:35.544Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6d/908fca70c2dee3e066831fcde011fb0d8c563418c75e052208bc538105cb/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5777d235930be71186adf948388580317943a022aa3761d6f78bcffe7dfc5ee4", size = 351864, upload-time = "2025-10-22T08:34:26.064Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e8/ddbfbc71cc2a7246de06cd4a0e934c9613a3a814406afbf8dfcd071813bf/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cbf226d07d34a6a395635b90ebb4d6e083136f07ca2e746d4431c44b00fd2d5", size = 493208, upload-time = "2025-10-22T08:35:01.445Z" }, + { url = "https://files.pythonhosted.org/packages/75/d1/51af83f5b70c2eaf5f871efdf62c7d88116af2d5309898b2de9925857556/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bab5d550e2225c9d4d6ee69b98fd13cf75b8b3df4ab9824d7759668e04a6e5bf", size = 585005, upload-time = "2025-10-22T08:35:14.756Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a8/cef7d415d864c8fa04362485ecb1648947a194b90426d147972ce59f4263/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7fc0243f9abc3d14aadaaa19b86d4930bf1e3bace0bfbbde73048ed80928b0f5", size = 526789, upload-time = "2025-10-22T08:35:27.367Z" }, + { url = "https://files.pythonhosted.org/packages/d2/4e/98e8e72f3cf0758eb4e6eb7320438dfb9e08d6ff593f6cc3661e726cf9a1/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a060b9022becd8decf9868063099fe68e598f7c07406d96795408ca862d208b3", size = 498731, upload-time = "2025-10-22T08:35:38.944Z" }, + { url = "https://files.pythonhosted.org/packages/26/fc/d9b66b439ea27c20d01e6cc841b34b3a8cc17fb0e79acaaa8ba4f5a4c587/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-win32.whl", hash = "sha256:ebf961d3ae3cd0798ed8d4e2bec8aec57f33fe2fb713852ad0ba2de4386c9c1a", size = 176607, upload-time = "2025-10-22T08:35:58.496Z" }, + { url = "https://files.pythonhosted.org/packages/9b/be/848776e83114ee92d9799860860be6dff036f22c9d01e85805c02a6d05fc/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:8afa30ed7da49544c8215033d2375c2f76f3311a6a1f380fe9acd2c076f9d45f", size = 187332, upload-time = "2025-10-22T08:35:51.994Z" }, + { url = "https://files.pythonhosted.org/packages/11/39/6c40cca1970ce47d9ae1661c87230cd37a6e2d782f34e0aec745f155d831/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:356134c5df18a01226432fbd1fb24649aced5a14da3c0406ebe2d1b3b8c002d2", size = 299587, upload-time = "2025-10-22T08:34:55.208Z" }, + { url = "https://files.pythonhosted.org/packages/5c/30/f9ba417bc1782d6a256ef9024eb0329c50cb7a3d12e83afd4b67047a01d6/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a232408fb7c58d6da73c40a40a120bae4f51bf9119de108530572723a00280d7", size = 276656, upload-time = "2025-10-22T08:34:46.904Z" }, + { url = "https://files.pythonhosted.org/packages/75/e7/e3bb2597d86f2037a1e4537f2352d7e92ff4699ee725b43a90400f15894e/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e7c3d2c73f89bf817d8c3abb8f0b23a6efdfce330a749c6e29e1e0cf6db9d7d", size = 312798, upload-time = "2025-10-22T08:34:04.219Z" }, + { url = "https://files.pythonhosted.org/packages/62/2f/64d2c4b434ef413c948935a0f57b4a502cc7effad68dd97263cdee22df64/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba0faba18be71b68026c70ccf4db6d9ea588774053d22487f228b490204a8a00", size = 321023, upload-time = "2025-10-22T08:34:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/c8/0e/f4cbddd5c0ed10cdba7f4baffc68f2e8102eb1d55b309690a52af3b067f8/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bed2ec420ea354ce62572afe8672ae8701a139781d9d8da97932597907019ee", size = 337756, upload-time = "2025-10-22T08:34:36.66Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d5/ac043e65949ba904b7ac901d74b8514ab47203de3af44e96c44dd2da7a94/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a79f6517728463294d5ca4945b18d843dd16cc410815ce039b35c1198bdc355d", size = 351251, upload-time = "2025-10-22T08:34:27.06Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ef/80bb31cee07d2336013808ce3b76dee29ae04274f053e1694e3a285da555/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5404cf14cc8894962dbbc82594af453588539b4b9458b8f95f43c29bc8bd2e34", size = 493292, upload-time = "2025-10-22T08:35:02.56Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e2/4f6c5a0d2a77111a9806243160b1aa3531ad3024a59f05c7f6157917bcc5/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:2e1f9d9ce4222d7ecda5cb77c96fed763de3ac94993e60c73adf9749d26e16df", size = 584893, upload-time = "2025-10-22T08:35:15.981Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/b0b57c9c46b77aa3c03f4071fca0c92809e23f9b22df5f85446ec5329fe2/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7c29c3d7b70d0576c740969cfa3e35ba98cc8e378c0867a79f53d5fee3568f77", size = 525948, upload-time = "2025-10-22T08:35:28.451Z" }, + { url = "https://files.pythonhosted.org/packages/06/12/f4d94e8c0b1b19b47072c2041f31fb83701cff1a199d0fcf012c0489f32f/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5b94ca8e94058efcd89553144b0a0b0f7c4abfe67a4cd60e2993cd0833c9e130", size = 499239, upload-time = "2025-10-22T08:35:40.026Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b6/907870cb3f588a6da58b64357c03241a28dac8a9ec9f42e91c291cb95c51/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-win32.whl", hash = "sha256:edcbcedaa4aa99684588bd897733a33ff8f8d9eed8ae39bd7d0fd691874f0457", size = 176379, upload-time = "2025-10-22T08:35:59.841Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c0/a5c1db0bf8dc55cf6b41a11463285ef440a2efa74d8b75be8443234c1acf/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:eb5d6d27ce08e8816496b6049979cf64ffbf3901dd5bb290efe439f5455526c2", size = 187469, upload-time = "2025-10-22T08:35:53.307Z" }, + { url = "https://files.pythonhosted.org/packages/13/5c/fffb02be21f666cf880042804c703de2410f32a44b0412d6df20bb156d15/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2aae2b9424a111935e26977fe2ab25c130c766e8049d72073e31a7ad78c84fb5", size = 299868, upload-time = "2025-10-22T08:34:56.48Z" }, + { url = "https://files.pythonhosted.org/packages/a3/33/b7e610c6325ed4fe439bd0be3e96850b5a5b6dc360116741bdf4c3a57ce9/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38ba383417c472ac67945a57c62ba621128b4486bd9d818512929454f47ce76d", size = 276655, upload-time = "2025-10-22T08:34:47.905Z" }, + { url = "https://files.pythonhosted.org/packages/93/bf/a1f579e4a6930b2155c99f80ac5b96d256c0047537c0802c34f0adfcde81/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3788d9c5b5315eff026486c3367e97ea23cd4ccd3eb6c7c1e37e0d00ec6b7128", size = 312962, upload-time = "2025-10-22T08:34:05.504Z" }, + { url = "https://files.pythonhosted.org/packages/89/cf/bf2a450adb2e6fbc5a9baa3ad9bece4d7272341723f4e76eff710463b484/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6983b555c1af6fd2c1ca8b32ae374c2b060239bb04b9b562806771ddafe81abf", size = 320871, upload-time = "2025-10-22T08:34:16.889Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ad/1eab50e3c56a65ac2f14a4890ae5370984586f52adf13cd8a7963ebf423c/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca28a8cda1ab4973259ed9aa06c7173ac5899492a3140075c58225a0ed96be52", size = 337653, upload-time = "2025-10-22T08:34:37.679Z" }, + { url = "https://files.pythonhosted.org/packages/a0/ce/8d3802dde54f9595daa9bd7b12a3de42ba4b4b48d92d8abe7a43919d74a8/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c8591616ef354d4f0724affef58eb14374f4a06b649b7947e94b97ec22d2fb9", size = 351553, upload-time = "2025-10-22T08:34:28.126Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/5e1de72d044440afb8cb7480af0c9ddcdcd9654b0ac62c11113fedc731d4/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45f4d9f159714e60eef22c9c00232beb34a8d27a89acce7d3ffcec2b86992b06", size = 493556, upload-time = "2025-10-22T08:35:03.963Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8b/1a33d934b9720586dc261349b500fb6a969ff1d3ba7c6f9bb7ba87d61d37/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:02a525696238dc85e9a1f3260d7d0db25074bb54f1cc2a0a4052849344026806", size = 585019, upload-time = "2025-10-22T08:35:17.344Z" }, + { url = "https://files.pythonhosted.org/packages/b9/5e/8cf4011456e3262f2a67b66ee77838cc56655cdcd7941efd44cb6ff8eb85/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:342b4a9adb9714f98d6569121c053800ae0a5b3904a9863ca65603bb3b9e7f0a", size = 526143, upload-time = "2025-10-22T08:35:29.636Z" }, + { url = "https://files.pythonhosted.org/packages/0f/3e/0d1168324c288693c07abd0050b83f682cf12a27c850e42d2601d3da84ef/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b596910a1ba0aaf79fc525ec5a8405dcd41c28946667faa549e789e5c1b93a5", size = 499284, upload-time = "2025-10-22T08:35:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/66/4e/0f69c0287a9289a0bc78d623cbf8cbd652e54ff6e854979b4985eb7fa75e/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-win32.whl", hash = "sha256:d5437b5d7f9093e879859d83da6888738f281fe728fad0a9f1678fe01035b4d3", size = 176631, upload-time = "2025-10-22T08:36:00.974Z" }, + { url = "https://files.pythonhosted.org/packages/94/00/eff3fa6480da3c2b486b8bcec55ea650b4955fb874664e9e7dce205a9885/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:c3c813012eacc7e779c81388f3dcb30811bee461672f9f9dc03835c73e3a5bc4", size = 187334, upload-time = "2025-10-22T08:35:54.464Z" }, + { url = "https://files.pythonhosted.org/packages/0a/e2/2c19fbf08a5e3836147ee345b9d75fbe1cd26df8d1f9e83b9cefa4bc80ae/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e1f563b31cbb0e0ee9f015801ef2eba31b9c37c306e3ca7737097a482355e0a", size = 312043, upload-time = "2025-10-22T08:34:06.505Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d4/873c4317a598e9709dd2aa68f0a072568b1f2db3616a2ffa76259618889e/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:874b986c44a94e1e1752f8f0b159342b0f60d4610e4df9c4bdf421e2749d949e", size = 320190, upload-time = "2025-10-22T08:34:17.889Z" }, + { url = "https://files.pythonhosted.org/packages/1f/11/64941229b39bfb1c39ea2ccb5fd02998915f87e40e277e4b0b744a2c3a2b/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f5060865aba96d3ffe1ac5cb93dc6439154a78ef8fdbb8a4313e4dc33064efb5", size = 492437, upload-time = "2025-10-22T08:35:05.014Z" }, + { url = "https://files.pythonhosted.org/packages/20/47/82704725e0d5cae887a4604e9bbf7688e6a676768ab47202b018ef9f7f32/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f7ddeef8610a936afbfd7dda1713be18d207032e18604e46963729996c3d1a41", size = 583980, upload-time = "2025-10-22T08:35:18.517Z" }, + { url = "https://files.pythonhosted.org/packages/97/6d/bfcdc6912531c62885450646f629aa581fb116ee5806dba00c01712b02f4/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2f498398c933e87a63a5747a2c813df09dcb68ded3ba79f86d092801ced36da8", size = 525181, upload-time = "2025-10-22T08:35:30.819Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6d/4f32bc65f83307a6eba5b62231e276bde8509d26dd8ba1a9997fb6c4b924/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6464868b209ec5cc0e50829b25bdad8cf765a48c943a5a7f504a3ec4ed7aedcb", size = 498743, upload-time = "2025-10-22T08:35:42.183Z" }, + { url = "https://files.pythonhosted.org/packages/85/26/2af509eb72c556a5f8628454122f61bcd55ae760ed74c2a1d8cfe21ebafe/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:419cba0b2ca01b52aba79004681201e1ad16d5a06a2ae9f4f74c45ea82e88f11", size = 276979, upload-time = "2025-10-22T08:34:49.023Z" }, + { url = "https://files.pythonhosted.org/packages/82/62/5fdf253c4293447fe2b95329891a46292fed02fd15f71a7eafbcca842194/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c654f6e06da8c6f8f5f2613c7a8d1841dca730ba2397125418f1b26bfeb46330", size = 337650, upload-time = "2025-10-22T08:34:38.745Z" }, + { url = "https://files.pythonhosted.org/packages/01/2e/eee9bed34de89569f52965fdbf6bd16c914c1b87f4f233e49ffa1f3f0590/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:58a36591b27a80c0836ab08ff21bf605413213f079baeef6fd1e3d6b47d8a341", size = 352082, upload-time = "2025-10-22T08:34:29.451Z" }, + { url = "https://files.pythonhosted.org/packages/06/b2/bf657750a75dfc8b5e12c1f4ca2e09ed4c4c7ea207295fc82a71e34dfad1/reachy_mini_rust_kinematics-1.0.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260bef2b277a63f5ded78b03cdcb98127862ae8eb6c4794ea25a71be5a03cd53", size = 313219, upload-time = "2025-10-22T08:34:10.265Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3d/df94e31f27e1f5e725ae188c6804e9064a78be6a3d052b3a2146857afd5a/reachy_mini_rust_kinematics-1.0.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2f73d69afbb6ddf4a0cf24e557a6340e71777a2b6de2ca4ac3243bd3f8abd5", size = 321182, upload-time = "2025-10-22T08:34:21.259Z" }, + { url = "https://files.pythonhosted.org/packages/19/94/35c9fc05d387026594f576b514d964af0a69e2b00712069215a9a735365b/reachy_mini_rust_kinematics-1.0.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:111de74d29630f1a2d8d0282328764bc490cb4aa63270b4f58467e9766225bde", size = 493659, upload-time = "2025-10-22T08:35:09.472Z" }, + { url = "https://files.pythonhosted.org/packages/e6/11/505834201862263b5d61beca2bbd43300f669a5960d482edf44ebb8cf835/reachy_mini_rust_kinematics-1.0.2-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:3126d71e7bdaa180eb62ef97cfd56cdf3b21c0f0693535ca44ff2ee12caea75b", size = 585112, upload-time = "2025-10-22T08:35:22.295Z" }, + { url = "https://files.pythonhosted.org/packages/c8/d9/eb0ec95412262132dd88494f85ec40b58f2ae6c83e4908585746edbad3c7/reachy_mini_rust_kinematics-1.0.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:89735b9ddb19eda38f4a2ebf1c7d7dbddbc9b39f55d407e87db5e151bbbca4b1", size = 526493, upload-time = "2025-10-22T08:35:34.19Z" }, + { url = "https://files.pythonhosted.org/packages/ac/0b/e403e4ce2d3ffe1d97efc54a5ddb024b1fff6c6f8607a1a306f83a615b47/reachy_mini_rust_kinematics-1.0.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:58e4edeec417a64c2508d25ce57a45932253d2339035bd66388a54beaaa91afb", size = 499556, upload-time = "2025-10-22T08:35:46.538Z" }, + { url = "https://files.pythonhosted.org/packages/bc/2d/c4492e19625f81348c812e5e17e97e777c521fe7200006bc41ebc904dd14/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305793e3097db1a93eabeeb5bcf7a581dedb859740d5f5164d7f2b695ce90953", size = 312932, upload-time = "2025-10-22T08:34:11.265Z" }, + { url = "https://files.pythonhosted.org/packages/9a/b2/d6cdc7960650c609b3e902734dcd10d6eb44373ba4f0aadaefde401244ba/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dda63846d7196737bad42d9de847b3c4702e68e40fc0a691fed50a87b9ef0898", size = 321183, upload-time = "2025-10-22T08:34:22.468Z" }, + { url = "https://files.pythonhosted.org/packages/51/74/d92143a61237d3f83ba9f6398f7d546cdefd8d43f820677bcf4d7ed3a265/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b307111f6ff46a1e8dc5b0d600c836ccf237106cf0bb9b87d85e079199fb733", size = 337577, upload-time = "2025-10-22T08:34:42.092Z" }, + { url = "https://files.pythonhosted.org/packages/05/e4/5ab1e64bd201e388f3fc0bb1ee89ef166479c8482d582ee58d603ba1b6ba/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64649a8ca74f3f528d57adf02f3b5ad6eaab4e5ab40bf837554ad878f0f4ea64", size = 351547, upload-time = "2025-10-22T08:34:33.109Z" }, + { url = "https://files.pythonhosted.org/packages/5f/19/f754c4cac653d3133145694abb6bb2d0da15b2459c1361b35528b3d16287/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6f0eda0e6cb8d86e80937a78b44e3db5e338039480fc077503aca3c23af008e6", size = 493554, upload-time = "2025-10-22T08:35:10.535Z" }, + { url = "https://files.pythonhosted.org/packages/af/81/14e1848dc1fb662a9dd8108bb3be4161a241055d38bac65eb9ee1fe5926c/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:12b9c538544352ee829338b3ae34623e3903294cd09ebb286f9467cad9882360", size = 585142, upload-time = "2025-10-22T08:35:23.413Z" }, + { url = "https://files.pythonhosted.org/packages/bb/47/a74608d37b58a162a3204ad4a1b7981ca79dc598b6c76533922cdc2bcb48/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:56eb81ad90e2b04506b4adf809b48a449fbd3972e2b32bd49038b745a6ff2d38", size = 526427, upload-time = "2025-10-22T08:35:35.379Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8e/c48f621c8d954849deb081a7a8840c57e38385dad999aaf5b82e10a09f84/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2af9062ffb5970b3318a85eaa7ce78042e7b023e7c096e34002da5aa083920dd", size = 499551, upload-time = "2025-10-22T08:35:47.616Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "rerun-sdk" +version = "0.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "numpy" }, + { name = "pillow" }, + { name = "pyarrow" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/ef/38ecd7fbb31b846d749299c2b848a30e85b7a6a7d496ea054373abfb3b08/rerun_sdk-0.27.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:e3e180a97085e7d7e1f1aee20c45f96173c87d723ce155573b96441733ef1560", size = 99965645, upload-time = "2025-11-14T14:49:18.53Z" }, + { url = "https://files.pythonhosted.org/packages/e7/67/ce06267c5fc5c7bb1cc027410a75cca0c5232afa1d4072ff2abe685cb923/rerun_sdk-0.27.2-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:224d168b9673bf9237057db6beb62a3a63223d702602c2e57283089ed77acf42", size = 107368188, upload-time = "2025-11-14T14:49:24.538Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6e/0be74188a53af91572b466e6f672dae476b9058ca71c7d053e753a665087/rerun_sdk-0.27.2-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5583f9d67b485e405939ddb1f9da38cc7202b326a15b1110d71dc7d2fdacc28b", size = 114630744, upload-time = "2025-11-14T14:49:30.28Z" }, + { url = "https://files.pythonhosted.org/packages/d4/8b/9fcb34b9d7bde9183372cc3dbaaca8d2ce49a43015e41dfe35bb62dfbef7/rerun_sdk-0.27.2-cp310-abi3-win_amd64.whl", hash = "sha256:d0437b73a807bb4643d3a7fee163e65e0df0459e6228eb2b087692610612ce99", size = 97879453, upload-time = "2025-11-14T14:49:35.062Z" }, +] + +[[package]] +name = "rhoban-cmeel-jsoncpp" +version = "1.9.4.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmeel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/0d/8686269eecbea32f314865075521b6305df709fe6bf0793397e31ef7506a/rhoban_cmeel_jsoncpp-1.9.4.9.tar.gz", hash = "sha256:953003fd1ce3b447170ef21747180f70a50ec2e0b81c6e193088adc9a90d37da", size = 220876, upload-time = "2025-06-24T18:54:10.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/8c/6006d71a441c2e51427ae2016ef8b227a78f9074717be46fbe2b196c805b/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0c032d05ce19aed18bf6b454daa510d4dcd89366745e7bfd062a6a16c3bfd51", size = 289726, upload-time = "2025-06-24T18:53:06.57Z" }, + { url = "https://files.pythonhosted.org/packages/38/fe/080a251ef48c99e1bd272fae8442a65864b7ddba94cd207774e6c84e659d/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7b606a2bed978408825be84a4731bed3a10b7f91e6dbeb5dca2b0955ed5453a3", size = 281613, upload-time = "2025-06-24T18:53:07.909Z" }, + { url = "https://files.pythonhosted.org/packages/91/18/f035f099a24bbe0b468387c5eede093ba4ac1636c5b5ef8bcf0c946fba80/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp310-cp310-manylinux_2_17_i686.whl", hash = "sha256:d29850410ee68a3201bc10ec0b0008afd9c7ce70888355fdac14a52efba48baa", size = 491818, upload-time = "2025-06-24T18:53:09.208Z" }, + { url = "https://files.pythonhosted.org/packages/2a/f0/513b12ba87a62272adff2298f22d78185faf54265afc298f1d8c337e7a5f/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:41cc0235e0e1132f3332bf0b8ca49b6e01693b04f56110633976dbd9dc33fa57", size = 330615, upload-time = "2025-06-24T18:53:10.758Z" }, + { url = "https://files.pythonhosted.org/packages/4e/a0/79a987ed722365b61051da30484cc7e8c8837b0e4693149b96c0173287ab/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e57547e0d34e18f989ee4966380deb48245d46dc0cc4da28ebaa7641e6615e2a", size = 362586, upload-time = "2025-06-24T18:53:11.854Z" }, + { url = "https://files.pythonhosted.org/packages/07/4b/035c9def4cca5e62b3053e8f728f500e0025e8e0a4c5c2fc70a9b5a065d0/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bf644a2e17f88f509c28e58c0d318a94c3fbae1c09eecf447b1be98f97a42f44", size = 338462, upload-time = "2025-06-24T18:53:13.343Z" }, + { url = "https://files.pythonhosted.org/packages/c8/d7/12e5dcc03c73d13ba546f522481d944f44829758eb6554b4751f49d45b0b/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ff4b6f7a26c89a2aed2242c6b834fc8abdfc099692b683e972f6fc4ed8ad83a", size = 397780, upload-time = "2025-06-24T18:53:14.836Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ae/cf627de3c52a80c65163fd3e214c3f0326d0411f67eb64db6629bc71717b/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bc0bb9ff7d0090cf722c72ef4088967336b6dd304fc34db6787345edc16f3be4", size = 363910, upload-time = "2025-06-24T18:53:16.033Z" }, + { url = "https://files.pythonhosted.org/packages/87/63/51136e4fdcaedcbf326fc242753e2291a5e3aeabdc0c0d5a5bab0edc5378/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1b3a0fd46c2e2e6fc6912dcae7cb987cd0a61d9caee4f3ca1cb62544eb8aa11a", size = 289728, upload-time = "2025-06-24T18:53:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/77/ee/bc97fd2474f0f28449149211776ac63b9d76a82f7468277e09611e9253cf/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffd64a71c7e74312180c4ff20c55f0ebc235c3d634dba18618063c60175cd06c", size = 281614, upload-time = "2025-06-24T18:53:19.575Z" }, + { url = "https://files.pythonhosted.org/packages/82/a6/5cb9320ffce6ee8f5a62f942aabb7253d03ed38f611d891114a5c1304b7a/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp311-cp311-manylinux_2_17_i686.whl", hash = "sha256:6f4c09ca5ba465769e972f94bd8113927aed0a30932caefc7799dd6b6a5d83fb", size = 491819, upload-time = "2025-06-24T18:53:20.751Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ef/df1cba0fdbe278b45e2eaf617b4aedb29b7670e04795b1dafa5339ad67e9/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:cfa5a8f18c3fe4a973ff1e49fe5f1048a81b2f2cc1d22df0770f3d23a91d455c", size = 330615, upload-time = "2025-06-24T18:53:22.243Z" }, + { url = "https://files.pythonhosted.org/packages/54/ca/fca12118933539461dc66cd70fd2dfc38f0dff99075e544ff9afb3924479/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:db51d1b31d0d0fe04e5d7fc123a849154689cadc5e43a289c20c8ecf243c5fa5", size = 362584, upload-time = "2025-06-24T18:53:23.831Z" }, + { url = "https://files.pythonhosted.org/packages/24/2f/9829e23758b6df6ade5da3f7a2348adce273c271b386573e15cce201ba88/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b885cc44fd59e2070b77f5463324683b3d99035307dc0c9635cdbe4fc1759741", size = 338463, upload-time = "2025-06-24T18:53:24.986Z" }, + { url = "https://files.pythonhosted.org/packages/e7/dd/a5adb0bea0bc8ca19b3631e2d4a66e8b2a66b4497aa24f176e8549b3c4c2/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:23d94e38b1266ad987ed42369841839d7299b6e5745890f39882236485b66e08", size = 397781, upload-time = "2025-06-24T18:53:26.633Z" }, + { url = "https://files.pythonhosted.org/packages/37/7f/8f9d90373411e297db923bf5c42c596fc4bc6f4955561aec508fa375b299/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b67cd1ff1d3801154e0ca6518f77dae6d75297f83de8246abb20cd8f0813d6bd", size = 363909, upload-time = "2025-06-24T18:53:27.796Z" }, + { url = "https://files.pythonhosted.org/packages/34/c7/70335d8227dbfe222a2362eece6a37ed6526438636d445fa53cee897625b/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f0f62d47631ed02be9a83669b24ed2fb870c27e39311b5ff4842473aa61e3ca8", size = 290015, upload-time = "2025-06-24T18:53:28.982Z" }, + { url = "https://files.pythonhosted.org/packages/55/8f/c07df2a93cb2184f2b3cd4edf7ca9c4467d17466cae5dc84166de5365963/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78d34f04880cc0ff799832c3f1e2c34f7179c54ac7c428339f35c87e3bb5739b", size = 281613, upload-time = "2025-06-24T18:53:30.392Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/a7b6df62549654b940dd4737384d2bd15afc570595a1a98fbdcf8aa5fcbf/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp312-cp312-manylinux_2_17_i686.whl", hash = "sha256:3841bb7fed9ca370631bafc44c493b1b4044048e857e1265b24ded9cd6bef385", size = 491819, upload-time = "2025-06-24T18:53:31.59Z" }, + { url = "https://files.pythonhosted.org/packages/e6/7a/ec81041d3bcd1c99ae4ef14505d81cbe8a424d1bcee752bd1f32b6391d24/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a68789f5226bb8df92383140f3f45b94afe07b115fcc3b34a0e1da806d7d1f66", size = 330613, upload-time = "2025-06-24T18:53:32.985Z" }, + { url = "https://files.pythonhosted.org/packages/09/5a/96550200a9aefea3e14f1eaea0d62a649968883bb1c927509666d2ad680c/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a3aa7cc485acf11e4876f0ac20ee5ffcc0c89c9dd7b8eee4d5e078392421e2fa", size = 362585, upload-time = "2025-06-24T18:53:34.14Z" }, + { url = "https://files.pythonhosted.org/packages/bd/e9/1c32193f9a2e0b397417b20877f0c3fd2b3b88a20b85b4f8925ef5e50dfe/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fbcda72ec3aa1935b355df5dbde55f885b3a7aadc7d9b8d1ff1cd274247c9a15", size = 338462, upload-time = "2025-06-24T18:53:35.297Z" }, + { url = "https://files.pythonhosted.org/packages/72/6b/bb9e6e6dee18a32f47213c42f03291901d6214d3a352c7104304e06d684e/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2472911f555b8f39caaddf23601a08befdf218e08c521049b0cbd705c1693772", size = 397779, upload-time = "2025-06-24T18:53:36.413Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ca/5aa50bd53bad9c079e2ceabe17231803c420fcc549894e77c7266f1b3853/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cb67950a3d3b4a6ec23fcce2e7f844c2ddd1c626ff9f4c7991c699d66213be5", size = 363910, upload-time = "2025-06-24T18:53:37.595Z" }, + { url = "https://files.pythonhosted.org/packages/8a/17/43932dd90f1febb6cbc6c8d17df5b0b9f0bd3b21660c4fb3d846770964ee/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:096d147389647ee103066e91b799ec230842ebd2916e0a59069bf598f06020a5", size = 290015, upload-time = "2025-06-24T18:53:39.01Z" }, + { url = "https://files.pythonhosted.org/packages/78/a1/3bb178bdb062bab896aaa5bae91e43a83cf986a155dee1479a27a289fad3/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a3f54fe0ea0aaa91c46dba6939a822f08f8f5a2611e17074e9b4cf0273f8ca03", size = 281613, upload-time = "2025-06-24T18:53:40.14Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3e/f8cc82bf48d1c638be0c17a70c6b8a2d84f55e6c84adae88074d30e2d3a8/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp313-cp313-manylinux_2_17_i686.whl", hash = "sha256:f491c23be755f33d04fcd120b2555084bb2b5f8ce6610853f55d0b7ef73d9454", size = 491818, upload-time = "2025-06-24T18:53:41.584Z" }, + { url = "https://files.pythonhosted.org/packages/71/7d/b28c58560b757a1d2e821ddfab9a737f760573dc331d604d2f1a50ad0c59/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:5cfa7582e21289214dc6e0eb17e821a463429f4eb9bbe0b1d73c8b6b5070e822", size = 330615, upload-time = "2025-06-24T18:53:42.797Z" }, + { url = "https://files.pythonhosted.org/packages/dc/45/c0a97f844b416ac4bb0701cb5bedcdd714236c60a968f1a17a929acf2030/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0e736f7c65279767558477c73b7ee07d7900878b6489362af90b75bf58ef98e5", size = 362585, upload-time = "2025-06-24T18:53:43.976Z" }, + { url = "https://files.pythonhosted.org/packages/82/d1/e68942c2136ba7f16150d7174376df83f7b5034391605839a280c94b6b93/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d2d289decd44461a22561353d26a4ebd94a35d7967de43a094cdf1d68afd47ce", size = 338462, upload-time = "2025-06-24T18:53:45.242Z" }, + { url = "https://files.pythonhosted.org/packages/ba/5b/97acff8d776ef2fca5d4e21893624dbb424095f1a4b66c3c0d1375854341/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fe1165ea4390a4cfce698f1018b3305e27abf4f9db7f464116f7252ae27d16ae", size = 397779, upload-time = "2025-06-24T18:53:46.76Z" }, + { url = "https://files.pythonhosted.org/packages/11/7c/4f2cd6df47c6b83652e8f9ffafb25f056a1b01fa0050df4b4abf5f41dc12/rhoban_cmeel_jsoncpp-1.9.4.9-0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f49041be98e0104856f8a0874936f50be435c514a8cd20ed5291b82d81912099", size = 363908, upload-time = "2025-06-24T18:53:48.05Z" }, +] + +[[package]] +name = "ruff" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/90/5255432602c0b196a0da6720f6f76b93eb50baef46d3c9b0025e2f9acbf3/ruff-0.12.0.tar.gz", hash = "sha256:4d047db3662418d4a848a3fdbfaf17488b34b62f527ed6f10cb8afd78135bc5c", size = 4376101, upload-time = "2025-06-17T15:19:26.217Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/fd/b46bb20e14b11ff49dbc74c61de352e0dc07fb650189513631f6fb5fc69f/ruff-0.12.0-py3-none-linux_armv6l.whl", hash = "sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848", size = 10311554, upload-time = "2025-06-17T15:18:45.792Z" }, + { url = "https://files.pythonhosted.org/packages/e7/d3/021dde5a988fa3e25d2468d1dadeea0ae89dc4bc67d0140c6e68818a12a1/ruff-0.12.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6", size = 11118435, upload-time = "2025-06-17T15:18:49.064Z" }, + { url = "https://files.pythonhosted.org/packages/07/a2/01a5acf495265c667686ec418f19fd5c32bcc326d4c79ac28824aecd6a32/ruff-0.12.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:07a7aa9b69ac3fcfda3c507916d5d1bca10821fe3797d46bad10f2c6de1edda0", size = 10466010, upload-time = "2025-06-17T15:18:51.341Z" }, + { url = "https://files.pythonhosted.org/packages/4c/57/7caf31dd947d72e7aa06c60ecb19c135cad871a0a8a251723088132ce801/ruff-0.12.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7731c3eec50af71597243bace7ec6104616ca56dda2b99c89935fe926bdcd48", size = 10661366, upload-time = "2025-06-17T15:18:53.29Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ba/aa393b972a782b4bc9ea121e0e358a18981980856190d7d2b6187f63e03a/ruff-0.12.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:952d0630eae628250ab1c70a7fffb641b03e6b4a2d3f3ec6c1d19b4ab6c6c807", size = 10173492, upload-time = "2025-06-17T15:18:55.262Z" }, + { url = "https://files.pythonhosted.org/packages/d7/50/9349ee777614bc3062fc6b038503a59b2034d09dd259daf8192f56c06720/ruff-0.12.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c021f04ea06966b02614d442e94071781c424ab8e02ec7af2f037b4c1e01cc82", size = 11761739, upload-time = "2025-06-17T15:18:58.906Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/ad459de67c70ec112e2ba7206841c8f4eb340a03ee6a5cabc159fe558b8e/ruff-0.12.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d235618283718ee2fe14db07f954f9b2423700919dc688eacf3f8797a11315c", size = 12537098, upload-time = "2025-06-17T15:19:01.316Z" }, + { url = "https://files.pythonhosted.org/packages/ed/50/15ad9c80ebd3c4819f5bd8883e57329f538704ed57bac680d95cb6627527/ruff-0.12.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0758038f81beec8cc52ca22de9685b8ae7f7cc18c013ec2050012862cc9165", size = 12154122, upload-time = "2025-06-17T15:19:03.727Z" }, + { url = "https://files.pythonhosted.org/packages/76/e6/79b91e41bc8cc3e78ee95c87093c6cacfa275c786e53c9b11b9358026b3d/ruff-0.12.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139b3d28027987b78fc8d6cfb61165447bdf3740e650b7c480744873688808c2", size = 11363374, upload-time = "2025-06-17T15:19:05.875Z" }, + { url = "https://files.pythonhosted.org/packages/db/c3/82b292ff8a561850934549aa9dc39e2c4e783ab3c21debe55a495ddf7827/ruff-0.12.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68853e8517b17bba004152aebd9dd77d5213e503a5f2789395b25f26acac0da4", size = 11587647, upload-time = "2025-06-17T15:19:08.246Z" }, + { url = "https://files.pythonhosted.org/packages/2b/42/d5760d742669f285909de1bbf50289baccb647b53e99b8a3b4f7ce1b2001/ruff-0.12.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3a9512af224b9ac4757f7010843771da6b2b0935a9e5e76bb407caa901a1a514", size = 10527284, upload-time = "2025-06-17T15:19:10.37Z" }, + { url = "https://files.pythonhosted.org/packages/19/f6/fcee9935f25a8a8bba4adbae62495c39ef281256693962c2159e8b284c5f/ruff-0.12.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b08df3d96db798e5beb488d4df03011874aff919a97dcc2dd8539bb2be5d6a88", size = 10158609, upload-time = "2025-06-17T15:19:12.286Z" }, + { url = "https://files.pythonhosted.org/packages/37/fb/057febf0eea07b9384787bfe197e8b3384aa05faa0d6bd844b94ceb29945/ruff-0.12.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a315992297a7435a66259073681bb0d8647a826b7a6de45c6934b2ca3a9ed51", size = 11141462, upload-time = "2025-06-17T15:19:15.195Z" }, + { url = "https://files.pythonhosted.org/packages/10/7c/1be8571011585914b9d23c95b15d07eec2d2303e94a03df58294bc9274d4/ruff-0.12.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e55e44e770e061f55a7dbc6e9aed47feea07731d809a3710feda2262d2d4d8a", size = 11641616, upload-time = "2025-06-17T15:19:17.6Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ef/b960ab4818f90ff59e571d03c3f992828d4683561095e80f9ef31f3d58b7/ruff-0.12.0-py3-none-win32.whl", hash = "sha256:7162a4c816f8d1555eb195c46ae0bd819834d2a3f18f98cc63819a7b46f474fb", size = 10525289, upload-time = "2025-06-17T15:19:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/34/93/8b16034d493ef958a500f17cda3496c63a537ce9d5a6479feec9558f1695/ruff-0.12.0-py3-none-win_amd64.whl", hash = "sha256:d00b7a157b8fb6d3827b49d3324da34a1e3f93492c1f97b08e222ad7e9b291e0", size = 11598311, upload-time = "2025-06-17T15:19:21.785Z" }, + { url = "https://files.pythonhosted.org/packages/d0/33/4d3e79e4a84533d6cd526bfb42c020a23256ae5e4265d858bd1287831f7d/ruff-0.12.0-py3-none-win_arm64.whl", hash = "sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b", size = 10724946, upload-time = "2025-06-17T15:19:23.952Z" }, +] + +[[package]] +name = "rustypot" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/ad/22e84d4b3099e3fc109fd65e3af9629987974a227fa566d229c32a0bf654/rustypot-1.4.0.tar.gz", hash = "sha256:5e8607f0cff9f2953f59c567e34cc089f4fd9ff88ebbb41d4b329dd9dffcf0f8", size = 60097, upload-time = "2025-11-19T11:53:43.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/ab/5e24e49b1472a7ff97a16a3a7606ea29f2feeef018fc404715e510156e2e/rustypot-1.4.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6b99e6e89028116e9923375c2aaab1b8da8cd5c1dc2dcc682a893765517c7f0d", size = 1657408, upload-time = "2025-11-19T11:53:17.917Z" }, + { url = "https://files.pythonhosted.org/packages/15/af/9208b1c1e350b1ecd986e6782d64b9f8f770e3da65f3707952501db3b56a/rustypot-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91dbf14f0f0e31969df43185bd18cfd6bc7341e6fad815d000175fd5cb1bd7ad", size = 1530195, upload-time = "2025-11-19T11:53:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/02/db/c511c59b0c2428eaa59f2cf3640c677dad83eee5e8f4caf876ebdeb3db09/rustypot-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfb9bfce1adea617eb948d5cf410703070ab7aac3b454014e172acbd4c4c1b81", size = 1673673, upload-time = "2025-11-19T11:52:49.553Z" }, + { url = "https://files.pythonhosted.org/packages/82/ac/a7188231bd853be75388eba1f2b6a24922942c9f7a0de0a962e752faa8ca/rustypot-1.4.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd9896ce88eebbed3f9cd8d98774505cafd23b399256a3aeb3844b2ef1ced49f", size = 1726837, upload-time = "2025-11-19T11:52:54.942Z" }, + { url = "https://files.pythonhosted.org/packages/e6/de/97f330269bcaaccd81b1e1eef2c9410d9e13c16de97450c6b1632400b474/rustypot-1.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8c7f4709fc8f9338199ce0560de230a644f5e7c161f8ac3c1c24530d5abbcc8", size = 1752455, upload-time = "2025-11-19T11:53:06.014Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/480833485a2d960cf998fda6567b919258e08346309c1afca44d407cad97/rustypot-1.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ecaaf5b555b11db3132c803b79e93ea7db9caa5d08dc6bd67c654f29eb5bb46", size = 1737355, upload-time = "2025-11-19T11:53:00.727Z" }, + { url = "https://files.pythonhosted.org/packages/bf/50/e428c68fedf5c5ac78aebe321ed8ec84e247ae044b3306b36f8c6a74ff8f/rustypot-1.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8f04aaa90dfc2b6c535e8b0897b844200dfc8d267034006a5d0f8bfc8329bb67", size = 1858991, upload-time = "2025-11-19T11:53:23.014Z" }, + { url = "https://files.pythonhosted.org/packages/f4/06/1fd6106dfb9eb1f8d0bdf5ef1ccb4d7e38db8d41fe0984201d67dde7e018/rustypot-1.4.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f2800cd8b732ae43eb8936d3462c489c2efff43ded92da3612828debbcbd5515", size = 1996042, upload-time = "2025-11-19T11:53:28.339Z" }, + { url = "https://files.pythonhosted.org/packages/43/f3/d40eb22fbab02986bd5d8a6f2c86bae20425577fdb19b3ebbc0cdea62ae4/rustypot-1.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:80626bbeaf05ea3edd112dad541eda2f1771a252c455d381956fa77c95c1e6c0", size = 1823848, upload-time = "2025-11-19T11:53:33.327Z" }, + { url = "https://files.pythonhosted.org/packages/98/7e/620c6b4ef86a83fe42d3bc3d18265ca6c53a3f644e155653ad18df93e215/rustypot-1.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8766222a6ac4df8f8afedcc6c2cf493cc71bf245e4b593e24fad0a61cf83e3dc", size = 1944672, upload-time = "2025-11-19T11:53:38.067Z" }, + { url = "https://files.pythonhosted.org/packages/89/91/2c399e66eb3507a9b1ad8ec2be9695bfda7fb9a7305f787113cf95166770/rustypot-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:a162451a69766702a5a36c8055a822d5b7af99420ee131162d93c5926e78d7e7", size = 1671429, upload-time = "2025-11-19T11:53:43.789Z" }, + { url = "https://files.pythonhosted.org/packages/c6/4d/28a3f898567587b1ae6c40d26ec6e9d52d823ad09a3a1dceea71cc2840d2/rustypot-1.4.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5eb56ef3f4c93c0564d4387e51dabf024c392597bfc101b7d9bfbfa282b936a3", size = 1657433, upload-time = "2025-11-19T11:53:19.191Z" }, + { url = "https://files.pythonhosted.org/packages/15/b8/c27afb0203b0d24930dcb673aacbf1db187d3d5d961401bf5596d95164dd/rustypot-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e84c3c06bc25511fec1c475985a6038ad5e1c77574ced3cdcd3b18bec59f3f0c", size = 1530013, upload-time = "2025-11-19T11:53:13.252Z" }, + { url = "https://files.pythonhosted.org/packages/7b/eb/60e6a2b63076a86f1c5fe09edc996439dedf4027bd900290019ec506a61b/rustypot-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:852309d8c8af86eafc1c4afd065c219f0ff0f0db19d486a7cb30cdae3bcc1e9d", size = 1673985, upload-time = "2025-11-19T11:52:50.843Z" }, + { url = "https://files.pythonhosted.org/packages/01/0f/61d7f782b9473864eaf46d608f06e3425acbb72d31252a281baec34349a3/rustypot-1.4.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed87d23cb5b0bdb3f12539de9e71f7ba55d6ffb42a69d99082348d357381dc66", size = 1727323, upload-time = "2025-11-19T11:52:56.581Z" }, + { url = "https://files.pythonhosted.org/packages/11/f3/042cb6871a464c251e403f85e31af5a387b68f290c6f7686891af955aaec/rustypot-1.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:042ad6d0e72db7036fc472c0de9be9ee6b035cee234ebcf9b10d75a30618c1c9", size = 1752098, upload-time = "2025-11-19T11:53:07.118Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d9/47c8f992e0a1d7d30de17459724a4c736751b9c53c69b8c04e2942cd7081/rustypot-1.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:26e243a81cedbbe51abf461ca5ec2b9641730340b03ad52f7fd638d922ea300d", size = 1737415, upload-time = "2025-11-19T11:53:01.906Z" }, + { url = "https://files.pythonhosted.org/packages/2a/67/a1745fee19e4e025d51b5ee0eac13a20bf9984792e8dcdc0173bd3a99348/rustypot-1.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76e9fd0376815c227c915372e34a61366365faf3472f849e3d31de690eef9532", size = 1859533, upload-time = "2025-11-19T11:53:24.437Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8f/2e5db416b6b9428d99888baa2f045faf3fa0662e6d1ea10c7b3b3871f199/rustypot-1.4.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ecabfa2b34e9821ded4a686df16092530b233ddf560e5920ca11e4ffb3a9c59a", size = 1997475, upload-time = "2025-11-19T11:53:29.845Z" }, + { url = "https://files.pythonhosted.org/packages/e4/69/50de9222c02377ad7e2b0353034dfb04efa644bd220b402a6ea72da78a2c/rustypot-1.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6259a0e202f9d543d329fad83c3f2d9439061f17c9d7f08a5b02cc6123b807a9", size = 1822346, upload-time = "2025-11-19T11:53:34.654Z" }, + { url = "https://files.pythonhosted.org/packages/11/df/da8a96db6d02a35c94c159eb2ff3389d9de5e2ee2beda04df4dce384a2ed/rustypot-1.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:883a95f573ad23a630591428cd8b4228c5bd62884323a079bf6517c588812f90", size = 1943995, upload-time = "2025-11-19T11:53:39.288Z" }, + { url = "https://files.pythonhosted.org/packages/c1/61/c108d25e61cdcb2f6aea984cbbf359952d935ae99115c7746e8dc86371f2/rustypot-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:09858b97b004337b8370c0a41b7e08a74c92e1d7530c9bd9106cf9037c090d69", size = 1671721, upload-time = "2025-11-19T11:53:44.918Z" }, + { url = "https://files.pythonhosted.org/packages/47/db/0a1ed93069a7ab86d28fc4c47cb9e7a995211ac5d5d77ec1b5d68ae0e64c/rustypot-1.4.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c3c133ca8d9a7f0453532bec8d0f9c6f20e64f71d1141a25d9bc31e62b7251b6", size = 1651633, upload-time = "2025-11-19T11:53:20.422Z" }, + { url = "https://files.pythonhosted.org/packages/b9/6e/32fd0e56dbf6dcb29a2d2da8b4692a15beb63557a655e3e22f367cf19db6/rustypot-1.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12942dc5694d2511e12e5d59ea50a41da0bfab29d4cdd6f4718b05874d132145", size = 1517305, upload-time = "2025-11-19T11:53:14.311Z" }, + { url = "https://files.pythonhosted.org/packages/aa/67/4616ac267267ed9b2bbd82bfdce9e7edadeef5d09f7c63df737b870479d5/rustypot-1.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c9962e22adabe744e54b3699cd64099320a74b7ca7b1ed0be425b3b379636e3", size = 1643720, upload-time = "2025-11-19T11:52:52.202Z" }, + { url = "https://files.pythonhosted.org/packages/17/95/9d77beeaf20c2bd13107d84249be010f951e5041e8045fbdac4f80e3d80b/rustypot-1.4.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:67a5d8c04e19022dbfbf6b38a886420b1928d7024d97767bfe5574b7f1d13e74", size = 1694743, upload-time = "2025-11-19T11:52:57.873Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0d/2ce9f220ec672a847fd76e08831d9d17c57a59ba5aa1940951d96dfd61d8/rustypot-1.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c4cbbc072df203697ac5f2346be94a149a792e0ca052b6392504b27cfe2d447", size = 1745176, upload-time = "2025-11-19T11:53:08.476Z" }, + { url = "https://files.pythonhosted.org/packages/3a/33/3fe3be1f95998113926aa38532adeb9964a02511a0071d1680850cfaf74b/rustypot-1.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d73802eec8dc8d47555f05fa7165b87c33e9d3997c841213759cbe72bffa145e", size = 1699759, upload-time = "2025-11-19T11:53:03.064Z" }, + { url = "https://files.pythonhosted.org/packages/22/ba/ef2428a865b5350c649c67573519e7052756286913cd7d5b28a762e063e0/rustypot-1.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8bf4d6b87add0b275e993748c825751c0d7fcd77b8081e2ff344037bd13f521", size = 1829416, upload-time = "2025-11-19T11:53:25.8Z" }, + { url = "https://files.pythonhosted.org/packages/71/67/b6dae95ec2d169bb8afa489418fe64623fe35b48f57fba6ba7649bdfaaa1/rustypot-1.4.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4b068f9229a329dbe327feb982f683209900739e2811d60e41a6999eb46fa627", size = 1963364, upload-time = "2025-11-19T11:53:30.972Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a2/946cde0c5d31f7ce7b7c79f79a1785f194b2922d2b4a67c53e6e1b8099e9/rustypot-1.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:519a3ba8bd2d9291436ef2259869ef2c918a9410ac063e33e76178d52e0230e3", size = 1815541, upload-time = "2025-11-19T11:53:35.773Z" }, + { url = "https://files.pythonhosted.org/packages/13/7f/acebd54c52c7ecd0f4d2caaee0b4ea57047443d16cb64c2d9e9e0b359832/rustypot-1.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ba4d42d5dc32e00dbae1eb592eb0a94d8cc8551c1b2285be774e4d9cdfb064d9", size = 1936044, upload-time = "2025-11-19T11:53:40.782Z" }, + { url = "https://files.pythonhosted.org/packages/b8/3e/877cb56347550409a9f33e92e224b7527684d89b4159a96d1e9f3065fe28/rustypot-1.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:acdc44bf55ece4d7205c5f8d68faaea1c7e16f66631d4533929e7c027c7d9583", size = 1671794, upload-time = "2025-11-19T11:53:46.089Z" }, + { url = "https://files.pythonhosted.org/packages/c9/cc/5592dcc870a6ac0c8ff3173c84985da9ebfe039a6c704387cf84247e3c6e/rustypot-1.4.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6a34cee68caac4dda00ad23dba2fb923dfe47ad8b82816bcd68fd742508dc772", size = 1650940, upload-time = "2025-11-19T11:53:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/96/8f/25b99ff877c82679c9bb6d54c2dd74d72ccf731565022f67ecb6a8fc6e93/rustypot-1.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c05c4500037d6c981324cfb560f3f0b2f9066ac725912de7dbbc22652a8b1a89", size = 1516899, upload-time = "2025-11-19T11:53:15.493Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/4cc071a6b81c0b7470234fd31dae86aa3a98326ade39ff8e1200a563d72e/rustypot-1.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efe08c3535ef28a65c1fd3fa2f4074dd568b080b468d84c7cfdd6ac47bf3568a", size = 1644159, upload-time = "2025-11-19T11:52:53.521Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6d/ea3778c7673559316361d1c021f6e774e3df449e928416bbe434721cdfa9/rustypot-1.4.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e222c615a4e859363a9d75f25e9394fe8e3d9634465e7244861cf9dd9568c06", size = 1694143, upload-time = "2025-11-19T11:52:59.329Z" }, + { url = "https://files.pythonhosted.org/packages/e6/f1/cc231247f54d38f8ee0c3c41f768fc2fa1a9c6a782f4c3928ea775af759c/rustypot-1.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:377017dc152f75cf9a73ae6cbe4dae501051bcd2269d345b3f52d526af3388e3", size = 1744386, upload-time = "2025-11-19T11:53:09.629Z" }, + { url = "https://files.pythonhosted.org/packages/ea/c8/c137ba5b77413165d5a0e27b1937b10971e200984c0604b9ce751911f14e/rustypot-1.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c4a89781b13805d09f03a51665bb41fe6d41a3da466bc71fce7688f5865c7ce", size = 1701060, upload-time = "2025-11-19T11:53:04.548Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e5/a09da32532b5b2416e5faf1708d4a09f25682b984826f8e6b09310ed6d56/rustypot-1.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:624e909936934412ac068601a251e44749ab2acc02fac09eefa75d8b9d88cfb3", size = 1829242, upload-time = "2025-11-19T11:53:27.156Z" }, + { url = "https://files.pythonhosted.org/packages/fe/f9/69214ea8d15755c2a1a7a2a5575b7f675944b09a03abb04e5a063023b7a0/rustypot-1.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3a4fbc587099a96806f30cd15cc3ad20fdfca698083253f29724a516b068fd65", size = 1963269, upload-time = "2025-11-19T11:53:32.193Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c8/da7ba34a1ff0c7b7a98dd281f2900f7c1a9d6e8ffc2935b10d7e74d7cf0d/rustypot-1.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bfc0c8026fa00d00307cbad2e106ba36abb6022884365db0400147786b0c9f07", size = 1816497, upload-time = "2025-11-19T11:53:36.956Z" }, + { url = "https://files.pythonhosted.org/packages/7d/8f/07d9e529cdb9f8c7734f76af1f17f907da770025c7b2b904286cde6089ee/rustypot-1.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c453fb38f4435918c762513a91d89a586a415f6e420f79ab45016b643f5b4db4", size = 1935302, upload-time = "2025-11-19T11:53:41.917Z" }, + { url = "https://files.pythonhosted.org/packages/35/8b/e7c248f46bcd3d9f5d974253b9c1e967ae010897da5af72a831535ae41b5/rustypot-1.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:52a5a208030f956fa079ad4405d24c2215ed6afd1a8bcc6e2a1ee95fafee67b7", size = 1671632, upload-time = "2025-11-19T11:53:47.224Z" }, + { url = "https://files.pythonhosted.org/packages/8d/45/36a3ccfa501d568afe4ef9abe5af728522edc352dc088a4351df1b85cfba/rustypot-1.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:936760476f2576968fa0f2411aee16963306e9a284cec98c24138b760ef0110f", size = 1524411, upload-time = "2025-11-19T11:53:16.836Z" }, + { url = "https://files.pythonhosted.org/packages/bf/c8/fe09616e5632afc1ea261c6ec53ed6e30b1e478112c8891274c3349f523d/rustypot-1.4.0-cp314-cp314-win32.whl", hash = "sha256:36088211b186d438a40ad3013cac3f196e24ec4291904675f4f119738ee0850b", size = 1243384, upload-time = "2025-11-19T11:53:50.65Z" }, + { url = "https://files.pythonhosted.org/packages/6a/3e/3ef1357731787c2eeb1e9c82f2d87e51daa055e24cedf55079c8c1188932/rustypot-1.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:e0befc88f34336d010bbf2ef75d0245a3537d007dfb2f492f6922dc972246681", size = 1680240, upload-time = "2025-11-19T11:53:49.137Z" }, +] + +[[package]] +name = "scipy" +version = "1.15.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, + { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, + { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, + { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, + { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, + { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255, upload-time = "2025-05-08T16:05:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035, upload-time = "2025-05-08T16:05:20.152Z" }, + { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499, upload-time = "2025-05-08T16:05:24.494Z" }, + { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602, upload-time = "2025-05-08T16:05:29.313Z" }, + { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415, upload-time = "2025-05-08T16:05:34.699Z" }, + { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622, upload-time = "2025-05-08T16:05:40.762Z" }, + { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796, upload-time = "2025-05-08T16:05:48.119Z" }, + { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684, upload-time = "2025-05-08T16:05:54.22Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504, upload-time = "2025-05-08T16:06:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, + { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, + { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, + { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, + { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, + { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, + { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, + { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, + { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, + { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, + { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, + { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, + { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, + { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, + { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, + { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, + { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, + { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, + { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, + { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, +] + +[[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 = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + +[[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 = "smbus3" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/39/4b7fe2b7cfb42a39e5bb4ef2970a3befc0febbf2b5b8ef85fac04ca6dcb3/smbus3-0.5.5.tar.gz", hash = "sha256:91eed38fb6b7d2f893fbfc3f37006aa41e6913fdda5b3a9a79238b353760f92e", size = 22100, upload-time = "2024-06-29T01:55:18.214Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/cf/a0cfae35dac3e3d0b1b4242c8ba184616a47550f8c727b0df654d4338e2d/smbus3-0.5.5-py3-none-any.whl", hash = "sha256:7f4cc169975543e67e4b7404168ce918e656f6f8daca5de2bd30527298058083", size = 13616, upload-time = "2024-06-29T01:55:16.434Z" }, +] + +[[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 = "sounddevice" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/2d/b04ae180312b81dbb694504bee170eada5372242e186f6298139fd3a0513/sounddevice-0.5.1.tar.gz", hash = "sha256:09ca991daeda8ce4be9ac91e15a9a81c8f81efa6b695a348c9171ea0c16cb041", size = 52896, upload-time = "2024-10-12T09:40:12.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/d1/464b5fca3decdd0cfec8c47f7b4161a0b12972453201c1bf03811f367c5e/sounddevice-0.5.1-py3-none-any.whl", hash = "sha256:e2017f182888c3f3c280d9fbac92e5dbddac024a7e3442f6e6116bd79dab8a9c", size = 32276, upload-time = "2024-10-12T09:40:05.605Z" }, + { url = "https://files.pythonhosted.org/packages/6f/f6/6703fe7cf3d7b7279040c792aeec6334e7305956aba4a80f23e62c8fdc44/sounddevice-0.5.1-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d16cb23d92322526a86a9490c427bf8d49e273d9ccc0bd096feecd229cde6031", size = 107916, upload-time = "2024-10-12T09:40:07.436Z" }, + { url = "https://files.pythonhosted.org/packages/57/a5/78a5e71f5ec0faedc54f4053775d61407bfbd7d0c18228c7f3d4252fd276/sounddevice-0.5.1-py3-none-win32.whl", hash = "sha256:d84cc6231526e7a08e89beff229c37f762baefe5e0cc2747cbe8e3a565470055", size = 312494, upload-time = "2024-10-12T09:40:09.355Z" }, + { url = "https://files.pythonhosted.org/packages/af/9b/15217b04f3b36d30de55fef542389d722de63f1ad81f9c72d8afc98cb6ab/sounddevice-0.5.1-py3-none-win_amd64.whl", hash = "sha256:4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1", size = 363634, upload-time = "2024-10-12T09:40:11.065Z" }, +] + +[[package]] +name = "soundfile" +version = "0.13.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/41/9b873a8c055582859b239be17902a85339bec6a30ad162f98c9b0288a2cc/soundfile-0.13.1.tar.gz", hash = "sha256:b2c68dab1e30297317080a5b43df57e302584c49e2942defdde0acccc53f0e5b", size = 46156, upload-time = "2025-01-25T09:17:04.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/28/e2a36573ccbcf3d57c00626a21fe51989380636e821b341d36ccca0c1c3a/soundfile-0.13.1-py2.py3-none-any.whl", hash = "sha256:a23c717560da2cf4c7b5ae1142514e0fd82d6bbd9dfc93a50423447142f2c445", size = 25751, upload-time = "2025-01-25T09:16:44.235Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ab/73e97a5b3cc46bba7ff8650a1504348fa1863a6f9d57d7001c6b67c5f20e/soundfile-0.13.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:82dc664d19831933fe59adad199bf3945ad06d84bc111a5b4c0d3089a5b9ec33", size = 1142250, upload-time = "2025-01-25T09:16:47.583Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e5/58fd1a8d7b26fc113af244f966ee3aecf03cb9293cb935daaddc1e455e18/soundfile-0.13.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:743f12c12c4054921e15736c6be09ac26b3b3d603aef6fd69f9dde68748f2593", size = 1101406, upload-time = "2025-01-25T09:16:49.662Z" }, + { url = "https://files.pythonhosted.org/packages/58/ae/c0e4a53d77cf6e9a04179535766b3321b0b9ced5f70522e4caf9329f0046/soundfile-0.13.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9c9e855f5a4d06ce4213f31918653ab7de0c5a8d8107cd2427e44b42df547deb", size = 1235729, upload-time = "2025-01-25T09:16:53.018Z" }, + { url = "https://files.pythonhosted.org/packages/57/5e/70bdd9579b35003a489fc850b5047beeda26328053ebadc1fb60f320f7db/soundfile-0.13.1-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:03267c4e493315294834a0870f31dbb3b28a95561b80b134f0bd3cf2d5f0e618", size = 1313646, upload-time = "2025-01-25T09:16:54.872Z" }, + { url = "https://files.pythonhosted.org/packages/fe/df/8c11dc4dfceda14e3003bb81a0d0edcaaf0796dd7b4f826ea3e532146bba/soundfile-0.13.1-py2.py3-none-win32.whl", hash = "sha256:c734564fab7c5ddf8e9be5bf70bab68042cd17e9c214c06e365e20d64f9a69d5", size = 899881, upload-time = "2025-01-25T09:16:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/14/e9/6b761de83277f2f02ded7e7ea6f07828ec78e4b229b80e4ca55dd205b9dc/soundfile-0.13.1-py2.py3-none-win_amd64.whl", hash = "sha256:1e70a05a0626524a69e9f0f4dd2ec174b4e9567f4d8b6c11d38b5c289be36ee9", size = 1019162, upload-time = "2025-01-25T09:16:59.573Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "starlette" +version = "0.47.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/15/b9/cc3017f9a9c9b6e27c5106cc10cc7904653c3eec0729793aec10479dd669/starlette-0.47.3.tar.gz", hash = "sha256:6bc94f839cc176c4858894f1f8908f0ab79dfec1a6b8402f6da9be26ebea52e9", size = 2584144, upload-time = "2025-08-24T13:36:42.122Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/fd/901cfa59aaa5b30a99e16876f11abe38b59a1a2c51ffb3d7142bb6089069/starlette-0.47.3-py3-none-any.whl", hash = "sha256:89c0778ca62a76b826101e7c709e70680a1699ca7da6b44d38eb0a7e61fe4b51", size = 72991, upload-time = "2025-08-24T13:36:40.887Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, + { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429, upload-time = "2024-11-27T22:37:56.698Z" }, + { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067, upload-time = "2024-11-27T22:37:57.63Z" }, + { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030, upload-time = "2024-11-27T22:37:59.344Z" }, + { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898, upload-time = "2024-11-27T22:38:00.429Z" }, + { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894, upload-time = "2024-11-27T22:38:02.094Z" }, + { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319, upload-time = "2024-11-27T22:38:03.206Z" }, + { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273, upload-time = "2024-11-27T22:38:04.217Z" }, + { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310, upload-time = "2024-11-27T22:38:05.908Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309, upload-time = "2024-11-27T22:38:06.812Z" }, + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762, upload-time = "2024-11-27T22:38:07.731Z" }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453, upload-time = "2024-11-27T22:38:09.384Z" }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486, upload-time = "2024-11-27T22:38:10.329Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349, upload-time = "2024-11-27T22:38:11.443Z" }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159, upload-time = "2024-11-27T22:38:13.099Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243, upload-time = "2024-11-27T22:38:14.766Z" }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645, upload-time = "2024-11-27T22:38:15.843Z" }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584, upload-time = "2024-11-27T22:38:17.645Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875, upload-time = "2024-11-27T22:38:19.159Z" }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418, upload-time = "2024-11-27T22:38:20.064Z" }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708, upload-time = "2024-11-27T22:38:21.659Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582, upload-time = "2024-11-27T22:38:22.693Z" }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543, upload-time = "2024-11-27T22:38:24.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691, upload-time = "2024-11-27T22:38:26.081Z" }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170, upload-time = "2024-11-27T22:38:27.921Z" }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530, upload-time = "2024-11-27T22:38:29.591Z" }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666, upload-time = "2024-11-27T22:38:30.639Z" }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954, upload-time = "2024-11-27T22:38:31.702Z" }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724, upload-time = "2024-11-27T22:38:32.837Z" }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383, upload-time = "2024-11-27T22:38:34.455Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821, upload-time = "2025-08-08T18:27:00.78Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563, upload-time = "2025-08-08T18:26:42.945Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729, upload-time = "2025-08-08T18:26:44.473Z" }, + { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295, upload-time = "2025-08-08T18:26:46.021Z" }, + { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644, upload-time = "2025-08-08T18:26:47.625Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878, upload-time = "2025-08-08T18:26:50.599Z" }, + { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549, upload-time = "2025-08-08T18:26:51.864Z" }, + { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973, upload-time = "2025-08-08T18:26:53.625Z" }, + { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954, upload-time = "2025-08-08T18:26:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023, upload-time = "2025-08-08T18:26:56.677Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427, upload-time = "2025-08-08T18:26:57.91Z" }, + { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456, upload-time = "2025-08-08T18:26:59.207Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "transforms3d" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d5/1e/626c2d87c29a35fadc8de5624f4302e1ee56cff380d282d62cb3780e6620/transforms3d-0.4.2.tar.gz", hash = "sha256:e8b5df30eaedbee556e81c6938e55aab5365894e47d0a17615d7db7fd2393680", size = 1368797, upload-time = "2024-06-17T11:43:33.231Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/7a/f38385f1b2d5f54221baf1db3d6371dc6eef8041d95abff39576c694e9d9/transforms3d-0.4.2-py3-none-any.whl", hash = "sha256:1c70399d9e9473ecc23311fd947f727f7c69ed0b063244828c383aa1aefa5941", size = 1376759, upload-time = "2024-06-20T11:09:19.43Z" }, +] + +[[package]] +name = "types-requests" +version = "2.32.4.20250913" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/27/489922f4505975b11de2b5ad07b4fe1dca0bca9be81a703f26c5f3acfce5/types_requests-2.32.4.20250913.tar.gz", hash = "sha256:abd6d4f9ce3a9383f269775a9835a4c24e5cd6b9f647d64f88aa4613c33def5d", size = 23113, upload-time = "2025-09-13T02:40:02.309Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/20/9a227ea57c1285986c4cf78400d0a91615d25b24e257fd9e2969606bdfae/types_requests-2.32.4.20250913-py3-none-any.whl", hash = "sha256:78c9c1fffebbe0fa487a418e0fa5252017e9c60d1a2da394077f1780f655d7e1", size = 20658, upload-time = "2025-09-13T02:40:01.115Z" }, +] + +[[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.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "u-msgpack-python" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/36/9d/a40411a475e7d4838994b7f6bcc6bfca9acc5b119ce3a7503608c4428b49/u-msgpack-python-2.8.0.tar.gz", hash = "sha256:b801a83d6ed75e6df41e44518b4f2a9c221dc2da4bcd5380e3a0feda520bc61a", size = 18167, upload-time = "2023-05-18T09:28:12.187Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/5e/512aeb40fd819f4660d00f96f5c7371ee36fc8c6b605128c5ee59e0b28c6/u_msgpack_python-2.8.0-py2.py3-none-any.whl", hash = "sha256:1d853d33e78b72c4228a2025b4db28cda81214076e5b0422ed0ae1b1b2bb586a", size = 10590, upload-time = "2023-05-18T09:28:10.323Z" }, +] + +[[package]] +name = "urdf-parser-py" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lxml" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/8b/9dd44781a4e87746a426c56c3368c3da64fd90a130f582340cbf74397f8e/urdf_parser_py-0.0.4.tar.gz", hash = "sha256:e983f637145fded67bcff6a542302069bb975b2edf1b18318c093abba1b794cc", size = 12952, upload-time = "2021-11-11T17:20:42.012Z" } + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.35.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, + { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, + { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, + { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, + { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, + { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, + { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, + { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, + { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, + { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, + { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, + { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, + { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, + { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, + { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, + { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, + { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, + { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, + { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.34.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/14/37fcdba2808a6c615681cd216fecae00413c9dab44fb2e57805ecf3eaee3/virtualenv-20.34.0.tar.gz", hash = "sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a", size = 6003808, upload-time = "2025-08-13T14:24:07.464Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/06/04c8e804f813cf972e3262f3f8584c232de64f0cde9f703b46cf53a45090/virtualenv-20.34.0-py3-none-any.whl", hash = "sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026", size = 5983279, upload-time = "2025-08-13T14:24:05.111Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/9a/d451fcc97d029f5812e898fd30a53fd8c15c7bbd058fd75cfc6beb9bd761/watchfiles-1.1.0.tar.gz", hash = "sha256:693ed7ec72cbfcee399e92c895362b6e66d63dac6b91e2c11ae03d10d503e575", size = 94406, upload-time = "2025-06-15T19:06:59.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/dd/579d1dc57f0f895426a1211c4ef3b0cb37eb9e642bb04bdcd962b5df206a/watchfiles-1.1.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:27f30e14aa1c1e91cb653f03a63445739919aef84c8d2517997a83155e7a2fcc", size = 405757, upload-time = "2025-06-15T19:04:51.058Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a0/7a0318cd874393344d48c34d53b3dd419466adf59a29ba5b51c88dd18b86/watchfiles-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3366f56c272232860ab45c77c3ca7b74ee819c8e1f6f35a7125556b198bbc6df", size = 397511, upload-time = "2025-06-15T19:04:52.79Z" }, + { url = "https://files.pythonhosted.org/packages/06/be/503514656d0555ec2195f60d810eca29b938772e9bfb112d5cd5ad6f6a9e/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8412eacef34cae2836d891836a7fff7b754d6bcac61f6c12ba5ca9bc7e427b68", size = 450739, upload-time = "2025-06-15T19:04:54.203Z" }, + { url = "https://files.pythonhosted.org/packages/4e/0d/a05dd9e5f136cdc29751816d0890d084ab99f8c17b86f25697288ca09bc7/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df670918eb7dd719642e05979fc84704af913d563fd17ed636f7c4783003fdcc", size = 458106, upload-time = "2025-06-15T19:04:55.607Z" }, + { url = "https://files.pythonhosted.org/packages/f1/fa/9cd16e4dfdb831072b7ac39e7bea986e52128526251038eb481effe9f48e/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7642b9bc4827b5518ebdb3b82698ada8c14c7661ddec5fe719f3e56ccd13c97", size = 484264, upload-time = "2025-06-15T19:04:57.009Z" }, + { url = "https://files.pythonhosted.org/packages/32/04/1da8a637c7e2b70e750a0308e9c8e662ada0cca46211fa9ef24a23937e0b/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:199207b2d3eeaeb80ef4411875a6243d9ad8bc35b07fc42daa6b801cc39cc41c", size = 597612, upload-time = "2025-06-15T19:04:58.409Z" }, + { url = "https://files.pythonhosted.org/packages/30/01/109f2762e968d3e58c95731a206e5d7d2a7abaed4299dd8a94597250153c/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a479466da6db5c1e8754caee6c262cd373e6e6c363172d74394f4bff3d84d7b5", size = 477242, upload-time = "2025-06-15T19:04:59.786Z" }, + { url = "https://files.pythonhosted.org/packages/b5/b8/46f58cf4969d3b7bc3ca35a98e739fa4085b0657a1540ccc29a1a0bc016f/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:935f9edd022ec13e447e5723a7d14456c8af254544cefbc533f6dd276c9aa0d9", size = 453148, upload-time = "2025-06-15T19:05:01.103Z" }, + { url = "https://files.pythonhosted.org/packages/a5/cd/8267594263b1770f1eb76914940d7b2d03ee55eca212302329608208e061/watchfiles-1.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8076a5769d6bdf5f673a19d51da05fc79e2bbf25e9fe755c47595785c06a8c72", size = 626574, upload-time = "2025-06-15T19:05:02.582Z" }, + { url = "https://files.pythonhosted.org/packages/a1/2f/7f2722e85899bed337cba715723e19185e288ef361360718973f891805be/watchfiles-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86b1e28d4c37e89220e924305cd9f82866bb0ace666943a6e4196c5df4d58dcc", size = 624378, upload-time = "2025-06-15T19:05:03.719Z" }, + { url = "https://files.pythonhosted.org/packages/bf/20/64c88ec43d90a568234d021ab4b2a6f42a5230d772b987c3f9c00cc27b8b/watchfiles-1.1.0-cp310-cp310-win32.whl", hash = "sha256:d1caf40c1c657b27858f9774d5c0e232089bca9cb8ee17ce7478c6e9264d2587", size = 279829, upload-time = "2025-06-15T19:05:04.822Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/a9c1ed33de7af80935e4eac09570de679c6e21c07070aa99f74b4431f4d6/watchfiles-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:a89c75a5b9bc329131115a409d0acc16e8da8dfd5867ba59f1dd66ae7ea8fa82", size = 292192, upload-time = "2025-06-15T19:05:06.348Z" }, + { url = "https://files.pythonhosted.org/packages/8b/78/7401154b78ab484ccaaeef970dc2af0cb88b5ba8a1b415383da444cdd8d3/watchfiles-1.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c9649dfc57cc1f9835551deb17689e8d44666315f2e82d337b9f07bd76ae3aa2", size = 405751, upload-time = "2025-06-15T19:05:07.679Z" }, + { url = "https://files.pythonhosted.org/packages/76/63/e6c3dbc1f78d001589b75e56a288c47723de28c580ad715eb116639152b5/watchfiles-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:406520216186b99374cdb58bc48e34bb74535adec160c8459894884c983a149c", size = 397313, upload-time = "2025-06-15T19:05:08.764Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a2/8afa359ff52e99af1632f90cbf359da46184207e893a5f179301b0c8d6df/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb45350fd1dc75cd68d3d72c47f5b513cb0578da716df5fba02fff31c69d5f2d", size = 450792, upload-time = "2025-06-15T19:05:09.869Z" }, + { url = "https://files.pythonhosted.org/packages/1d/bf/7446b401667f5c64972a57a0233be1104157fc3abf72c4ef2666c1bd09b2/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11ee4444250fcbeb47459a877e5e80ed994ce8e8d20283857fc128be1715dac7", size = 458196, upload-time = "2025-06-15T19:05:11.91Z" }, + { url = "https://files.pythonhosted.org/packages/58/2f/501ddbdfa3fa874ea5597c77eeea3d413579c29af26c1091b08d0c792280/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bda8136e6a80bdea23e5e74e09df0362744d24ffb8cd59c4a95a6ce3d142f79c", size = 484788, upload-time = "2025-06-15T19:05:13.373Z" }, + { url = "https://files.pythonhosted.org/packages/61/1e/9c18eb2eb5c953c96bc0e5f626f0e53cfef4bd19bd50d71d1a049c63a575/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b915daeb2d8c1f5cee4b970f2e2c988ce6514aace3c9296e58dd64dc9aa5d575", size = 597879, upload-time = "2025-06-15T19:05:14.725Z" }, + { url = "https://files.pythonhosted.org/packages/8b/6c/1467402e5185d89388b4486745af1e0325007af0017c3384cc786fff0542/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed8fc66786de8d0376f9f913c09e963c66e90ced9aa11997f93bdb30f7c872a8", size = 477447, upload-time = "2025-06-15T19:05:15.775Z" }, + { url = "https://files.pythonhosted.org/packages/2b/a1/ec0a606bde4853d6c4a578f9391eeb3684a9aea736a8eb217e3e00aa89a1/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe4371595edf78c41ef8ac8df20df3943e13defd0efcb732b2e393b5a8a7a71f", size = 453145, upload-time = "2025-06-15T19:05:17.17Z" }, + { url = "https://files.pythonhosted.org/packages/90/b9/ef6f0c247a6a35d689fc970dc7f6734f9257451aefb30def5d100d6246a5/watchfiles-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b7c5f6fe273291f4d414d55b2c80d33c457b8a42677ad14b4b47ff025d0893e4", size = 626539, upload-time = "2025-06-15T19:05:18.557Z" }, + { url = "https://files.pythonhosted.org/packages/34/44/6ffda5537085106ff5aaa762b0d130ac6c75a08015dd1621376f708c94de/watchfiles-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7738027989881e70e3723c75921f1efa45225084228788fc59ea8c6d732eb30d", size = 624472, upload-time = "2025-06-15T19:05:19.588Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e3/71170985c48028fa3f0a50946916a14055e741db11c2e7bc2f3b61f4d0e3/watchfiles-1.1.0-cp311-cp311-win32.whl", hash = "sha256:622d6b2c06be19f6e89b1d951485a232e3b59618def88dbeda575ed8f0d8dbf2", size = 279348, upload-time = "2025-06-15T19:05:20.856Z" }, + { url = "https://files.pythonhosted.org/packages/89/1b/3e39c68b68a7a171070f81fc2561d23ce8d6859659406842a0e4bebf3bba/watchfiles-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:48aa25e5992b61debc908a61ab4d3f216b64f44fdaa71eb082d8b2de846b7d12", size = 292607, upload-time = "2025-06-15T19:05:21.937Z" }, + { url = "https://files.pythonhosted.org/packages/61/9f/2973b7539f2bdb6ea86d2c87f70f615a71a1fc2dba2911795cea25968aea/watchfiles-1.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:00645eb79a3faa70d9cb15c8d4187bb72970b2470e938670240c7998dad9f13a", size = 285056, upload-time = "2025-06-15T19:05:23.12Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b8/858957045a38a4079203a33aaa7d23ea9269ca7761c8a074af3524fbb240/watchfiles-1.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9dc001c3e10de4725c749d4c2f2bdc6ae24de5a88a339c4bce32300a31ede179", size = 402339, upload-time = "2025-06-15T19:05:24.516Z" }, + { url = "https://files.pythonhosted.org/packages/80/28/98b222cca751ba68e88521fabd79a4fab64005fc5976ea49b53fa205d1fa/watchfiles-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d9ba68ec283153dead62cbe81872d28e053745f12335d037de9cbd14bd1877f5", size = 394409, upload-time = "2025-06-15T19:05:25.469Z" }, + { url = "https://files.pythonhosted.org/packages/86/50/dee79968566c03190677c26f7f47960aff738d32087087bdf63a5473e7df/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130fc497b8ee68dce163e4254d9b0356411d1490e868bd8790028bc46c5cc297", size = 450939, upload-time = "2025-06-15T19:05:26.494Z" }, + { url = "https://files.pythonhosted.org/packages/40/45/a7b56fb129700f3cfe2594a01aa38d033b92a33dddce86c8dfdfc1247b72/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50a51a90610d0845a5931a780d8e51d7bd7f309ebc25132ba975aca016b576a0", size = 457270, upload-time = "2025-06-15T19:05:27.466Z" }, + { url = "https://files.pythonhosted.org/packages/b5/c8/fa5ef9476b1d02dc6b5e258f515fcaaecf559037edf8b6feffcbc097c4b8/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc44678a72ac0910bac46fa6a0de6af9ba1355669b3dfaf1ce5f05ca7a74364e", size = 483370, upload-time = "2025-06-15T19:05:28.548Z" }, + { url = "https://files.pythonhosted.org/packages/98/68/42cfcdd6533ec94f0a7aab83f759ec11280f70b11bfba0b0f885e298f9bd/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a543492513a93b001975ae283a51f4b67973662a375a403ae82f420d2c7205ee", size = 598654, upload-time = "2025-06-15T19:05:29.997Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/b2a1544224118cc28df7e59008a929e711f9c68ce7d554e171b2dc531352/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ac164e20d17cc285f2b94dc31c384bc3aa3dd5e7490473b3db043dd70fbccfd", size = 478667, upload-time = "2025-06-15T19:05:31.172Z" }, + { url = "https://files.pythonhosted.org/packages/8c/77/e3362fe308358dc9f8588102481e599c83e1b91c2ae843780a7ded939a35/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7590d5a455321e53857892ab8879dce62d1f4b04748769f5adf2e707afb9d4f", size = 452213, upload-time = "2025-06-15T19:05:32.299Z" }, + { url = "https://files.pythonhosted.org/packages/6e/17/c8f1a36540c9a1558d4faf08e909399e8133599fa359bf52ec8fcee5be6f/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:37d3d3f7defb13f62ece99e9be912afe9dd8a0077b7c45ee5a57c74811d581a4", size = 626718, upload-time = "2025-06-15T19:05:33.415Z" }, + { url = "https://files.pythonhosted.org/packages/26/45/fb599be38b4bd38032643783d7496a26a6f9ae05dea1a42e58229a20ac13/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7080c4bb3efd70a07b1cc2df99a7aa51d98685be56be6038c3169199d0a1c69f", size = 623098, upload-time = "2025-06-15T19:05:34.534Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e7/fdf40e038475498e160cd167333c946e45d8563ae4dd65caf757e9ffe6b4/watchfiles-1.1.0-cp312-cp312-win32.whl", hash = "sha256:cbcf8630ef4afb05dc30107bfa17f16c0896bb30ee48fc24bf64c1f970f3b1fd", size = 279209, upload-time = "2025-06-15T19:05:35.577Z" }, + { url = "https://files.pythonhosted.org/packages/3f/d3/3ae9d5124ec75143bdf088d436cba39812122edc47709cd2caafeac3266f/watchfiles-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:cbd949bdd87567b0ad183d7676feb98136cde5bb9025403794a4c0db28ed3a47", size = 292786, upload-time = "2025-06-15T19:05:36.559Z" }, + { url = "https://files.pythonhosted.org/packages/26/2f/7dd4fc8b5f2b34b545e19629b4a018bfb1de23b3a496766a2c1165ca890d/watchfiles-1.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:0a7d40b77f07be87c6faa93d0951a0fcd8cbca1ddff60a1b65d741bac6f3a9f6", size = 284343, upload-time = "2025-06-15T19:05:37.5Z" }, + { url = "https://files.pythonhosted.org/packages/d3/42/fae874df96595556a9089ade83be34a2e04f0f11eb53a8dbf8a8a5e562b4/watchfiles-1.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5007f860c7f1f8df471e4e04aaa8c43673429047d63205d1630880f7637bca30", size = 402004, upload-time = "2025-06-15T19:05:38.499Z" }, + { url = "https://files.pythonhosted.org/packages/fa/55/a77e533e59c3003d9803c09c44c3651224067cbe7fb5d574ddbaa31e11ca/watchfiles-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:20ecc8abbd957046f1fe9562757903f5eaf57c3bce70929fda6c7711bb58074a", size = 393671, upload-time = "2025-06-15T19:05:39.52Z" }, + { url = "https://files.pythonhosted.org/packages/05/68/b0afb3f79c8e832e6571022611adbdc36e35a44e14f129ba09709aa4bb7a/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2f0498b7d2a3c072766dba3274fe22a183dbea1f99d188f1c6c72209a1063dc", size = 449772, upload-time = "2025-06-15T19:05:40.897Z" }, + { url = "https://files.pythonhosted.org/packages/ff/05/46dd1f6879bc40e1e74c6c39a1b9ab9e790bf1f5a2fe6c08b463d9a807f4/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:239736577e848678e13b201bba14e89718f5c2133dfd6b1f7846fa1b58a8532b", size = 456789, upload-time = "2025-06-15T19:05:42.045Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ca/0eeb2c06227ca7f12e50a47a3679df0cd1ba487ea19cf844a905920f8e95/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eff4b8d89f444f7e49136dc695599a591ff769300734446c0a86cba2eb2f9895", size = 482551, upload-time = "2025-06-15T19:05:43.781Z" }, + { url = "https://files.pythonhosted.org/packages/31/47/2cecbd8694095647406645f822781008cc524320466ea393f55fe70eed3b/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12b0a02a91762c08f7264e2e79542f76870c3040bbc847fb67410ab81474932a", size = 597420, upload-time = "2025-06-15T19:05:45.244Z" }, + { url = "https://files.pythonhosted.org/packages/d9/7e/82abc4240e0806846548559d70f0b1a6dfdca75c1b4f9fa62b504ae9b083/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29e7bc2eee15cbb339c68445959108803dc14ee0c7b4eea556400131a8de462b", size = 477950, upload-time = "2025-06-15T19:05:46.332Z" }, + { url = "https://files.pythonhosted.org/packages/25/0d/4d564798a49bf5482a4fa9416dea6b6c0733a3b5700cb8a5a503c4b15853/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9481174d3ed982e269c090f780122fb59cee6c3796f74efe74e70f7780ed94c", size = 451706, upload-time = "2025-06-15T19:05:47.459Z" }, + { url = "https://files.pythonhosted.org/packages/81/b5/5516cf46b033192d544102ea07c65b6f770f10ed1d0a6d388f5d3874f6e4/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:80f811146831c8c86ab17b640801c25dc0a88c630e855e2bef3568f30434d52b", size = 625814, upload-time = "2025-06-15T19:05:48.654Z" }, + { url = "https://files.pythonhosted.org/packages/0c/dd/7c1331f902f30669ac3e754680b6edb9a0dd06dea5438e61128111fadd2c/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:60022527e71d1d1fda67a33150ee42869042bce3d0fcc9cc49be009a9cded3fb", size = 622820, upload-time = "2025-06-15T19:05:50.088Z" }, + { url = "https://files.pythonhosted.org/packages/1b/14/36d7a8e27cd128d7b1009e7715a7c02f6c131be9d4ce1e5c3b73d0e342d8/watchfiles-1.1.0-cp313-cp313-win32.whl", hash = "sha256:32d6d4e583593cb8576e129879ea0991660b935177c0f93c6681359b3654bfa9", size = 279194, upload-time = "2025-06-15T19:05:51.186Z" }, + { url = "https://files.pythonhosted.org/packages/25/41/2dd88054b849aa546dbeef5696019c58f8e0774f4d1c42123273304cdb2e/watchfiles-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:f21af781a4a6fbad54f03c598ab620e3a77032c5878f3d780448421a6e1818c7", size = 292349, upload-time = "2025-06-15T19:05:52.201Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cf/421d659de88285eb13941cf11a81f875c176f76a6d99342599be88e08d03/watchfiles-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:5366164391873ed76bfdf618818c82084c9db7fac82b64a20c44d335eec9ced5", size = 283836, upload-time = "2025-06-15T19:05:53.265Z" }, + { url = "https://files.pythonhosted.org/packages/45/10/6faf6858d527e3599cc50ec9fcae73590fbddc1420bd4fdccfebffeedbc6/watchfiles-1.1.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:17ab167cca6339c2b830b744eaf10803d2a5b6683be4d79d8475d88b4a8a4be1", size = 400343, upload-time = "2025-06-15T19:05:54.252Z" }, + { url = "https://files.pythonhosted.org/packages/03/20/5cb7d3966f5e8c718006d0e97dfe379a82f16fecd3caa7810f634412047a/watchfiles-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:328dbc9bff7205c215a7807da7c18dce37da7da718e798356212d22696404339", size = 392916, upload-time = "2025-06-15T19:05:55.264Z" }, + { url = "https://files.pythonhosted.org/packages/8c/07/d8f1176328fa9e9581b6f120b017e286d2a2d22ae3f554efd9515c8e1b49/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7208ab6e009c627b7557ce55c465c98967e8caa8b11833531fdf95799372633", size = 449582, upload-time = "2025-06-15T19:05:56.317Z" }, + { url = "https://files.pythonhosted.org/packages/66/e8/80a14a453cf6038e81d072a86c05276692a1826471fef91df7537dba8b46/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8f6f72974a19efead54195bc9bed4d850fc047bb7aa971268fd9a8387c89011", size = 456752, upload-time = "2025-06-15T19:05:57.359Z" }, + { url = "https://files.pythonhosted.org/packages/5a/25/0853b3fe0e3c2f5af9ea60eb2e781eade939760239a72c2d38fc4cc335f6/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d181ef50923c29cf0450c3cd47e2f0557b62218c50b2ab8ce2ecaa02bd97e670", size = 481436, upload-time = "2025-06-15T19:05:58.447Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9e/4af0056c258b861fbb29dcb36258de1e2b857be4a9509e6298abcf31e5c9/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adb4167043d3a78280d5d05ce0ba22055c266cf8655ce942f2fb881262ff3cdf", size = 596016, upload-time = "2025-06-15T19:05:59.59Z" }, + { url = "https://files.pythonhosted.org/packages/c5/fa/95d604b58aa375e781daf350897aaaa089cff59d84147e9ccff2447c8294/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5701dc474b041e2934a26d31d39f90fac8a3dee2322b39f7729867f932b1d4", size = 476727, upload-time = "2025-06-15T19:06:01.086Z" }, + { url = "https://files.pythonhosted.org/packages/65/95/fe479b2664f19be4cf5ceeb21be05afd491d95f142e72d26a42f41b7c4f8/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20", size = 451864, upload-time = "2025-06-15T19:06:02.144Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8a/3c4af14b93a15ce55901cd7a92e1a4701910f1768c78fb30f61d2b79785b/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef", size = 625626, upload-time = "2025-06-15T19:06:03.578Z" }, + { url = "https://files.pythonhosted.org/packages/da/f5/cf6aa047d4d9e128f4b7cde615236a915673775ef171ff85971d698f3c2c/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb", size = 622744, upload-time = "2025-06-15T19:06:05.066Z" }, + { url = "https://files.pythonhosted.org/packages/2c/00/70f75c47f05dea6fd30df90f047765f6fc2d6eb8b5a3921379b0b04defa2/watchfiles-1.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297", size = 402114, upload-time = "2025-06-15T19:06:06.186Z" }, + { url = "https://files.pythonhosted.org/packages/53/03/acd69c48db4a1ed1de26b349d94077cca2238ff98fd64393f3e97484cae6/watchfiles-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018", size = 393879, upload-time = "2025-06-15T19:06:07.369Z" }, + { url = "https://files.pythonhosted.org/packages/2f/c8/a9a2a6f9c8baa4eceae5887fecd421e1b7ce86802bcfc8b6a942e2add834/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0", size = 450026, upload-time = "2025-06-15T19:06:08.476Z" }, + { url = "https://files.pythonhosted.org/packages/fe/51/d572260d98388e6e2b967425c985e07d47ee6f62e6455cefb46a6e06eda5/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12", size = 457917, upload-time = "2025-06-15T19:06:09.988Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2d/4258e52917bf9f12909b6ec314ff9636276f3542f9d3807d143f27309104/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb", size = 483602, upload-time = "2025-06-15T19:06:11.088Z" }, + { url = "https://files.pythonhosted.org/packages/84/99/bee17a5f341a4345fe7b7972a475809af9e528deba056f8963d61ea49f75/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77", size = 596758, upload-time = "2025-06-15T19:06:12.197Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/e4bec1d59b25b89d2b0716b41b461ed655a9a53c60dc78ad5771fda5b3e6/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92", size = 477601, upload-time = "2025-06-15T19:06:13.391Z" }, + { url = "https://files.pythonhosted.org/packages/1f/fa/a514292956f4a9ce3c567ec0c13cce427c158e9f272062685a8a727d08fc/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e", size = 451936, upload-time = "2025-06-15T19:06:14.656Z" }, + { url = "https://files.pythonhosted.org/packages/32/5d/c3bf927ec3bbeb4566984eba8dd7a8eb69569400f5509904545576741f88/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b", size = 626243, upload-time = "2025-06-15T19:06:16.232Z" }, + { url = "https://files.pythonhosted.org/packages/e6/65/6e12c042f1a68c556802a84d54bb06d35577c81e29fba14019562479159c/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259", size = 623073, upload-time = "2025-06-15T19:06:17.457Z" }, + { url = "https://files.pythonhosted.org/packages/89/ab/7f79d9bf57329e7cbb0a6fd4c7bd7d0cee1e4a8ef0041459f5409da3506c/watchfiles-1.1.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f", size = 400872, upload-time = "2025-06-15T19:06:18.57Z" }, + { url = "https://files.pythonhosted.org/packages/df/d5/3f7bf9912798e9e6c516094db6b8932df53b223660c781ee37607030b6d3/watchfiles-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e", size = 392877, upload-time = "2025-06-15T19:06:19.55Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c5/54ec7601a2798604e01c75294770dbee8150e81c6e471445d7601610b495/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa", size = 449645, upload-time = "2025-06-15T19:06:20.66Z" }, + { url = "https://files.pythonhosted.org/packages/0a/04/c2f44afc3b2fce21ca0b7802cbd37ed90a29874f96069ed30a36dfe57c2b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8", size = 457424, upload-time = "2025-06-15T19:06:21.712Z" }, + { url = "https://files.pythonhosted.org/packages/9f/b0/eec32cb6c14d248095261a04f290636da3df3119d4040ef91a4a50b29fa5/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f", size = 481584, upload-time = "2025-06-15T19:06:22.777Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/ca4bb71c68a937d7145aa25709e4f5d68eb7698a25ce266e84b55d591bbd/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e", size = 596675, upload-time = "2025-06-15T19:06:24.226Z" }, + { url = "https://files.pythonhosted.org/packages/a1/dd/b0e4b7fb5acf783816bc950180a6cd7c6c1d2cf7e9372c0ea634e722712b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb", size = 477363, upload-time = "2025-06-15T19:06:25.42Z" }, + { url = "https://files.pythonhosted.org/packages/69/c4/088825b75489cb5b6a761a4542645718893d395d8c530b38734f19da44d2/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147", size = 452240, upload-time = "2025-06-15T19:06:26.552Z" }, + { url = "https://files.pythonhosted.org/packages/10/8c/22b074814970eeef43b7c44df98c3e9667c1f7bf5b83e0ff0201b0bd43f9/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8", size = 625607, upload-time = "2025-06-15T19:06:27.606Z" }, + { url = "https://files.pythonhosted.org/packages/32/fa/a4f5c2046385492b2273213ef815bf71a0d4c1943b784fb904e184e30201/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db", size = 623315, upload-time = "2025-06-15T19:06:29.076Z" }, + { url = "https://files.pythonhosted.org/packages/be/7c/a3d7c55cfa377c2f62c4ae3c6502b997186bc5e38156bafcb9b653de9a6d/watchfiles-1.1.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3a6fd40bbb50d24976eb275ccb55cd1951dfb63dbc27cae3066a6ca5f4beabd5", size = 406748, upload-time = "2025-06-15T19:06:44.2Z" }, + { url = "https://files.pythonhosted.org/packages/38/d0/c46f1b2c0ca47f3667b144de6f0515f6d1c670d72f2ca29861cac78abaa1/watchfiles-1.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9f811079d2f9795b5d48b55a37aa7773680a5659afe34b54cc1d86590a51507d", size = 398801, upload-time = "2025-06-15T19:06:45.774Z" }, + { url = "https://files.pythonhosted.org/packages/70/9c/9a6a42e97f92eeed77c3485a43ea96723900aefa3ac739a8c73f4bff2cd7/watchfiles-1.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2726d7bfd9f76158c84c10a409b77a320426540df8c35be172444394b17f7ea", size = 451528, upload-time = "2025-06-15T19:06:46.791Z" }, + { url = "https://files.pythonhosted.org/packages/51/7b/98c7f4f7ce7ff03023cf971cd84a3ee3b790021ae7584ffffa0eb2554b96/watchfiles-1.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df32d59cb9780f66d165a9a7a26f19df2c7d24e3bd58713108b41d0ff4f929c6", size = 454095, upload-time = "2025-06-15T19:06:48.211Z" }, + { url = "https://files.pythonhosted.org/packages/8c/6b/686dcf5d3525ad17b384fd94708e95193529b460a1b7bf40851f1328ec6e/watchfiles-1.1.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0ece16b563b17ab26eaa2d52230c9a7ae46cf01759621f4fbbca280e438267b3", size = 406910, upload-time = "2025-06-15T19:06:49.335Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d3/71c2dcf81dc1edcf8af9f4d8d63b1316fb0a2dd90cbfd427e8d9dd584a90/watchfiles-1.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:51b81e55d40c4b4aa8658427a3ee7ea847c591ae9e8b81ef94a90b668999353c", size = 398816, upload-time = "2025-06-15T19:06:50.433Z" }, + { url = "https://files.pythonhosted.org/packages/b8/fa/12269467b2fc006f8fce4cd6c3acfa77491dd0777d2a747415f28ccc8c60/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2bcdc54ea267fe72bfc7d83c041e4eb58d7d8dc6f578dfddb52f037ce62f432", size = 451584, upload-time = "2025-06-15T19:06:51.834Z" }, + { url = "https://files.pythonhosted.org/packages/bd/d3/254cea30f918f489db09d6a8435a7de7047f8cb68584477a515f160541d6/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923fec6e5461c42bd7e3fd5ec37492c6f3468be0499bc0707b4bbbc16ac21792", size = 454009, upload-time = "2025-06-15T19:06:52.896Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, +] + +[[package]] +name = "websockets" +version = "11.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/3b/2ed38e52eed4cf277f9df5f0463a99199a04d9e29c9e227cfafa57bd3993/websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016", size = 104235, upload-time = "2023-05-07T14:25:20.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/76/88640f8aeac7eb0d058b913e7bb72682f8d569db44c7d30e576ec4777ce1/websockets-11.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac", size = 123714, upload-time = "2023-05-07T14:23:15.309Z" }, + { url = "https://files.pythonhosted.org/packages/b9/6b/26b28115b46e23e74ede76d95792eedfe8c58b21f4daabfff1e9f159c8fe/websockets-11.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d", size = 120949, upload-time = "2023-05-07T14:23:17.656Z" }, + { url = "https://files.pythonhosted.org/packages/f3/82/2d1f3395d47fab65fa8b801e2251b324300ed8db54753b6fb7919cef0c11/websockets-11.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f", size = 121032, upload-time = "2023-05-07T14:23:20.096Z" }, + { url = "https://files.pythonhosted.org/packages/b2/ec/56bdd12d847e4fc2d0a7ba2d7f1476f79cda50599d11ffb6080b86f21ef1/websockets-11.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564", size = 130620, upload-time = "2023-05-07T14:23:21.545Z" }, + { url = "https://files.pythonhosted.org/packages/c9/fb/ae5ed4be3514287cf8f6c348c87e1392a6e3f4d6eadae75c18847a2f84b6/websockets-11.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11", size = 129628, upload-time = "2023-05-07T14:23:23.105Z" }, + { url = "https://files.pythonhosted.org/packages/58/0a/7570e15661a0a546c3a1152d95fe8c05480459bab36247f0acbf41f01a41/websockets-11.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca", size = 129938, upload-time = "2023-05-07T14:23:24.959Z" }, + { url = "https://files.pythonhosted.org/packages/ba/6c/5c0322b2875e8395e6bf0eff11f43f3e25da7ef5b12f4d908cd3a19ea841/websockets-11.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54", size = 134663, upload-time = "2023-05-07T14:23:26.382Z" }, + { url = "https://files.pythonhosted.org/packages/de/0e/d7274e4d41d7b34f204744c27a23707be2ecefaf6f7df2145655f086ecd7/websockets-11.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4", size = 133900, upload-time = "2023-05-07T14:23:28.307Z" }, + { url = "https://files.pythonhosted.org/packages/82/3c/00f051abcf88aec5e952a8840076749b0b26a30c219dcae8ba70200998aa/websockets-11.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526", size = 134520, upload-time = "2023-05-07T14:23:30.734Z" }, + { url = "https://files.pythonhosted.org/packages/8f/7b/4d4ecd29be7d08486e38f987a6603c491296d1e33fe55127d79aebb0333e/websockets-11.0.3-cp310-cp310-win32.whl", hash = "sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69", size = 124152, upload-time = "2023-05-07T14:23:33.183Z" }, + { url = "https://files.pythonhosted.org/packages/98/a7/0ed69892981351e5acf88fac0ff4c801fabca2c3bdef9fca4c7d3fde8c53/websockets-11.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f", size = 124674, upload-time = "2023-05-07T14:23:35.331Z" }, + { url = "https://files.pythonhosted.org/packages/16/49/ae616bd221efba84a3d78737b417f704af1ffa36f40dcaba5eb954dd4753/websockets-11.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb", size = 123748, upload-time = "2023-05-07T14:23:37.977Z" }, + { url = "https://files.pythonhosted.org/packages/0a/84/68b848a373493b58615d6c10e9e8ccbaadfd540f84905421739a807704f8/websockets-11.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288", size = 120975, upload-time = "2023-05-07T14:23:40.339Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a8/e81533499f84ef6cdd95d11d5b05fa827c0f097925afd86f16e6a2631d8e/websockets-11.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d", size = 121017, upload-time = "2023-05-07T14:23:41.874Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ca/65d6986665888494eca4d5435a9741c822022996f0f4200c57ce4b9242f7/websockets-11.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3", size = 131200, upload-time = "2023-05-07T14:23:43.309Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a8/a8a582ebeeecc8b5f332997d44c57e241748f8a9856e06a38a5a13b30796/websockets-11.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b", size = 130195, upload-time = "2023-05-07T14:23:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5e/b25c60067d700e811dccb4e3c318eeadd3a19d8b3620de9f97434af777a7/websockets-11.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6", size = 130569, upload-time = "2023-05-07T14:23:46.926Z" }, + { url = "https://files.pythonhosted.org/packages/14/fc/5cbbf439c925e1e184a0392ec477a30cee2fabc0e63807c1d4b6d570fb52/websockets-11.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97", size = 136015, upload-time = "2023-05-07T14:23:48.43Z" }, + { url = "https://files.pythonhosted.org/packages/0f/d8/a997d3546aef9cc995a1126f7d7ade96c0e16c1a0efb9d2d430aee57c925/websockets-11.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf", size = 135292, upload-time = "2023-05-07T14:23:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/89/8f/707a05d5725f956c78d252a5fd73b89fa3ac57dd3959381c2d1acb41cb13/websockets-11.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd", size = 135890, upload-time = "2023-05-07T14:23:52.707Z" }, + { url = "https://files.pythonhosted.org/packages/b5/94/ac47552208583d5dbcce468430c1eb2ae18962f6b3a694a2b7727cc60d4a/websockets-11.0.3-cp311-cp311-win32.whl", hash = "sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c", size = 124149, upload-time = "2023-05-07T14:23:53.848Z" }, + { url = "https://files.pythonhosted.org/packages/e1/7c/0ad6e7ef0a054d73092f616d20d3d9bd3e1b837554cb20a52d8dd9f5b049/websockets-11.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8", size = 124670, upload-time = "2023-05-07T14:23:55.812Z" }, + { url = "https://files.pythonhosted.org/packages/47/96/9d5749106ff57629b54360664ae7eb9afd8302fad1680ead385383e33746/websockets-11.0.3-py3-none-any.whl", hash = "sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6", size = 118056, upload-time = "2023-05-07T14:25:18.508Z" }, +] + +[[package]] +name = "yarl" +version = "1.20.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, + { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, + { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, + { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, + { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, + { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, + { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, + { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, + { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, + { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, + { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, + { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, + { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, + { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, + { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, + { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, + { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, + { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, + { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, + { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, + { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, + { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, + { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, + { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, + { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, + { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, + { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, + { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, + { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, + { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, + { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, + { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, + { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, + { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, + { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, + { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, + { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, + { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, + { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, + { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, + { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, + { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, + { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, + { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, + { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, + { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, + { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, + { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, + { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, + { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, + { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, + { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, + { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, + { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, + { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, + { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, + { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, + { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, + { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, + { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, + { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, + { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, + { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +] diff --git a/rmscript/.idea/.gitignore b/rmscript/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..13566b81b018ad684f3a35fee301741b2734c8f4 --- /dev/null +++ b/rmscript/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/rmscript/.idea/copilot.data.migration.agent.xml b/rmscript/.idea/copilot.data.migration.agent.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ea72a911af2d782f20b992e808276bb838718d8 --- /dev/null +++ b/rmscript/.idea/copilot.data.migration.agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/rmscript/.idea/copilot.data.migration.ask.xml b/rmscript/.idea/copilot.data.migration.ask.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ef04e2ea0752989be4a246d998b53adf46bab42 --- /dev/null +++ b/rmscript/.idea/copilot.data.migration.ask.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/rmscript/.idea/copilot.data.migration.ask2agent.xml b/rmscript/.idea/copilot.data.migration.ask2agent.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f2ea11e7f0069b02b6f715f9735b8a31b234538 --- /dev/null +++ b/rmscript/.idea/copilot.data.migration.ask2agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/rmscript/.idea/copilot.data.migration.edit.xml b/rmscript/.idea/copilot.data.migration.edit.xml new file mode 100644 index 0000000000000000000000000000000000000000..8648f9401aa827dc53e658ac3b1c1f1556df236b --- /dev/null +++ b/rmscript/.idea/copilot.data.migration.edit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/rmscript/.idea/inspectionProfiles/Project_Default.xml b/rmscript/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000000000000000000000000000000000..2969ecaa0b9bfe9d6363eaa2ef4c09f62350419e --- /dev/null +++ b/rmscript/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,87 @@ + + + + \ No newline at end of file diff --git a/rmscript/.idea/inspectionProfiles/profiles_settings.xml b/rmscript/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..105ce2da2d6447d11dfe32bfb846c3d5b199fc99 --- /dev/null +++ b/rmscript/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/rmscript/.idea/misc.xml b/rmscript/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba42d52e8c1e1e75bc460b697efdcbf2f23a5754 --- /dev/null +++ b/rmscript/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/rmscript/.idea/modules.xml b/rmscript/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..808fea148f42f29df0f6526c6b4abad3588547df --- /dev/null +++ b/rmscript/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/rmscript/.idea/rmscript.iml b/rmscript/.idea/rmscript.iml new file mode 100644 index 0000000000000000000000000000000000000000..749e725db0752f36e5c13f06bb47f8057632568c --- /dev/null +++ b/rmscript/.idea/rmscript.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/rmscript/README.md b/rmscript/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ca8752f2d2fdb896a190f7fbd0c89133ab357fcf --- /dev/null +++ b/rmscript/README.md @@ -0,0 +1,86 @@ +# rmscript + +A kid-friendly robot programming language for Reachy Mini. + +## Overview + +rmscript is a simple, Python-like domain-specific language (DSL) designed to make robot programming accessible to children and beginners. It compiles to an intermediate representation (IR) that can be executed by different adapters (queue-based execution, WebSocket streaming, etc.). + +## Installation + +```bash +pip install rmscript +``` + +With optional dependencies: +```bash +pip install rmscript[reachy] # For reachy_mini integration +pip install rmscript[scipy] # For advanced transformations +``` + +## Quick Start + +```python +from rmscript import compile_script + +# Compile rmscript source +result = compile_script(""" +DESCRIPTION Wave hello +look left +antenna both up +wait 1s +look right +""") + +if result.success: + print(f"Compiled {len(result.ir)} actions") + for action in result.ir: + print(f" - {type(action).__name__}") +else: + for error in result.errors: + print(f"Error: {error}") +``` + +## Language Features + +- **Intuitive syntax**: `look left`, `turn right`, `antenna up` +- **Time control**: `wait 2s`, `slow`, `fast` +- **Qualitative strengths**: `little`, `medium`, `lot`, `maximum` +- **Compound movements**: `look left and up` +- **Loops**: `repeat 3` blocks +- **Sound & pictures**: `play sound`, `picture` + +See the [Language Reference](docs/language_reference.md) for complete syntax. + +## Architecture + +rmscript uses a 5-stage compilation pipeline: + +``` +Source → Lexer → Parser → Semantic Analyzer → Optimizer → IR +``` + +The compiler outputs **Intermediate Representation (IR)**, not executable code. Execution is handled by **adapters** that consume IR in different contexts. + +## For Developers + +### Adapters + +Adapters execute IR in specific contexts. Example: + +```python +from rmscript import compile_file, ExecutionAdapter, ExecutionContext +from dataclasses import dataclass + +@dataclass +class MyContext(ExecutionContext): + robot: Any + +class MyAdapter: + def execute(self, ir, context: MyContext) -> dict: + for action in ir: + # Execute each IR action + if isinstance(action, IRAction): + context.robot.move(action.head_pose) + return {"status": "complete"} +``` \ No newline at end of file diff --git a/rmscript/pyproject.toml b/rmscript/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..dec328b2abba9cc9ee5fa3cd61a9aa7293c8ea55 --- /dev/null +++ b/rmscript/pyproject.toml @@ -0,0 +1,37 @@ +[project] +name = "rmscript" +version = "0.1.0" +description = "A kid-friendly robot programming language for Reachy Mini" +readme = "README.md" +requires-python = ">=3.11" + +dependencies = [ + "numpy>=1.24.0", + "reachy_mini>=1.0.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.0.0", + "pytest-asyncio>=0.21.0", + "ruff>=0.1.0", + "scipy>=1.10.0", # For testing rotation matrices +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.ruff] +line-length = 100 +target-version = "py311" + +[tool.ruff.lint] +select = ["E", "F", "I", "N", "W"] +ignore = [] + +[tool.pytest.ini_options] +testpaths = ["tests"] +python_files = ["test_*.py"] +python_classes = ["Test*"] +python_functions = ["test_*"] diff --git a/rmscript/rmscript_reference_doc.md b/rmscript/rmscript_reference_doc.md new file mode 100644 index 0000000000000000000000000000000000000000..e7ea53879237df00164e841450a26a494b0c7d7a --- /dev/null +++ b/rmscript/rmscript_reference_doc.md @@ -0,0 +1,1021 @@ +# rmscript - Kid-Friendly Robot Programming + +rmscript is a natural language-inspired programming language designed to make robot programming accessible and fun for children. It compiles to Python code that controls the Reachy Mini robot. + +## Example Usage + +Create a file `hello.rmscript`: + +```rmscript +DESCRIPTION Wave hello to someone +antenna up +wait 1s +antenna down +look left +look right +look center +``` + +Test the script using the provided runner (after starting the reachy-mini-daemon): + +``` +python src/reachy_mini_conversation_app/rmscript/run_rmscript.py path/to/hello.rmscript +``` + + +## Language Syntax + +### File Structure + +Every rmscript file has a simple structure: + +```rmscript +DESCRIPTION Wave hello to someone +# Your commands here +look left +wait 1s +``` + +**Key features:** +- **Tool name**: Automatically derived from the filename (e.g., `wave_hello.rmscript` → tool name is `wave_hello`) +- **DESCRIPTION** (optional): One-line description used for LLM tool registration + +### Basic Commands + +```rmscript +# Comments start with # + +# Movement commands +look left +turn right +antenna up +head forward 10 + +# Wait command +wait 2s +wait 0.5s + +# Camera command +picture + +# Sound playback +play mysound +play othersound pause +``` + +### Case Insensitivity + +rmscript is case-insensitive for keywords: + +```rmscript +LOOK left # Same as "look left" +Look Left # Same as "look left" +WAIT 1s # Same as "wait 1s" +``` + +## Movement Commands + +### Look (Head Orientation) + +Control the robot's head orientation (pitch and yaw): + +```rmscript +look left # Turn head left (30° default) +look right 45 # Turn head right 45° +look up # Tilt head up (30° default) +look down 20 # Tilt head down 20° +look center # Return to center position + +# Synonyms +look straight # Same as center +look neutral # Same as center +``` + +**Physical Limits:** +- Pitch (up/down): ±40° +- Yaw (left/right): ±180° absolute, ±65° relative to body + +### Turn (Body Rotation) + +Rotate the robot's body (the head rotates together with the body): + +```rmscript +turn left # Rotate body and head left (30° default) +turn right 90 # Rotate body and head right 90° +turn center # Face forward +``` + +**Note:** The `turn` command rotates both the body yaw and the head yaw together, since the body carries the head. + +**Physical Limits:** +- Body yaw: ±160° (safe range) + +### Antenna + +Control the antenna positions using multiple syntaxes: + +**Clock Position (Numeric 0-12):** +```rmscript +antenna both 0 # 0 o'clock = 0° (straight up) +antenna both 3 # 3 o'clock = 90° (external/right) +antenna both 6 # 6 o'clock = 180° (straight down) +antenna both 9 # 9 o'clock = -90° (internal/left) +antenna left 4.5 # Left antenna to 4.5 o'clock (135°) +``` + +**Clock Keywords:** +```rmscript +antenna both high # 0° (high position) +antenna both ext # 90° (external) +antenna both low # 180° (low position) +antenna both int # -90° (internal) +``` + +**Directional Keywords (Natural Language):** +```rmscript +antenna both up # 0° (up) +antenna both right # 90° (right/external) +antenna both down # 180° (down) +antenna both left # -90° (left/internal) + +# Individual antenna control +antenna left up # Left antenna pointing up +antenna right down # Right antenna pointing down + +# Even in potentially confusing cases, it works naturally: +antenna left left # Left antenna pointing left (-90°) +antenna right right # Right antenna pointing right (90°) +``` + +**Physical Limits:** +- Antenna angle: ±180° (safe recommended: ±120°) + +### Head Translation + +Move the head forward/back/left/right/up/down in space: + +```rmscript +head forward 10 # Move head forward 10mm +head back 5 # Move head back 5mm +head backward 5 # Same as "back" (synonym) +head backwards 5 # Same as "back" (synonym) +head left 8 # Move head left 8mm +head right 8 # Move head right 8mm +head up 5 # Move head up 5mm +head down 3 # Move head down 3mm +``` + +**Physical Limits:** +- X (forward/back): ±50mm typical +- Y (left/right): ±50mm typical +- Z (up/down): +20mm / -30mm typical + +### Tilt (Head Roll) + +Tilt the head side-to-side: + +```rmscript +tilt left 15 # Tilt head left +tilt right 15 # Tilt head right +tilt center # Return to level +``` + +**Physical Limits:** +- Roll: ±40° + +### Wait + +Pause between movements: + +```rmscript +wait 1s # Wait 1 second +wait 0.5s # Wait 0.5 seconds +wait 2.5s # Wait 2.5 seconds +``` + +**Important:** The `s` suffix is **required** for consistency. `wait 1` will produce a compilation error. + +### Picture + +Take a picture with the robot's camera and add it to the conversation: + +```rmscript +picture # Take a picture +``` + +The picture command captures a frame from the camera and returns it as a base64-encoded image. + +**How it works:** + +1. **During execution**: The `picture` command is queued as a movement (instant duration: 0.01s) +2. **Capture timing**: Picture is captured at the right moment in the movement sequence +3. **File storage**: Pictures are automatically saved to `/tmp/reachy_picture_YYYYMMDD_HHMMSS_microseconds.jpg` +4. **Color handling**: Images are captured in RGB format with proper color conversion +5. **LLM integration**: When called by the LLM, pictures are automatically added to the conversation + +**Single picture (LLM-compatible):** +```rmscript +DESCRIPTION Check behind by taking a picture +turn left maximum +wait 0.5s +picture +wait 0.5s +turn center +``` + +This script: +- Turns the robot to look behind (120° left) +- Waits for movement to stabilize +- Captures a picture at the right moment +- Returns to center position +- The LLM receives the picture and can describe what it sees + +**Important timing notes:** +- Add `wait` commands before `picture` to let movements complete +- The tool automatically waits for all movements + picture capture before returning +- Pictures are captured when the movement queue reaches them (not immediately) + +**Multiple pictures:** +```rmscript +DESCRIPTION Look around and take pictures +look left +wait 0.5s +picture +look right +wait 0.5s +picture +look center +``` + +Each `picture` command captures a separate image. For single-picture scripts, the image is returned in Camera-compatible format (`b64_im`) for LLM integration. For multi-picture scripts, images are returned as an array. + +**Use with `run_rmscript.py`:** + +When testing scripts with `run_rmscript.py`, pictures are: +- Saved to `/tmp` with timestamped filenames +- Logged with full paths for easy access +- Displayed in the execution summary + +**Use with LLM conversation:** + +When called as a tool by the LLM: +- Single picture: Automatically fed to the LLM conversation (like Camera tool) +- Multiple pictures: Available as base64 data (future enhancement for multi-image display) +- Gradio UI: Picture thumbnails displayed in the conversation interface + +**Example conversation:** +``` +User: "Can you check what's behind you?" +→ LLM calls: check_behind() +→ Robot: turns, captures picture, returns to center +→ LLM sees the picture and responds: "I can see a desk with a laptop and some books!" +``` + +### Play Sound + +Play sound files (.wav, .mp3, .ogg, .flac) during script execution: + +```rmscript +play soundname # Play sound in background (async, continues immediately) +play soundname pause # Wait for sound to finish before continuing (blocking) +play soundname 5s # Play sound for exactly 5 seconds (blocking) +``` + +The script automatically searches for sound files in this order: +1. **Directory containing the .rmscript file** (highest priority - co-located sounds) +2. Current working directory +3. `sounds/` subdirectory + +**Asynchronous playback (default):** +```rmscript +play intro # Starts playing, script continues immediately +look left +wait 1s +``` +The sound plays in the background while movements execute. + +**Blocking playback (wait for sound to finish):** +```rmscript +play mysound pause # Waits for sound to finish +# OR use synonyms: +play mysound fully +play mysound wait +play mysound block +play mysound complete +``` + +The script pauses until the sound finishes playing, then continues. + +**Duration-limited playback:** +```rmscript +play mysound 10s # Play sound for exactly 10 seconds (blocks for 10s) +``` + +Plays the sound for the specified duration. If the sound is shorter, it will finish early. If longer, it will be cut off. + +### Loop Sound + +Loop a sound file repeatedly for a specified duration: + +```rmscript +loop soundname # Loop sound for 10 seconds (default) +loop soundname 5s # Loop sound for 5 seconds +loop soundname 30s # Loop sound for 30 seconds +``` + +The loop command automatically repeats the sound until the duration expires. This is useful for background music or ambient sounds. + +**Example use case:** +```rmscript +DESCRIPTION Greet with sound and movement +play hello pause # Play greeting sound fully +wait 0.5s +antenna both up # Wave antennas +wait 1s +antenna both down +``` + +**Sound files:** +- File extensions: `.wav`, `.mp3`, `.ogg`, `.flac` +- Example: `play hello` looks for `hello.wav`, `hello.mp3`, etc. +- **Best practice**: Place sound files in the same directory as your .rmscript file +- Alternative locations: working directory or `sounds/` subdirectory + +## Advanced Features + +### Keyword Reuse with `and` + +Chain multiple directions with the same action keyword: + +```rmscript +# Reuse "look" keyword +look left and up 25 +# → Equivalent to: look left + look up 25 +# → Merged into single command + +# Different keywords - no reuse +turn left and look right +# → turn left + look right +# → Two separate commands merged +``` + +This creates more natural, flowing descriptions while optimizing execution. + +### Qualitative Strength + +Use descriptive words instead of numbers - works for both angles and distances: + +```rmscript +# 5 levels of strength - values are context-aware! + +# Examples: +turn left tiny # 10° (body yaw can handle larger movements) +look up tiny # 5° (head pitch limited by cone constraint) +head forward tiny # 2mm + +turn left maximum # 120° (body yaw safe maximum) +look up maximum # 38° (respects ±40° pitch limit) +look left maximum # 60° (respects ±65° body-head differential) +head forward maximum # 28mm (under 30mm limit) +``` + +**Available Qualitative Keywords:** +- **VERY_SMALL**: minuscule, mini, verysmall, tiny +- **SMALL**: little, slightly, small, alittle +- **MEDIUM**: medium, normal, regular, standard, normally +- **LARGE**: lot, big, large, very, alot, huge, strong, strongly +- **VERY_LARGE**: verybig, enormous, verylarge, maximum + +**Context-Aware Values:** + +The same qualitative keyword maps to different values depending on the movement type, respecting physical limits: + +| Keyword | VERY_SMALL | SMALL | MEDIUM | LARGE | VERY_LARGE | +|---------|------------|-------|--------|-------|------------| +| **Body Yaw (turn)** | 10° | 30° | 60° | 90° | 120° | +| **Head Pitch/Roll (look up/down, tilt)** | 5° | 10° | 20° | 30° | 38° | +| **Head Yaw (look left/right)** | 5° | 15° | 30° | 45° | 60° | +| **Head Translation (head forward/back/etc)** | 2mm | 5mm | 10mm | 20mm | 28mm | +| **Antennas** | 10° | 30° | 60° | 90° | 110° | + +**Note:** These values are carefully chosen to stay within the robot's physical limits while maximizing safe range of motion. + +### Duration Keywords + +Use descriptive speed words: + +```rmscript +look left superfast # 0.2 seconds +look right fast # 0.5 seconds +look up slow # 2.0 seconds +look up slowly # 2.0 seconds (synonym for slow) +look down superslow # 3.0 seconds +``` + +Combine with 'and': + +```rmscript +turn left and look right fast +# Both movements complete in 0.5 seconds +``` + +### Repeat Blocks + +Repeat a sequence of commands: + +```rmscript +repeat 3 + look left + wait 0.5s + look right + wait 0.5s + +# Nested repeat blocks work too +repeat 2 + antenna up + repeat 3 + look left + look right + antenna down +``` + +**Indentation:** Use spaces or tabs consistently (tabs = 4 spaces). + +### Combining Movements + +Combine multiple movements into a single smooth motion: + +```rmscript +# All happen simultaneously +antenna both up and look up 25 and turn left 30 +``` + +This merges into a single `goto_target()` call with all parameters. + +**Important:** The `and` keyword can only combine movement commands (turn, look, head, tilt, antenna). You **cannot** combine movements with control commands (picture, play, loop, wait) using `and`. Use separate lines instead: + +```rmscript +# ❌ ERROR - Cannot combine movement with picture +look left and picture + +# ✓ CORRECT - Use separate lines +look left +wait 0.5s +picture + +# ❌ ERROR - Cannot combine movement with play +turn right and play mysound + +# ✓ CORRECT - Use separate lines +turn right +play mysound +``` + +## Compiler Architecture + +### Overview + +The compiler uses a 5-stage pipeline: + +``` +Source Code → Lexer → Parser → Semantic Analyzer → Optimizer → Code Generator +``` + +### Stage 1: Lexer (Tokenization) + +Converts source text into tokens with indentation tracking: + +```python +from reachy_mini.rmscript.lexer import Lexer + +source = "look left\nwait 1s" +lexer = Lexer(source) +tokens = lexer.tokenize() +# → [Token(KEYWORD_LOOK, 'look', L1:C1), Token(DIRECTION, 'left', L1:C6), ...] +``` + +Features: +- Python-like INDENT/DEDENT tokens +- Case-insensitive keyword matching +- Comment stripping +- Line/column tracking for error messages + +### Stage 2: Parser (AST Construction) + +Builds an Abstract Syntax Tree from tokens: + +```python +from reachy_mini.rmscript.parser import Parser + +ast = Parser(tokens).parse() +# → Program(tool_name='...', description='...', statements=[...]) +``` + +Features: +- Keyword reuse detection for `and` chains +- Direction validation per keyword +- Repeat block nesting +- Syntax error reporting + +### Stage 3: Semantic Analyzer + +Applies defaults, validates ranges, and generates IR: + +```python +from reachy_mini.rmscript.semantic import SemanticAnalyzer + +ir, errors, warnings = SemanticAnalyzer().analyze(ast) +# → List[Action | WaitAction], List[CompilationError], List[CompilationError] +``` + +Features: +- Default value resolution (30° for angles, 1s for duration) +- Qualitative → quantitative conversion +- Duration keyword mapping +- Physical limit validation +- Action merging (multiple SingleActions → one Action) + +### Stage 4: Optimizer + +Optimizes the IR: + +```python +from reachy_mini.rmscript.optimizer import Optimizer + +optimized_ir = Optimizer().optimize(ir) +``` + +Features: +- Consecutive wait merging +- No-op action removal + +### Stage 5: Code Generator + +Creates executable Python functions: + +```python +from reachy_mini.rmscript.codegen import CodeGenerator + +executable = CodeGenerator().generate(tool_name, description, ir) +# → Callable that executes the behavior +``` + +Features: +- Direct execution: `executable(mini)` +- Readable code generation: `to_python_code()` +- Proper imports and function signatures + +## API Reference + +### rmscriptCompiler + +Main compiler class. + +```python +from reachy_mini.rmscript import rmscriptCompiler + +compiler = rmscriptCompiler(log_level="INFO") +tool = compiler.compile(source_code) +``` + +**Parameters:** +- `log_level` (str): Logging level - "DEBUG", "INFO", "WARNING", "ERROR" + +**Returns:** +- `CompiledTool`: Compilation result object + +### verify_rmscript + +Verification function that checks if rmscript code compiles without generating executable code. + +```python +from reachy_mini_conversation_app.rmscript import verify_rmscript + +is_valid, errors = verify_rmscript(source_code) +if not is_valid: + for error in errors: + print(error) +``` + +**Parameters:** +- `source_code` (str): rmscript source code to verify + +**Returns:** +- `tuple[bool, list[str]]`: Tuple of (is_valid, error_messages) + - `is_valid`: True if compilation succeeds, False otherwise + - `error_messages`: List of error and warning messages (empty if valid) + +**Example:** + +```python +script = """ +DESCRIPTION Test script +look left and picture +""" + +is_valid, errors = verify_rmscript(script) +# is_valid = False +# errors = ["❌ Line 3: Cannot combine movement with 'picture' using 'and'. Use separate lines instead."] +``` + +### CompiledTool + +Result of compilation. + +```python +class CompiledTool: + name: str # Tool name + description: str # Tool description + executable: Callable # Function to execute on robot + success: bool # Compilation succeeded? + errors: List[CompilationError] # Compilation errors + warnings: List[CompilationError] # Compilation warnings + source_code: str # Original source + ir: List[Action | WaitAction] # Intermediate representation + + def execute(self, mini: ReachyMini) -> None: + """Execute the compiled behavior on the robot.""" + + def to_python_code(self) -> str: + """Generate readable Python code.""" +``` + +**Usage:** + +```python +if tool.success: + # Execute on robot + with ReachyMini() as mini: + tool.execute(mini) + + # Or get Python code + print(tool.to_python_code()) +else: + # Handle errors + for error in tool.errors: + print(f"{error.severity} Line {error.line}: {error.message}") +``` + +### CompilationError + +Error or warning from compilation. + +```python +@dataclass +class CompilationError: + line: int # Line number (1-indexed) + column: int # Column number (1-indexed) + message: str # Error/warning message + severity: str # "ERROR" or "WARNING" +``` + +### Action (IR) + +Intermediate representation of a movement. + +```python +@dataclass +class Action: + head_pose: Optional[np.ndarray] # 4x4 transformation matrix + antennas: Optional[np.ndarray] # [left, right] angles in radians + body_yaw: Optional[float] # Body rotation in radians + duration: float # Movement duration in seconds + interpolation: str # "minjerk", "linear", "ease", "cartoon" +``` + +### WaitAction (IR) + +Intermediate representation of a wait/pause. + +```python +@dataclass +class WaitAction: + duration: float # Wait duration in seconds +``` + +## Examples + +### Example 1: Simple Greeting + +```rmscript + +DESCRIPTION Greet someone warmly +# Wave with antennas +antenna up +wait 0.5s +antenna down +wait 0.5s + +# Nod +look down 20 +wait 0.3s +look up 20 +wait 0.3s +look center +``` + +### Example 2: Search Pattern + +```rmscript + +DESCRIPTION Look around to search for something +# Scan left to right +look left 45 +wait 1s +look center +wait 0.5s +look right 45 +wait 1s +look center + +# Check up and down +look up 30 +wait 0.5s +look down 30 +wait 0.5s +look center +``` + +### Example 3: Dance Choreography + +```rmscript + +DESCRIPTION Perform a fun dance routine +# Opening pose +antenna both up and look up 25 +wait 1s + +# Main sequence +repeat 2 + # Move left + turn left 30 and look right 20 + wait 0.5s + + # Move right + turn right 30 and look left 20 + wait 0.5s + +# Ending pose +turn center and look center and antenna down +``` + +### Example 4: Using Qualitative Strength + +```rmscript + +DESCRIPTION Wave shyly at someone +# Small movements +look down slightly +antenna left up a little +wait 1s +antenna left down +look center +``` + +### Example 5: Complex Combination + +```rmscript + +DESCRIPTION Show excitement when greeting +# Quick movements +repeat 3 + antenna both up superfast + antenna both down superfast + +# Energetic looking around +look left and up fast +wait 0.2s +look right and up fast +wait 0.2s +look center slow +``` + +## Error Handling + +### Compilation Errors + +Errors prevent code generation: + +```rmscript +# Invalid keyword +jump up +``` +**Output:** `❌ Line 1: Unexpected token: 'jump'` + +```rmscript +# Invalid direction for keyword +turn up +``` +**Output:** `❌ Line 1: Invalid direction 'up' for keyword 'turn'` + +```rmscript +# Missing indentation +repeat 3 +look left +``` +**Output:** `❌ Line 2: Expected indented block after 'repeat'` + +### Compilation Warnings + +Warnings allow compilation but alert to potential issues: + +```rmscript +# Exceeds safe range +turn left 200 +``` +**Output:** `⚠️ Line 1: Body yaw 200.0° exceeds safe range (±160.0°), will be clamped` + +```rmscript +# Exceeds physical limit +look up 50 +``` +**Output:** `⚠️ Line 1: Head pitch 50.0° exceeds limit (±40.0°), will be clamped` + +### Handling Errors in Code + +```python +tool = compiler.compile(source) + +if not tool.success: + print("Compilation failed!") + for error in tool.errors: + print(f" ❌ Line {error.line}: {error.message}") + exit(1) + +if tool.warnings: + print("Compilation succeeded with warnings:") + for warning in tool.warnings: + print(f" ⚠️ Line {warning.line}: {warning.message}") + +# Safe to execute +tool.execute(mini) +``` + +## Tips and Best Practices + +### 1. Use Comments + +```rmscript +# Good: explain what you're doing +# Opening sequence: get attention +antenna up +wait 1s + +# Main behavior: scan the room +look left 45 +wait 1s +look right 45 +``` + +### 2. Use Descriptive Tool Names + +```python +# Good + + + + +# Avoid + + + +``` + +### 3. Break Complex Behaviors into Steps + +```rmscript +# Good: readable steps +antenna up +wait 1s +look left +wait 0.5s +look right +wait 0.5s +look center + +# Avoid: too compressed +antenna up and look left and wait 1s and look right +``` + +### 4. Use Repeat for Patterns + +```rmscript +# Good: use repeat +repeat 3 + antenna up + antenna down + +# Avoid: repetitive +antenna up +antenna down +antenna up +antenna down +antenna up +antenna down +``` + +### 5. Test with Small Values First + +```rmscript +# Start conservative +look left 10 +turn right 15 + +# Then increase if needed +look left 45 +turn right 90 +``` + +## Physical Safety Limits + +rmscript validates all movements against these limits: + +| Movement | Limit | Warning Threshold | +|----------|-------|------------------| +| Body yaw (turn) | ±180° | ±160° | +| Head yaw (look left/right) | ±180° absolute | ±65° relative to body | +| Head pitch (look up/down) | ±40° | ±40° | +| Head roll (tilt) | ±40° | ±40° | +| Antenna | ±90° | ±65° | +| Head X (forward/back) | ±50mm typical | - | +| Head Y (left/right) | ±50mm typical | - | +| Head Z (up/down) | +20mm / -30mm typical | - | + +Exceeding these limits generates **warnings** but still compiles. The robot's hardware will clamp values to safe ranges. + +## Default Values + +When values aren't specified: + +| Parameter | Default | +|-----------|---------| +| Angle (look, turn, tilt) | 30° | +| Distance (head translation) | 10mm | +| Antenna angle | 45° | +| Duration | 1.0s | + +**Qualitative Strength Values:** + +| Level | Keywords | Angle | Distance | +|-------|----------|-------|----------| +| VERY_SMALL | tiny, minuscule, mini, verysmall | 5° | 2mm | +| SMALL | little, slightly, small, alittle | 15° | 5mm | +| MEDIUM | medium, normal, regular, standard, normally | 30° | 10mm | +| LARGE | strong, lot, big, large, very, alot, huge, strongly | 45° | 20mm | +| VERY_LARGE | enormous, verybig, verylarge, maximum | 60° | 30mm | + +## Troubleshooting + +### Issue: "Inconsistent indentation" + +**Cause:** Mixing tabs and spaces, or inconsistent indentation levels. + +**Solution:** Use only spaces or only tabs (not mixed). Ensure nested blocks are indented consistently. + +```rmscript +# Bad: mixed tabs and spaces +repeat 3 + look left # 4 spaces +→ look right # 1 tab (shows as →) + +# Good: consistent spaces +repeat 3 + look left # 4 spaces + look right # 4 spaces +``` + +### Issue: "Expected indented block after 'repeat'" + +**Cause:** No indentation after `repeat`. + +**Solution:** Indent the repeat block body. + +```rmscript +# Bad +repeat 3 +look left + +# Good +repeat 3 + look left +``` + +### Issue: Generated code has unexpected angles + +**Cause:** Sign convention confusion (left/right). + +**Solution:** Remember: `left` = positive yaw, `right` = negative yaw in the generated code. `up` = negative pitch, `down` = positive pitch. This matches the robot's actual coordinate system. + + +## Contributing + +To extend rmscript: + +1. **Add new keywords**: Update `lexer.py`, `parser.py`, and `semantic.py` +2. **Add new features**: Modify the appropriate compiler stage +3. **Add tests**: Create integration tests in `tests/test_rmscript/` +4. **Update docs**: Keep this README and examples current + +## License + +Same as Reachy Mini SDK. diff --git a/rmscript/src/rmscript/__init__.py b/rmscript/src/rmscript/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..87a5181531eea4bc3338cb06ff7c329b7c054409 --- /dev/null +++ b/rmscript/src/rmscript/__init__.py @@ -0,0 +1,32 @@ +"""rmscript: A kid-friendly robot programming language for Reachy Mini.""" + +from rmscript.compiler import RMScriptCompiler, compile_script, compile_file, verify_script +from rmscript.ir import ( + CompilationResult, + CompilationError, + IRAction, + IRWaitAction, + IRPictureAction, + IRPlaySoundAction, +) +from rmscript.adapters import ExecutionAdapter, ExecutionContext + +__version__ = "0.1.0" + +__all__ = [ + # Compiler + "RMScriptCompiler", + "compile_script", + "compile_file", + "verify_script", + # IR types + "CompilationResult", + "CompilationError", + "IRAction", + "IRWaitAction", + "IRPictureAction", + "IRPlaySoundAction", + # Adapter protocol + "ExecutionAdapter", + "ExecutionContext", +] diff --git a/rmscript/src/rmscript/adapters/__init__.py b/rmscript/src/rmscript/adapters/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7cd2e4aace6a85914305192ec8ecb721212e6072 --- /dev/null +++ b/rmscript/src/rmscript/adapters/__init__.py @@ -0,0 +1,5 @@ +"""Execution adapters for rmscript.""" + +from rmscript.adapters.base import ExecutionAdapter, ExecutionContext + +__all__ = ["ExecutionAdapter", "ExecutionContext"] diff --git a/rmscript/src/rmscript/adapters/base.py b/rmscript/src/rmscript/adapters/base.py new file mode 100644 index 0000000000000000000000000000000000000000..689a98238994e664af135daf5629ec7973ec7d8c --- /dev/null +++ b/rmscript/src/rmscript/adapters/base.py @@ -0,0 +1,42 @@ +"""Base adapter protocol for executing rmscript IR.""" + +from typing import Protocol, Any, Dict, List, Optional +from dataclasses import dataclass + +from rmscript.ir import IRAction, IRWaitAction, IRPictureAction, IRPlaySoundAction + + +@dataclass +class ExecutionContext: + """Base context for all adapters.""" + + script_name: str + script_description: str + source_file_path: Optional[str] = None + + +class ExecutionAdapter(Protocol): + """Protocol for execution adapters. + + Adapters consume IR and execute it in adapter-specific ways. + Examples: + - QueueExecutionAdapter: Converts IR to movement queue for robot execution + - WebSocketExecutionAdapter: Streams pose parameters over WebSocket + - SimulationAdapter: Runs IR in a simulation environment + """ + + def execute( + self, + ir: List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction], + context: ExecutionContext, + ) -> Dict[str, Any]: + """Execute IR in adapter-specific way. + + Args: + ir: List of IR actions to execute + context: Execution context with metadata + + Returns: + Dictionary with execution results (adapter-specific format) + """ + ... diff --git a/rmscript/src/rmscript/ast_nodes.py b/rmscript/src/rmscript/ast_nodes.py new file mode 100644 index 0000000000000000000000000000000000000000..3263d6196915ae351480e91dbd36d653eed92a6d --- /dev/null +++ b/rmscript/src/rmscript/ast_nodes.py @@ -0,0 +1,96 @@ +"""Abstract Syntax Tree node definitions for ReachyMiniScript.""" + +from typing import List, Optional +from dataclasses import dataclass + + +@dataclass +class ASTNode: + """Base class for all AST nodes.""" + + line: int = 0 + column: int = 0 + + +@dataclass +class Program(ASTNode): + """Root node of the AST.""" + + tool_name: str = "" + description: str = "" + statements: List["Statement"] = None # type: ignore + + def __post_init__(self) -> None: + """Initialize mutable defaults.""" + if self.statements is None: + self.statements = [] + + +@dataclass +class Statement(ASTNode): + """Base class for statements.""" + + pass + + +@dataclass +class ActionChain(Statement): + """Chain of actions connected by 'and' keyword.""" + + actions: List["SingleAction"] = None # type: ignore + + def __post_init__(self) -> None: + """Initialize mutable defaults.""" + if self.actions is None: + self.actions = [] + + +@dataclass +class SingleAction(ASTNode): + """Single action (may be part of a chain).""" + + keyword: str = "" # turn, look, head, tilt, antenna + direction: Optional[str] = None # left, right, up, down, etc. + antenna_modifier: Optional[str] = None # left, right, both (for antenna only) + strength: Optional[float] = None # Numerical value (degrees or mm) + strength_qualitative: Optional[str] = None # little, lot, etc. + duration: Optional[float] = None # seconds + duration_keyword: Optional[str] = None # fast, slow, etc. + + +@dataclass +class RepeatBlock(Statement): + """Repeat block with nested statements.""" + + count: int = 0 + body: List[Statement] = None # type: ignore + + def __post_init__(self) -> None: + """Initialize mutable defaults.""" + if self.body is None: + self.body = [] + + +@dataclass +class WaitStatement(Statement): + """Wait/pause statement.""" + + duration: Optional[float] = None + duration_keyword: Optional[str] = None + + +@dataclass +class PictureStatement(Statement): + """Take a picture statement.""" + + pass + + +@dataclass +class PlaySoundStatement(Statement): + """Play a sound statement.""" + + sound_name: str = "" # Name of the sound file (without extension) + blocking: bool = False # True = wait for sound to finish + loop: bool = False # True = loop the sound + duration: Optional[float] = None # Duration for looping (or limited playback) diff --git a/rmscript/src/rmscript/compiler.py b/rmscript/src/rmscript/compiler.py new file mode 100644 index 0000000000000000000000000000000000000000..8308294a862467fb090538f1f89fa490d6cb32f9 --- /dev/null +++ b/rmscript/src/rmscript/compiler.py @@ -0,0 +1,202 @@ +"""Main ReachyMiniScript compiler - orchestrates lexing, parsing, semantic analysis, and optimization.""" + +import logging +from pathlib import Path + +from rmscript.lexer import Lexer +from rmscript.ir import CompilationResult, CompilationError +from rmscript.parser import Parser, ParseError +from rmscript.semantic import SemanticAnalyzer +from rmscript.optimizer import Optimizer + + +class RMScriptCompiler: + """Compiler for ReachyMiniScript language.""" + + def __init__(self, log_level: str = "WARNING"): + """Initialize compiler.""" + self.logger = logging.getLogger(__name__) + self.logger.setLevel(log_level) + + def compile(self, source: str) -> CompilationResult: + """Compile ReachyMiniScript source code into intermediate representation.""" + result = CompilationResult( + name="", + description="", + source_code=source, + ) + + try: + # Stage 1: Lexical Analysis + self.logger.info("Stage 1: Lexical analysis...") + lexer = Lexer(source) + tokens = lexer.tokenize() + self.logger.debug(f"Generated {len(tokens)} tokens") + + # Stage 2: Parsing + self.logger.info("Stage 2: Parsing...") + parser = Parser(tokens) + ast = parser.parse() + + # Use tool_name from AST, or default to "rmscript_tool" if empty + result.name = ast.tool_name if ast.tool_name else "rmscript_tool" + result.description = ast.description + + self.logger.debug(f"Parsed tool '{result.name}'") + + # Stage 3: Semantic Analysis + self.logger.info("Stage 3: Semantic analysis...") + analyzer = SemanticAnalyzer() + ir = analyzer.analyze(ast) + + result.ir = ir + result.errors.extend(analyzer.errors) + result.warnings.extend(analyzer.warnings) + + if result.errors: + self.logger.error( + f"Compilation failed with {len(result.errors)} error(s)" + ) + result.success = False + return result + + self.logger.debug(f"Generated {len(ir)} IR actions") + + # Stage 4: Optimization + self.logger.info("Stage 4: Optimization...") + optimizer = Optimizer() + optimized_ir = optimizer.optimize(ir) + + result.ir = optimized_ir + self.logger.debug( + f"Optimized to {len(optimized_ir)} actions (from {len(ir)})" + ) + + # Compilation successful + result.success = True + + self.logger.info(f"✓ Successfully compiled tool '{result.name}'") + + # Print warnings if any + if result.warnings: + self.logger.warning( + f"Compilation succeeded with {len(result.warnings)} warning(s)" + ) + + except ParseError as e: + # Parser error + result.success = False + result.errors.append( + CompilationError( + line=e.token.line, column=e.token.column, message=e.message + ) + ) + self.logger.error(f"Parse error: {e}") + + except SyntaxError as e: + # Lexer error + result.success = False + result.errors.append(CompilationError(line=1, column=1, message=str(e))) + self.logger.error(f"Syntax error: {e}") + + except Exception as e: + # Unexpected error + result.success = False + result.errors.append( + CompilationError(line=0, column=0, message=f"Internal error: {e}") + ) + self.logger.exception("Unexpected error during compilation") + + return result + + def compile_file(self, filepath: str) -> CompilationResult: + """Compile a rmscript file. + + The tool name is derived from the filename (without .rmscript extension), + with spaces replaced by underscores. + """ + try: + # Extract tool name from filename + filename = Path(filepath).stem # Remove .rmscript extension + tool_name = filename.replace(" ", "_") # Replace spaces with underscores + + # Read and compile source + with open(filepath, "r") as f: + source = f.read() + + result = self.compile(source) + + # Override tool name with filename (from compile(), name is "rmscript_tool") + if result.name == "rmscript_tool": + result.name = tool_name + + # Store absolute path to source file + result.source_file_path = str(Path(filepath).resolve()) + + return result + except FileNotFoundError: + result = CompilationResult(name="", description="", source_code="") + result.success = False + result.errors.append( + CompilationError( + line=0, column=0, message=f"File not found: {filepath}" + ) + ) + return result + except Exception as e: + result = CompilationResult(name="", description="", source_code="") + result.success = False + result.errors.append( + CompilationError( + line=0, column=0, message=f"Error reading file: {e}" + ) + ) + return result + + +def compile_script(source: str, verbose: bool = False) -> CompilationResult: + """Compile ReachyMiniScript source, convenience function.""" + log_level = "INFO" if verbose else "WARNING" + compiler = RMScriptCompiler(log_level=log_level) + return compiler.compile(source) + + +def compile_file(filepath: str, verbose: bool = False) -> CompilationResult: + """Compile ReachyMiniScript file, convenience function.""" + log_level = "INFO" if verbose else "WARNING" + compiler = RMScriptCompiler(log_level=log_level) + return compiler.compile_file(filepath) + + +def verify_script(source: str) -> tuple[bool, list[str]]: + """Verify ReachyMiniScript source without generating executable code. + + Args: + source: ReachyMiniScript source code to verify + + Returns: + Tuple of (is_valid, error_messages) + - is_valid: True if compilation succeeds, False otherwise + - error_messages: List of error and warning messages (empty if no errors/warnings) + + Example: + >>> is_valid, errors = verify_script("look left\\nwait 1s") + >>> if not is_valid: + ... for error in errors: + ... print(error) + + """ + compiler = RMScriptCompiler(log_level="ERROR") + result = compiler.compile(source) + + error_messages = [] + + # Collect errors + for error in result.errors: + error_messages.append(str(error)) + + # Collect warnings + for warning in result.warnings: + error_messages.append(str(warning)) + + return result.success, error_messages diff --git a/rmscript/src/rmscript/constants.py b/rmscript/src/rmscript/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..df47afee3a25ad1d22870c3df7ce9ac8d1e0c369 --- /dev/null +++ b/rmscript/src/rmscript/constants.py @@ -0,0 +1,158 @@ +"""Constants and default values for ReachyMiniScript.""" + +from typing import Dict, List + + +# Default Strengths +DEFAULT_ANGLE = 30 # degrees (for turn, look, tilt) +DEFAULT_DISTANCE = 10 # mm (for head translation) +DEFAULT_ANTENNA_ANGLE = 45 # degrees + +# Qualitative Strength Mappings - Context-Aware +# Different movement types have different physical limits + +# For BODY YAW (turn command) - can handle larger angles +BODY_YAW_VERY_SMALL = 10 # degrees +BODY_YAW_SMALL = 30 # degrees +BODY_YAW_MEDIUM = 60 # degrees +BODY_YAW_LARGE = 90 # degrees +BODY_YAW_VERY_LARGE = 120 # degrees (safe limit, max is ±160°) + +# For HEAD PITCH/ROLL (look up/down, tilt) - limited by cone constraint +HEAD_PITCH_ROLL_VERY_SMALL = 5 # degrees +HEAD_PITCH_ROLL_SMALL = 10 # degrees +HEAD_PITCH_ROLL_MEDIUM = 20 # degrees +HEAD_PITCH_ROLL_LARGE = 30 # degrees +HEAD_PITCH_ROLL_VERY_LARGE = 38 # degrees (just under ±40° limit) + +# For HEAD YAW (look left/right) - larger range possible +HEAD_YAW_VERY_SMALL = 5 # degrees +HEAD_YAW_SMALL = 15 # degrees +HEAD_YAW_MEDIUM = 30 # degrees +HEAD_YAW_LARGE = 45 # degrees +HEAD_YAW_VERY_LARGE = 60 # degrees (respecting ±65° body-head differential) + +# For ANTENNAS - safe operating range +ANTENNA_VERY_SMALL = 10 # degrees +ANTENNA_SMALL = 30 # degrees +ANTENNA_MEDIUM = 60 # degrees +ANTENNA_LARGE = 90 # degrees +ANTENNA_VERY_LARGE = 110 # degrees (safe limit, under ±120°) + +# For HEAD TRANSLATIONS (distances in mm) +TRANSLATION_VERY_SMALL = 2 # mm +TRANSLATION_SMALL = 5 # mm +TRANSLATION_MEDIUM = 10 # mm +TRANSLATION_LARGE = 20 # mm +TRANSLATION_VERY_LARGE = 28 # mm (just under ±30mm limit) + +# Legacy constants (deprecated - use context-aware versions above) +VERY_SMALL_ANGLE = HEAD_YAW_VERY_SMALL +VERY_SMALL_DISTANCE = TRANSLATION_VERY_SMALL +SMALL_ANGLE = HEAD_YAW_SMALL +SMALL_DISTANCE = TRANSLATION_SMALL +MEDIUM_ANGLE = HEAD_YAW_MEDIUM +MEDIUM_DISTANCE = TRANSLATION_MEDIUM +LARGE_ANGLE = HEAD_YAW_LARGE +LARGE_DISTANCE = TRANSLATION_LARGE +VERY_LARGE_ANGLE = HEAD_YAW_VERY_LARGE +VERY_LARGE_DISTANCE = TRANSLATION_VERY_LARGE + +# Duration Mappings +DEFAULT_DURATION = 1.0 # seconds + +DURATION_KEYWORDS: Dict[str, float] = { + "superfast": 0.2, + "veryfast": 0.2, + "fast": 0.5, + "slow": 2.0, + "slowly": 2.0, + "veryslow": 3.0, + "superslow": 3.0, +} + +# Qualitative keywords +SMALL_KEYWORDS: List[str] = ["little", "slightly", "small", "alittle"] +MEDIUM_KEYWORDS: List[str] = ["medium", "normal", "regular", "standard", "normally"] +LARGE_KEYWORDS: List[str] = ["lot", "big", "large", "very", "alot", "huge", "strong", "strongly"] +VERY_SMALL_KEYWORDS: List[str] = ["minuscule", "mini", "verysmall", "tiny"] +VERY_LARGE_KEYWORDS: List[str] = ["verybig", "enormous","verylarge","maximum"] + +# Direction Synonyms +CENTER_SYNONYMS: List[str] = ["center", "straight", "forward", "neutral"] +INWARD_SYNONYMS: List[str] = ["in", "inside", "inward"] +OUTWARD_SYNONYMS: List[str] = ["out", "outside", "outward"] +BACKWARD_SYNONYMS: List[str] = ["back", "backward", "backwards"] + +# All valid directions (used by lexer for tokenization) +ALL_DIRECTIONS: List[str] = [ + "left", "right", "up", "down", "both" +] + CENTER_SYNONYMS + INWARD_SYNONYMS + OUTWARD_SYNONYMS + BACKWARD_SYNONYMS + +# Physical Limits (from robot constraints) +MAX_BODY_YAW_DEG = 160.0 # degrees +MAX_HEAD_PITCH_DEG = 40.0 # degrees (cone constraint) +MAX_HEAD_ROLL_DEG = 40.0 # degrees (cone constraint) +MAX_HEAD_YAW_DEG = 180.0 # degrees (absolute) +MAX_HEAD_BODY_YAW_DIFF_DEG = 65.0 # degrees (relative constraint) + +MAX_HEAD_TRANSLATION_X_MM = 30.0 # mm +MAX_HEAD_TRANSLATION_Y_MM = 30.0 # mm +MAX_HEAD_TRANSLATION_Z_MM = 40.0 # mm (positive) +MIN_HEAD_TRANSLATION_Z_MM = -20.0 # mm (negative) + +MAX_ANTENNA_ANGLE_DEG = 180.0 # degrees +SAFE_ANTENNA_ANGLE_DEG = 120.0 # recommended maximum for safety + +# Movement Keywords +MOVEMENT_KEYWORDS: List[str] = ["turn", "look", "head", "tilt", "antenna"] + +# Control Keywords +CONTROL_KEYWORDS: List[str] = ["wait", "repeat", "end", "play", "loop", "picture"] + +# Sound Playback Mode Keywords +SOUND_BLOCKING_KEYWORDS: List[str] = ["pause", "fully", "wait", "block", "complete"] + +# Valid Directions per Keyword +TURN_DIRECTIONS: List[str] = ["left", "right"] + CENTER_SYNONYMS +LOOK_DIRECTIONS: List[str] = ["left", "right", "up", "down"] + CENTER_SYNONYMS +HEAD_DIRECTIONS: List[str] = ["forward", "left", "right", "up", "down"] + BACKWARD_SYNONYMS +TILT_DIRECTIONS: List[str] = ["left", "right"] + CENTER_SYNONYMS + +# Antenna movements (OLD SYSTEM - kept for backward compatibility if needed) +ANTENNA_MOVEMENTS: List[str] = ["up", "down"] + INWARD_SYNONYMS + OUTWARD_SYNONYMS +ANTENNA_MODIFIERS: List[str] = ["left", "right", "both"] + +# Antenna clock system (NEW) +ANTENNA_CLOCK_KEYWORDS: Dict[str, float] = { + "high": 0.0, # 0 o'clock = 0° + "ext": 3.0, # 3 o'clock = +90° (external) + "low": 6.0, # 6 o'clock = ±180° + "int": 9.0, # 9 o'clock = -90° (internal) +} + +# Antenna directional keywords (map to clock positions) +ANTENNA_DIRECTION_KEYWORDS: Dict[str, float] = { + "up": 0.0, # Same as high: 0° + "right": 3.0, # Same as ext: +90° (external/right) + "down": 6.0, # Same as low: ±180° + "left": 9.0, # Same as int: -90° (internal/left) +} + +# Direction Sign Conventions (for coordinate system) +# Note: These match the robot's actual coordinate system +# Positive values +POSITIVE_DIRECTIONS = { + "left": "yaw", # Positive yaw (verified from robot) + "down": "pitch", # Positive pitch (verified from robot) + "forward": "x", # Positive X +} + +# Negative values +NEGATIVE_DIRECTIONS = { + "right": "yaw", # Negative yaw (verified from robot) + "up": "pitch", # Negative pitch (verified from robot) + "back": "x", # Negative X + "backward": "x", # Negative X (synonym for back) + "backwards": "x", # Negative X (synonym for back) +} diff --git a/rmscript/src/rmscript/ir.py b/rmscript/src/rmscript/ir.py new file mode 100644 index 0000000000000000000000000000000000000000..e08b8a9da28dbd4cf603052eba11580b812adae7 --- /dev/null +++ b/rmscript/src/rmscript/ir.py @@ -0,0 +1,89 @@ +"""Intermediate representation and compilation result types for ReachyMiniScript.""" + +from typing import List, Literal, Optional +from dataclasses import field, dataclass + +import numpy as np +import numpy.typing as npt + + +@dataclass +class CompilationError: + """Represents a compilation error or warning.""" + + line: int + column: int = 0 + message: str = "" + severity: Literal["error", "warning"] = "error" + + def __str__(self) -> str: + """Format error message for display.""" + icon = "❌" if self.severity == "error" else "⚠️ " + return f"{icon} Line {self.line}: {self.message}" + + +@dataclass +class IRAction: + """Resolved action - all defaults applied, ready to execute.""" + + head_pose: Optional[npt.NDArray[np.float64]] = None # 4x4 matrix + antennas: Optional[List[float]] = None # [right, left] in radians + body_yaw: Optional[float] = None # radians + duration: float = 1.0 + interpolation: str = "minjerk" + + # Metadata for debugging + source_line: int = 0 + original_text: str = "" + + +@dataclass +class IRWaitAction: + """Wait/pause action.""" + + duration: float + source_line: int = 0 + original_text: str = "" + + +@dataclass +class IRPictureAction: + """Take a picture action.""" + + source_line: int = 0 + original_text: str = "" + + +@dataclass +class IRPlaySoundAction: + """Play a sound action.""" + + sound_name: str # Name of the sound file (without extension) + blocking: bool = False # True = wait for sound to finish, False = play in background + loop: bool = False # True = loop the sound + duration: Optional[float] = None # Duration for looping or limited playback + source_line: int = 0 + original_text: str = "" + + +@dataclass +class CompilationResult: + """Result of ReachyMiniScript compilation.""" + + # Tool metadata + name: str + description: str + + # Compilation results + success: bool = False + errors: List[CompilationError] = field(default_factory=list) + warnings: List[CompilationError] = field(default_factory=list) + + # Source code + source_code: str = "" + source_file_path: Optional[str] = None + + # Intermediate representation (IR output) + ir: List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction] = field( + default_factory=list + ) diff --git a/rmscript/src/rmscript/lexer.py b/rmscript/src/rmscript/lexer.py new file mode 100644 index 0000000000000000000000000000000000000000..85bdfc38b270ee4991c84bcea4a3815a4bbdcb23 --- /dev/null +++ b/rmscript/src/rmscript/lexer.py @@ -0,0 +1,323 @@ +"""Lexer for ReachyMiniScript - tokenization and indentation handling.""" + +from enum import Enum, auto +from typing import List, Optional +from dataclasses import dataclass + + +class TokenType(Enum): + """Token types for ReachyMiniScript.""" + + # Keywords + KEYWORD_TURN = auto() + KEYWORD_LOOK = auto() + KEYWORD_HEAD = auto() + KEYWORD_TILT = auto() + KEYWORD_ANTENNA = auto() + KEYWORD_WAIT = auto() + KEYWORD_PICTURE = auto() + KEYWORD_PLAY = auto() + KEYWORD_LOOP = auto() + KEYWORD_REPEAT = auto() + KEYWORD_END = auto() + KEYWORD_DESCRIPTION = auto() + + # Directions + DIRECTION = auto() # left, right, up, down, center, etc. + + # Values + NUMBER = auto() # 30, 2.5 + DURATION = auto() # 2s, 0.5s + DURATION_KEYWORD = auto() # fast, slow, superfast, superslow + QUALITATIVE = auto() # little, lot, etc. + ANTENNA_CLOCK = auto() # high, low, ext, int (clock position keywords) + SOUND_BLOCKING = auto() # pause, fully, wait, block, complete (for sound playback) + + # Operators + AND = auto() # and + + # Structure + INDENT = auto() + DEDENT = auto() + NEWLINE = auto() + EOF = auto() + + # Identifiers + IDENTIFIER = auto() # For tool names and other identifiers + + +@dataclass +class Token: + """Represents a lexical token.""" + + type: TokenType + value: str + line: int + column: int + + def __repr__(self) -> str: + """Turn as string representation for debugging.""" + return f"Token({self.type.name}, {self.value!r}, L{self.line}:C{self.column})" + + +class Lexer: + """Tokenizer for ReachyMiniScript with indentation handling.""" + + def __init__(self, source: str): + """Initialize lexer with source code.""" + self.source = source + self.pos = 0 + self.line = 1 + self.column = 1 + self.tokens: List[Token] = [] + self.indent_stack: List[int] = [0] # Track indentation levels + + # Keywords (case-insensitive) + self.keywords = { + "turn": TokenType.KEYWORD_TURN, + "look": TokenType.KEYWORD_LOOK, + "head": TokenType.KEYWORD_HEAD, + "tilt": TokenType.KEYWORD_TILT, + "antenna": TokenType.KEYWORD_ANTENNA, + "wait": TokenType.KEYWORD_WAIT, + "picture": TokenType.KEYWORD_PICTURE, + "play": TokenType.KEYWORD_PLAY, + "loop": TokenType.KEYWORD_LOOP, + "repeat": TokenType.KEYWORD_REPEAT, + "end": TokenType.KEYWORD_END, + "description": TokenType.KEYWORD_DESCRIPTION, + } + + # Directions - import from constants + from rmscript.constants import ALL_DIRECTIONS + self.directions = set(ALL_DIRECTIONS) + + # Duration keywords - import from constants + from rmscript.constants import DURATION_KEYWORDS + self.duration_keywords = set(DURATION_KEYWORDS.keys()) + + # Qualitative strength - import from constants + from rmscript.constants import ( + LARGE_KEYWORDS, + SMALL_KEYWORDS, + MEDIUM_KEYWORDS, + VERY_LARGE_KEYWORDS, + VERY_SMALL_KEYWORDS, + ) + self.qualitative_keywords = ( + set(SMALL_KEYWORDS) + | set(MEDIUM_KEYWORDS) + | set(LARGE_KEYWORDS) + | set(VERY_SMALL_KEYWORDS) + | set(VERY_LARGE_KEYWORDS) + ) + + # Antenna clock keywords + self.antenna_clock_keywords = {"high", "low", "ext", "int"} + + # Sound blocking keywords (for "play sound pause/fully") + from rmscript.constants import SOUND_BLOCKING_KEYWORDS + self.sound_blocking_keywords = set(SOUND_BLOCKING_KEYWORDS) + + def error(self, message: str) -> Exception: + """Create a lexer error with position information.""" + return SyntaxError(f"Line {self.line}, Column {self.column}: {message}") + + def peek(self, offset: int = 0) -> Optional[str]: + """Peek at character at current position + offset.""" + pos = self.pos + offset + if pos < len(self.source): + return self.source[pos] + return None + + def advance(self) -> Optional[str]: + """Advance position and return current character.""" + if self.pos >= len(self.source): + return None + + char = self.source[self.pos] + self.pos += 1 + + if char == "\n": + self.line += 1 + self.column = 1 + else: + self.column += 1 + + return char + + def skip_whitespace_inline(self) -> None: + """Skip spaces and tabs but not newlines.""" + while self.peek() in (" ", "\t"): + self.advance() + + def skip_comment(self) -> None: + """Skip comment (from # to end of line).""" + if self.peek() == "#": + while self.peek() and self.peek() != "\n": + self.advance() + + def read_number(self) -> Token: + """Read a number token (integer or float).""" + start_col = self.column + num_str = "" + + while (ch := self.peek()) is not None and (ch.isdigit() or ch == "."): + num_str += self.advance() # type: ignore + + # Check if followed by 's' for duration + if self.peek() == "s": + self.advance() + return Token( + TokenType.DURATION, num_str + "s", self.line, start_col + ) # Keep 's' in value + + return Token(TokenType.NUMBER, num_str, self.line, start_col) + + def read_identifier(self) -> Token: + """Read an identifier or keyword.""" + start_col = self.column + ident = "" + + while (ch := self.peek()) is not None and (ch.isalnum() or ch == "_"): + ident += self.advance() # type: ignore + + ident_lower = ident.lower() + + # Check if it's a keyword + if ident_lower in self.keywords: + return Token(self.keywords[ident_lower], ident, self.line, start_col) + + # Check if it's a direction + if ident_lower in self.directions: + return Token(TokenType.DIRECTION, ident_lower, self.line, start_col) + + # Check if it's a duration keyword + if ident_lower in self.duration_keywords: + return Token(TokenType.DURATION_KEYWORD, ident_lower, self.line, start_col) + + # Check if it's a qualitative keyword + if ident_lower in self.qualitative_keywords: + return Token(TokenType.QUALITATIVE, ident_lower, self.line, start_col) + + # Check if it's an antenna clock keyword + if ident_lower in self.antenna_clock_keywords: + return Token(TokenType.ANTENNA_CLOCK, ident_lower, self.line, start_col) + + # Check if it's a sound blocking keyword + if ident_lower in self.sound_blocking_keywords: + return Token(TokenType.SOUND_BLOCKING, ident_lower, self.line, start_col) + + # Check for 'and' + if ident_lower == "and": + return Token(TokenType.AND, ident_lower, self.line, start_col) + + # Otherwise it's a generic identifier + return Token(TokenType.IDENTIFIER, ident, self.line, start_col) + + def handle_indentation(self, indent_level: int) -> List[Token]: + """Generate INDENT/DEDENT tokens based on indentation level.""" + tokens = [] + + if indent_level > self.indent_stack[-1]: + # Indent + self.indent_stack.append(indent_level) + tokens.append(Token(TokenType.INDENT, "", self.line, 1)) + + elif indent_level < self.indent_stack[-1]: + # Dedent (possibly multiple levels) + while self.indent_stack and indent_level < self.indent_stack[-1]: + self.indent_stack.pop() + tokens.append(Token(TokenType.DEDENT, "", self.line, 1)) + + # Check if we dedented to a valid level + if not self.indent_stack or indent_level != self.indent_stack[-1]: + raise self.error(f"Inconsistent indentation (level {indent_level})") + + return tokens + + def tokenize(self) -> List[Token]: + """Tokenize the entire source code.""" + tokens = [] + at_line_start = True + + while self.pos < len(self.source): + # Handle indentation at start of line BEFORE skipping whitespace + if at_line_start: + # Count indentation + indent_level = 0 + temp_pos = self.pos + while temp_pos < len(self.source) and self.source[temp_pos] in ( + " ", + "\t", + ): + if self.source[temp_pos] == " ": + indent_level += 1 + else: # tab + indent_level += 4 # Treat tab as 4 spaces + temp_pos += 1 + + # Check if this is a blank line or comment-only line + if ( + temp_pos >= len(self.source) + or self.source[temp_pos] == "\n" + or self.source[temp_pos] == "#" + ): + # Skip blank/comment lines - consume the line + while self.peek() and self.peek() != "\n": + self.advance() + if self.peek() == "\n": + self.advance() + continue + + # Generate INDENT/DEDENT tokens + indent_tokens = self.handle_indentation(indent_level) + tokens.extend(indent_tokens) + + at_line_start = False + + # Skip inline whitespace + self.skip_whitespace_inline() + + # Skip comments + self.skip_comment() + + # Check for EOF + if self.pos >= len(self.source): + break + + # Handle newlines + if self.peek() == "\n": + self.advance() + tokens.append(Token(TokenType.NEWLINE, "\\n", self.line - 1, 1)) + at_line_start = True + continue + + # Read numbers + if (ch := self.peek()) is not None and ch.isdigit(): + tokens.append(self.read_number()) + continue + + # Read identifiers/keywords + if (ch := self.peek()) is not None and (ch.isalpha() or ch == "_"): + tokens.append(self.read_identifier()) + continue + + # Unknown character + raise self.error(f"Unexpected character: {self.peek()!r}") + + # Close any remaining indentation levels + while len(self.indent_stack) > 1: + self.indent_stack.pop() + tokens.append(Token(TokenType.DEDENT, "", self.line, 1)) + + # Add EOF token + tokens.append(Token(TokenType.EOF, "", self.line, self.column)) + + return tokens + + +def tokenize(source: str) -> List[Token]: + """Tokenize source code, convenience function.""" + lexer = Lexer(source) + return lexer.tokenize() diff --git a/rmscript/src/rmscript/optimizer.py b/rmscript/src/rmscript/optimizer.py new file mode 100644 index 0000000000000000000000000000000000000000..6f90c77c4f147430b4e032b9b5bbdf7c1d31a9ac --- /dev/null +++ b/rmscript/src/rmscript/optimizer.py @@ -0,0 +1,64 @@ +"""Optimizer for ReachyMiniScript - further optimize IR for execution.""" + +from typing import List + +from rmscript.ir import IRAction, IRWaitAction, IRPictureAction, IRPlaySoundAction + + +class Optimizer: + """Optimizes intermediate representation.""" + + def optimize(self, ir: List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction]) -> List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction]: + """Optimize IR. + + Current optimizations: + - Merge consecutive wait actions + - Remove no-op actions + + Future optimizations: + - Combine compatible actions with same duration + - Minimize movement time + """ + optimized: List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction] = [] + + i = 0 + while i < len(ir): + action = ir[i] + + # Merge consecutive waits + if isinstance(action, IRWaitAction): + total_wait = action.duration + j = i + 1 + while j < len(ir): + next_action = ir[j] + if isinstance(next_action, IRWaitAction): + total_wait += next_action.duration + j += 1 + else: + break + + optimized.append( + IRWaitAction( + duration=total_wait, + source_line=action.source_line, + original_text=f"wait {total_wait}s", + ) + ) + i = j + continue + + # Remove no-op actions (no actual movement) + if isinstance(action, IRAction): + if ( + action.head_pose is None + and action.antennas is None + and action.body_yaw is None + ): + # Skip this action - it does nothing + i += 1 + continue + + optimized.append(action) + i += 1 + + return optimized diff --git a/rmscript/src/rmscript/parser.py b/rmscript/src/rmscript/parser.py new file mode 100644 index 0000000000000000000000000000000000000000..80118856be0e9634b153710433d9c4e6a97c7501 --- /dev/null +++ b/rmscript/src/rmscript/parser.py @@ -0,0 +1,441 @@ +"""Parser for ReachyMiniScript - builds Abstract Syntax Tree from tokens.""" + +from typing import List, Optional + +from rmscript.lexer import Token, TokenType +from rmscript.ast_nodes import ( + Program, + Statement, + ActionChain, + RepeatBlock, + SingleAction, + WaitStatement, + PictureStatement, + PlaySoundStatement, +) +from rmscript.constants import ( + HEAD_DIRECTIONS, + LOOK_DIRECTIONS, + TILT_DIRECTIONS, + TURN_DIRECTIONS, + ANTENNA_MODIFIERS, + ANTENNA_DIRECTION_KEYWORDS, +) + + +class ParseError(Exception): + """Parser error with position information.""" + + def __init__(self, message: str, token: Token): + """Initialize parse error.""" + self.message = message + self.token = token + super().__init__(f"Line {token.line}: {message}") + + +class Parser: + """Parser for ReachyMiniScript.""" + + def __init__(self, tokens: List[Token]): + """Initialize parser with token stream.""" + self.tokens = tokens + self.pos = 0 + + def error(self, message: str) -> ParseError: + """Create parse error at current position.""" + return ParseError(message, self.current()) + + def current(self) -> Token: + """Get current token.""" + if self.pos < len(self.tokens): + return self.tokens[self.pos] + return self.tokens[-1] # Return EOF token + + def peek(self, offset: int = 0) -> Token: + """Peek at token at current position + offset.""" + pos = self.pos + offset + if pos < len(self.tokens): + return self.tokens[pos] + return self.tokens[-1] # Return EOF token + + def advance(self) -> Token: + """Consume and return current token.""" + token = self.current() + if self.pos < len(self.tokens) - 1: + self.pos += 1 + return token + + def expect(self, token_type: TokenType) -> Token: + """Consume token of expected type or raise error.""" + token = self.current() + if token.type != token_type: + raise self.error( + f"Expected {token_type.name}, got {token.type.name} ({token.value!r})" + ) + return self.advance() + + def skip_newlines(self) -> None: + """Skip any newline tokens.""" + while self.current().type == TokenType.NEWLINE: + self.advance() + + def parse(self) -> Program: + """Parse entire program.""" + program = Program() + + self.skip_newlines() + + # Parse optional DESCRIPTION header + if self.current().type == TokenType.KEYWORD_DESCRIPTION: + self.advance() # Skip DESCRIPTION keyword + + # Read the rest of the line as the description + description_parts = [] + while self.current().type not in (TokenType.NEWLINE, TokenType.EOF): + description_parts.append(self.current().value) + self.advance() + program.description = " ".join(description_parts) + self.skip_newlines() + + # Note: tool_name will be set from filename by the compiler + program.tool_name = "" + + # Parse statements + program.statements = self.parse_statements() + + return program + + def parse_statements(self) -> List[Statement]: + """Parse a list of statements.""" + statements = [] + + while self.current().type not in ( + TokenType.EOF, + TokenType.DEDENT, + TokenType.KEYWORD_END, + ): + self.skip_newlines() + + if self.current().type in ( + TokenType.EOF, + TokenType.DEDENT, + TokenType.KEYWORD_END, + ): + break + + stmt = self.parse_statement() + if stmt: + statements.append(stmt) + + self.skip_newlines() + + return statements + + def parse_statement(self) -> Optional[Statement]: + """Parse a single statement.""" + token = self.current() + + # Check for repeat block + if token.type == TokenType.KEYWORD_REPEAT: + return self.parse_repeat_block() + + # Check for wait command + if token.type == TokenType.KEYWORD_WAIT: + return self.parse_wait() + + # Check for picture command + if token.type == TokenType.KEYWORD_PICTURE: + return self.parse_picture() + + # Check for play command + if token.type == TokenType.KEYWORD_PLAY: + return self.parse_play() + + # Check for loop command + if token.type == TokenType.KEYWORD_LOOP: + return self.parse_loop() + + # Check for movement keywords + if token.type in ( + TokenType.KEYWORD_TURN, + TokenType.KEYWORD_LOOK, + TokenType.KEYWORD_HEAD, + TokenType.KEYWORD_TILT, + TokenType.KEYWORD_ANTENNA, + ): + return self.parse_action_chain() + + # Unknown statement + if token.type != TokenType.NEWLINE: + raise self.error(f"Unexpected token: {token.value!r}") + + return None + + def parse_wait(self) -> WaitStatement: + """Parse wait command.""" + token = self.current() + self.advance() # consume 'wait' + + wait = WaitStatement(line=token.line, column=token.column) + + # Parse duration + if self.current().type == TokenType.DURATION: + duration_str = self.current().value.rstrip("s") + wait.duration = float(duration_str) + self.advance() + elif self.current().type == TokenType.DURATION_KEYWORD: + wait.duration_keyword = self.current().value + self.advance() + elif self.current().type == TokenType.NUMBER: + wait.duration = float(self.current().value) + self.advance() + # Require 's' suffix for consistency + if self.current().value != "s": + raise self.error( + f"Expected 's' after wait duration (e.g., 'wait {wait.duration}s')" + ) + self.advance() + else: + raise self.error("Expected duration after 'wait' (e.g., 'wait 1s')") + + return wait + + def parse_picture(self) -> PictureStatement: + """Parse picture command.""" + token = self.current() + self.advance() # consume 'picture' + + return PictureStatement(line=token.line, column=token.column) + + def parse_play(self) -> PlaySoundStatement: + """Parse play command: 'play soundname', 'play soundname pause', or 'play soundname 10s'.""" + token = self.current() + self.advance() # consume 'play' + + play = PlaySoundStatement(line=token.line, column=token.column) + + # Expect sound name (identifier) + if self.current().type != TokenType.IDENTIFIER: + raise self.error(f"Expected sound name after 'play', got '{self.current().value}'") + + play.sound_name = self.current().value + self.advance() + + # Check for optional duration or blocking modifier + if self.current().type == TokenType.DURATION: + # Duration specified (e.g., "play mysound 10s") + duration_str = self.current().value.rstrip("s") + play.duration = float(duration_str) + play.blocking = True # Duration implies blocking + self.advance() + elif self.current().type == TokenType.SOUND_BLOCKING: + # Blocking modifier (pause, fully, wait, block, complete) + play.blocking = True + self.advance() + + return play + + def parse_loop(self) -> PlaySoundStatement: + """Parse loop command: 'loop soundname' or 'loop soundname 10s'.""" + token = self.current() + self.advance() # consume 'loop' + + play = PlaySoundStatement(line=token.line, column=token.column, loop=True, blocking=True) + + # Expect sound name (identifier) + if self.current().type != TokenType.IDENTIFIER: + raise self.error(f"Expected sound name after 'loop', got '{self.current().value}'") + + play.sound_name = self.current().value + self.advance() + + # Check for optional duration (default to 10s if not specified) + if self.current().type == TokenType.DURATION: + duration_str = self.current().value.rstrip("s") + play.duration = float(duration_str) + self.advance() + else: + # Default duration for loop is 10s + play.duration = 10.0 + + return play + + def parse_repeat_block(self) -> RepeatBlock: + """Parse repeat block.""" + token = self.current() + self.advance() # consume 'repeat' + + # Parse count + if self.current().type != TokenType.NUMBER: + raise self.error("Expected number after 'repeat'") + + count = int(float(self.current().value)) + self.advance() + + self.skip_newlines() + + # Expect indent + if self.current().type != TokenType.INDENT: + raise self.error("Expected indented block after 'repeat'") + self.advance() + + # Parse body + body = self.parse_statements() + + # Expect dedent (this closes the block) + if self.current().type == TokenType.DEDENT: + self.advance() + # Note: 'end' keyword is no longer required - indentation defines the block + + return RepeatBlock(count=count, body=body, line=token.line, column=token.column) + + def parse_action_chain(self) -> ActionChain: + """Parse action chain (one or more actions connected by 'and').""" + chain = ActionChain() + chain.line = self.current().line + chain.column = self.current().column + + # Parse first action + first_action = self.parse_single_action() + chain.actions.append(first_action) + + # Parse additional actions connected by 'and' + while self.current().type == TokenType.AND: + self.advance() # consume 'and' + + # Check if next token is a keyword + next_action = self.parse_single_action( + previous_keyword=first_action.keyword + ) + chain.actions.append(next_action) + + return chain + + def parse_single_action( + self, previous_keyword: Optional[str] = None + ) -> SingleAction: + """Parse a single action. + + Args: + previous_keyword: If provided and no keyword is present, reuse this keyword. + + """ + token = self.current() + action = SingleAction(keyword="", line=token.line, column=token.column) + + # Check if we have a movement keyword + if token.type in ( + TokenType.KEYWORD_TURN, + TokenType.KEYWORD_LOOK, + TokenType.KEYWORD_HEAD, + TokenType.KEYWORD_TILT, + TokenType.KEYWORD_ANTENNA, + ): + action.keyword = token.value.lower() + self.advance() + elif previous_keyword: + # Check if current token is a control keyword (not allowed after 'and') + if token.type in (TokenType.KEYWORD_PICTURE, TokenType.KEYWORD_PLAY, TokenType.KEYWORD_LOOP, TokenType.KEYWORD_WAIT): + raise self.error( + f"Cannot combine movement with '{token.value}' using 'and'. " + f"Use separate lines instead." + ) + # Keyword reuse after 'and' + action.keyword = previous_keyword + else: + raise self.error(f"Expected movement keyword, got {token.value!r}") + + # Parse antenna modifier and clock position if applicable + if action.keyword == "antenna": + # Antenna modifier is now REQUIRED (left, right, both) + if ( + self.current().type == TokenType.DIRECTION + and self.current().value in ANTENNA_MODIFIERS + ): + action.antenna_modifier = self.current().value + self.advance() + else: + raise self.error( + f"Antenna command requires a modifier (left/right/both), got '{self.current().value}'" + ) + + # Now parse clock position (number, clock keyword, or directional keyword) + if self.current().type == TokenType.NUMBER: + # Clock position as number (0-12) + clock_pos = float(self.current().value) + if clock_pos < 0 or clock_pos > 12: + raise self.error( + f"Antenna clock position must be between 0 and 12, got {clock_pos}" + ) + action.strength = clock_pos # Store as strength for now + action.direction = "clock" # Special marker + self.advance() + elif self.current().type == TokenType.ANTENNA_CLOCK: + # Clock keyword (high/low/ext/int) + action.direction = self.current().value # Store keyword + self.advance() + elif ( + self.current().type == TokenType.DIRECTION + and self.current().value in ANTENNA_DIRECTION_KEYWORDS + ): + # Directional keyword (up/down/left/right) + action.direction = self.current().value # Store keyword + self.advance() + else: + raise self.error( + f"Antenna command requires a position (0-12, high/low/ext/int, or up/down/left/right), got '{self.current().value}'" + ) + + # Parse direction for non-antenna keywords + elif self.current().type == TokenType.DIRECTION: + direction = self.current().value + + # Validate direction for keyword + if action.keyword == "turn" and direction not in TURN_DIRECTIONS: + raise self.error( + f"Invalid direction '{direction}' for 'turn' (use left/right/center)" + ) + elif action.keyword == "look" and direction not in LOOK_DIRECTIONS: + raise self.error( + f"Invalid direction '{direction}' for 'look' (use left/right/up/down/center)" + ) + elif action.keyword == "head" and direction not in HEAD_DIRECTIONS: + raise self.error( + f"Invalid direction '{direction}' for 'head' (use forward/back/left/right/up/down)" + ) + elif action.keyword == "tilt" and direction not in TILT_DIRECTIONS: + raise self.error( + f"Invalid direction '{direction}' for 'tilt' (use left/right/center)" + ) + + action.direction = direction + self.advance() + + # Parse optional parameters (strength and/or duration, in any order) + while self.current().type in ( + TokenType.NUMBER, + TokenType.DURATION, + TokenType.DURATION_KEYWORD, + TokenType.QUALITATIVE, + ): + if self.current().type == TokenType.NUMBER: + action.strength = float(self.current().value) + self.advance() + elif self.current().type == TokenType.DURATION: + duration_str = self.current().value.rstrip("s") + action.duration = float(duration_str) + self.advance() + elif self.current().type == TokenType.DURATION_KEYWORD: + action.duration_keyword = self.current().value + self.advance() + elif self.current().type == TokenType.QUALITATIVE: + action.strength_qualitative = self.current().value + self.advance() + + return action + + +def parse(tokens: List[Token]) -> Program: + """Parse tokens into AST, convenience function.""" + parser = Parser(tokens) + return parser.parse() diff --git a/rmscript/src/rmscript/semantic.py b/rmscript/src/rmscript/semantic.py new file mode 100644 index 0000000000000000000000000000000000000000..7314849b7f488776bbe7967c17437d026e688e74 --- /dev/null +++ b/rmscript/src/rmscript/semantic.py @@ -0,0 +1,535 @@ +"""Semantic analysis for ReachyMiniScript - validation, defaults, and IR generation.""" + +from typing import List + +import numpy as np + +from reachy_mini.utils import create_head_pose +from rmscript.ir import ( + IRAction, + IRWaitAction, + IRPictureAction, + IRPlaySoundAction, + CompilationError, +) +from rmscript.ast_nodes import ( + Program, + Statement, + ActionChain, + RepeatBlock, + SingleAction, + WaitStatement, + PictureStatement, + PlaySoundStatement, +) +from rmscript.constants import ( + # Legacy angle/distance constants + ANTENNA_LARGE, + ANTENNA_SMALL, + DEFAULT_ANGLE, + ANTENNA_MEDIUM, + BODY_YAW_LARGE, + BODY_YAW_SMALL, + HEAD_YAW_LARGE, + HEAD_YAW_SMALL, + LARGE_KEYWORDS, + SMALL_KEYWORDS, + BODY_YAW_MEDIUM, + CENTER_SYNONYMS, + HEAD_YAW_MEDIUM, + MEDIUM_KEYWORDS, + DEFAULT_DISTANCE, + BACKWARD_SYNONYMS, + # Other constants + DEFAULT_DURATION, + MAX_BODY_YAW_DEG, + DURATION_KEYWORDS, + MAX_HEAD_ROLL_DEG, + TRANSLATION_LARGE, + TRANSLATION_SMALL, + ANTENNA_VERY_LARGE, + ANTENNA_VERY_SMALL, + MAX_HEAD_PITCH_DEG, + TRANSLATION_MEDIUM, + BODY_YAW_VERY_LARGE, + # Context-aware qualitative constants + BODY_YAW_VERY_SMALL, + HEAD_YAW_VERY_LARGE, + HEAD_YAW_VERY_SMALL, + VERY_LARGE_KEYWORDS, + VERY_SMALL_KEYWORDS, + DEFAULT_ANTENNA_ANGLE, + HEAD_PITCH_ROLL_LARGE, + HEAD_PITCH_ROLL_SMALL, + MAX_ANTENNA_ANGLE_DEG, + ANTENNA_CLOCK_KEYWORDS, + HEAD_PITCH_ROLL_MEDIUM, + SAFE_ANTENNA_ANGLE_DEG, + TRANSLATION_VERY_LARGE, + TRANSLATION_VERY_SMALL, + MAX_HEAD_TRANSLATION_X_MM, + MAX_HEAD_TRANSLATION_Y_MM, + MAX_HEAD_TRANSLATION_Z_MM, + MIN_HEAD_TRANSLATION_Z_MM, + ANTENNA_DIRECTION_KEYWORDS, + HEAD_PITCH_ROLL_VERY_LARGE, + HEAD_PITCH_ROLL_VERY_SMALL, +) + + +class SemanticAnalyzer: + """Analyzes AST and generates intermediate representation.""" + + def __init__(self) -> None: + """Initialize semantic analyzer.""" + self.errors: List[CompilationError] = [] + self.warnings: List[CompilationError] = [] + + @staticmethod + def clock_to_angle(clock_position: float) -> float: + """Convert clock position (0-12) to angle in degrees. + + Args: + clock_position: Clock position from 0 to 12 + + Returns: + Angle in degrees, normalized to ±180° + + Examples: + 0 -> 0° (straight up) + 3 -> 90° (to the right) + 6 -> 180° (straight down) + 9 -> -90° (to the left) + + """ + # Convert clock position to angle: position * 30° (360/12) + angle = clock_position * 30.0 + + # Normalize to ±180° range + if angle > 180: + angle = angle - 360 + + return angle + + def error(self, line: int, message: str) -> None: + """Add an error.""" + self.errors.append(CompilationError(line=line, message=message)) + + def warn(self, line: int, message: str) -> None: + """Add a warning.""" + self.warnings.append( + CompilationError(line=line, message=message, severity="warning") + ) + + def analyze(self, program: Program) -> List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction]: + """Analyze program and generate IR.""" + ir: List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction] = [] + + for statement in program.statements: + ir.extend(self.analyze_statement(statement)) + + return ir + + def analyze_statement(self, stmt: Statement) -> List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction]: + """Analyze a single statement.""" + if isinstance(stmt, WaitStatement): + return [self.analyze_wait(stmt)] + elif isinstance(stmt, PictureStatement): + return [self.analyze_picture(stmt)] + elif isinstance(stmt, PlaySoundStatement): + return [self.analyze_play_sound(stmt)] + elif isinstance(stmt, ActionChain): + return [self.analyze_action_chain(stmt)] + elif isinstance(stmt, RepeatBlock): + return self.analyze_repeat(stmt) + else: + self.error(0, f"Unknown statement type: {type(stmt)}") + return [] + + def analyze_wait(self, wait: WaitStatement) -> IRWaitAction: + """Analyze wait statement.""" + # Resolve duration + duration = DEFAULT_DURATION + if wait.duration is not None: + duration = wait.duration + elif wait.duration_keyword is not None: + duration = DURATION_KEYWORDS.get(wait.duration_keyword, DEFAULT_DURATION) + + return IRWaitAction( + duration=duration, source_line=wait.line, original_text="wait" + ) + + def analyze_picture(self, picture: PictureStatement) -> IRPictureAction: + """Analyze picture statement.""" + return IRPictureAction( + source_line=picture.line, original_text="picture" + ) + + def analyze_play_sound(self, play: PlaySoundStatement) -> IRPlaySoundAction: + """Analyze play sound statement.""" + return IRPlaySoundAction( + sound_name=play.sound_name, + blocking=play.blocking, + loop=play.loop, + duration=play.duration, + source_line=play.line, + original_text=f"{'loop' if play.loop else 'play'} {play.sound_name}" + ) + + def analyze_repeat(self, repeat: RepeatBlock) -> List[IRAction | IRWaitAction | IRPictureAction | IRPlaySoundAction]: + """Analyze repeat block - expand it into IR.""" + if repeat.count < 0: + self.error(repeat.line, f"Repeat count cannot be negative: {repeat.count}") + return [] + + if repeat.count == 0: + self.warn( + repeat.line, + "Repeat count is 0, block will not execute", + ) + return [] + + # Analyze body once + body_ir = [] + for stmt in repeat.body: + body_ir.extend(self.analyze_statement(stmt)) + + # Expand repeat + expanded = [] + for _ in range(repeat.count): + expanded.extend(body_ir) + + return expanded + + def analyze_action_chain(self, chain: ActionChain) -> IRAction: + """Analyze action chain and merge into single IRAction.""" + # Resolve each action + resolved_actions = [self.resolve_action(action) for action in chain.actions] + + # Merge all actions into a single IRAction + merged = self.merge_actions(resolved_actions, chain.line) + + return merged + + def resolve_action(self, action: SingleAction) -> "ResolvedAction": + """Resolve a single action - apply defaults and convert qualitative.""" + # Determine strength + strength = self.resolve_strength(action) + + # Determine duration + duration = self.resolve_duration(action) + + # Check ranges and issue warnings + self.validate_ranges(action, strength) + + return ResolvedAction( + keyword=action.keyword, + direction=action.direction or "", + antenna_modifier=action.antenna_modifier or "both", + strength=strength, + duration=duration, + line=action.line, + ) + + def _get_qualitative_values(self, action: SingleAction) -> tuple[float, float, float, float, float, float]: + """Get context-aware qualitative values based on movement type. + + Returns tuple of (very_small, small, medium, large, very_large, default). + """ + if action.keyword == "head": + # Head translations (distances in mm) + return (TRANSLATION_VERY_SMALL, TRANSLATION_SMALL, TRANSLATION_MEDIUM, + TRANSLATION_LARGE, TRANSLATION_VERY_LARGE, DEFAULT_DISTANCE) + + elif action.keyword == "turn": + # Body yaw rotation + return (BODY_YAW_VERY_SMALL, BODY_YAW_SMALL, BODY_YAW_MEDIUM, + BODY_YAW_LARGE, BODY_YAW_VERY_LARGE, DEFAULT_ANGLE) + + elif action.keyword == "antenna": + # Antenna rotations + return (ANTENNA_VERY_SMALL, ANTENNA_SMALL, ANTENNA_MEDIUM, + ANTENNA_LARGE, ANTENNA_VERY_LARGE, DEFAULT_ANTENNA_ANGLE) + + elif action.keyword == "tilt": + # Head roll - limited by cone constraint + return (HEAD_PITCH_ROLL_VERY_SMALL, HEAD_PITCH_ROLL_SMALL, HEAD_PITCH_ROLL_MEDIUM, + HEAD_PITCH_ROLL_LARGE, HEAD_PITCH_ROLL_VERY_LARGE, DEFAULT_ANGLE) + + elif action.keyword == "look": + # Head pitch/yaw - depends on direction + if action.direction in ["up", "down"]: + # Pitch - limited by cone constraint + return (HEAD_PITCH_ROLL_VERY_SMALL, HEAD_PITCH_ROLL_SMALL, HEAD_PITCH_ROLL_MEDIUM, + HEAD_PITCH_ROLL_LARGE, HEAD_PITCH_ROLL_VERY_LARGE, DEFAULT_ANGLE) + else: + # Yaw (left/right) - larger range + return (HEAD_YAW_VERY_SMALL, HEAD_YAW_SMALL, HEAD_YAW_MEDIUM, + HEAD_YAW_LARGE, HEAD_YAW_VERY_LARGE, DEFAULT_ANGLE) + + else: + # Fallback to head yaw values + return (HEAD_YAW_VERY_SMALL, HEAD_YAW_SMALL, HEAD_YAW_MEDIUM, + HEAD_YAW_LARGE, HEAD_YAW_VERY_LARGE, DEFAULT_ANGLE) + + def resolve_strength(self, action: SingleAction) -> float: + """Resolve strength parameter with context-aware qualitative mapping.""" + # If quantitative specified, use it + if action.strength is not None: + if action.strength_qualitative is not None: + self.warn( + action.line, + f"Both qualitative '{action.strength_qualitative}' and quantitative '{action.strength}' strength specified, using {action.strength}", + ) + return action.strength + + # Get context-aware values + very_small, small, medium, large, very_large, default = self._get_qualitative_values(action) + + # If qualitative specified, convert it using context-aware values + if action.strength_qualitative is not None: + if action.strength_qualitative in VERY_SMALL_KEYWORDS: + return float(very_small) + elif action.strength_qualitative in SMALL_KEYWORDS: + return float(small) + elif action.strength_qualitative in MEDIUM_KEYWORDS: + return float(medium) + elif action.strength_qualitative in LARGE_KEYWORDS: + return float(large) + elif action.strength_qualitative in VERY_LARGE_KEYWORDS: + return float(very_large) + + # Use context-aware default + return float(default) + + def resolve_duration(self, action: SingleAction) -> float: + """Resolve duration parameter.""" + if action.duration is not None: + if action.duration < 0.1: + self.warn( + action.line, + f"Very short duration ({action.duration}s) may cause jerky motion", + ) + return action.duration + + if action.duration_keyword is not None: + return DURATION_KEYWORDS.get(action.duration_keyword, DEFAULT_DURATION) + + return DEFAULT_DURATION + + def validate_ranges(self, action: SingleAction, strength: float) -> None: + """Validate ranges and issue warnings.""" + if action.keyword == "turn": + if abs(strength) > MAX_BODY_YAW_DEG: + self.warn( + action.line, + f"Body yaw {strength}° exceeds safe range (±{MAX_BODY_YAW_DEG}°), will be clamped", + ) + + elif action.keyword == "look": + if action.direction in ["up", "down"]: # pitch + if abs(strength) > MAX_HEAD_PITCH_DEG: + self.warn( + action.line, + f"Head pitch {strength}° exceeds limit (±{MAX_HEAD_PITCH_DEG}°), will be clamped", + ) + + elif action.keyword == "tilt": + if abs(strength) > MAX_HEAD_ROLL_DEG: + self.warn( + action.line, + f"Head roll {strength}° exceeds limit (±{MAX_HEAD_ROLL_DEG}°), will be clamped", + ) + + elif action.keyword == "head": + if action.direction in ["forward", "back"]: + if abs(strength) > MAX_HEAD_TRANSLATION_X_MM: + self.warn( + action.line, + f"Head X translation {strength}mm exceeds typical range (±{MAX_HEAD_TRANSLATION_X_MM}mm)", + ) + elif action.direction in ["left", "right"]: + if abs(strength) > MAX_HEAD_TRANSLATION_Y_MM: + self.warn( + action.line, + f"Head Y translation {strength}mm exceeds typical range (±{MAX_HEAD_TRANSLATION_Y_MM}mm)", + ) + elif action.direction == "up": + if strength > MAX_HEAD_TRANSLATION_Z_MM: + self.warn( + action.line, + f"Head Z translation {strength}mm exceeds typical range ({MAX_HEAD_TRANSLATION_Z_MM}mm max)", + ) + elif action.direction == "down": + if strength > abs(MIN_HEAD_TRANSLATION_Z_MM): + self.warn( + action.line, + f"Head Z translation {strength}mm exceeds typical range ({MIN_HEAD_TRANSLATION_Z_MM}mm min)", + ) + + elif action.keyword == "antenna": + if abs(strength) > MAX_ANTENNA_ANGLE_DEG: + self.warn( + action.line, + f"Antenna angle {strength}° exceeds maximum (±{MAX_ANTENNA_ANGLE_DEG}°), will be clamped", + ) + elif abs(strength) > SAFE_ANTENNA_ANGLE_DEG: + self.warn( + action.line, + f"Antenna angle {strength}° exceeds recommended safe range (±{SAFE_ANTENNA_ANGLE_DEG}°), may cause collision", + ) + + def merge_actions( + self, actions: List["ResolvedAction"], line: int + ) -> IRAction: # noqa: F821 + """Merge multiple actions into a single IRAction IR node.""" + # Extract parameters + head_pose_params = {"x": 0.0, "y": 0.0, "z": 0.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0} + has_head_movement = False + + antennas = [0.0, 0.0] # [right, left] + has_antenna_movement = False + + body_yaw = 0.0 + has_body_yaw = False + + # Use the maximum duration + max_duration = max((a.duration for a in actions), default=DEFAULT_DURATION) + + for action in actions: + if action.keyword == "turn": + has_body_yaw = True + has_head_movement = True # Head rotates with body + if action.direction in CENTER_SYNONYMS: + body_yaw = 0.0 + head_pose_params["yaw"] = 0.0 + elif action.direction == "left": + body_yaw += action.strength # LEFT = positive yaw + head_pose_params["yaw"] += action.strength # Head follows body + elif action.direction == "right": + body_yaw -= action.strength # RIGHT = negative yaw + head_pose_params["yaw"] -= action.strength # Head follows body + + elif action.keyword == "look": + has_head_movement = True + if action.direction in CENTER_SYNONYMS: + head_pose_params["yaw"] = 0.0 + head_pose_params["pitch"] = 0.0 + elif action.direction == "left": + head_pose_params["yaw"] += action.strength # LEFT = positive yaw + elif action.direction == "right": + head_pose_params["yaw"] -= action.strength # RIGHT = negative yaw + elif action.direction == "up": + head_pose_params["pitch"] -= action.strength # UP = negative pitch + elif action.direction == "down": + head_pose_params["pitch"] += action.strength # DOWN = positive pitch + + elif action.keyword == "head": + has_head_movement = True + if action.direction == "forward": + head_pose_params["x"] += action.strength + elif action.direction in BACKWARD_SYNONYMS: + head_pose_params["x"] -= action.strength + elif action.direction == "left": + head_pose_params["y"] += action.strength + elif action.direction == "right": + head_pose_params["y"] -= action.strength + elif action.direction == "up": + head_pose_params["z"] += action.strength + elif action.direction == "down": + head_pose_params["z"] -= action.strength + + elif action.keyword == "tilt": + has_head_movement = True + if action.direction in CENTER_SYNONYMS: + head_pose_params["roll"] = 0.0 + elif action.direction == "left": + head_pose_params["roll"] += action.strength + elif action.direction == "right": + head_pose_params["roll"] -= action.strength + + elif action.keyword == "antenna": + has_antenna_movement = True + + # Determine which antenna(s) to move + # Note: antennas array is [left_antenna, right_antenna] + if action.antenna_modifier == "both": + left_idx, right_idx = 0, 1 + elif action.antenna_modifier == "right": + left_idx, right_idx = None, 1 + elif action.antenna_modifier == "left": + left_idx, right_idx = 0, None + else: + left_idx, right_idx = 0, 1 # default to both + + # Convert clock position to angle + # If direction is "clock", the clock position is stored in strength + # If direction is a clock keyword (high/low/ext/int), look it up + if action.direction == "clock": + # Clock position as number (already in strength) + clock_pos = action.strength + elif action.direction in ANTENNA_CLOCK_KEYWORDS: + # Clock keyword - look up the position + clock_pos = ANTENNA_CLOCK_KEYWORDS[action.direction] + elif action.direction in ANTENNA_DIRECTION_KEYWORDS: + # Directional keyword (up/down/left/right) - look up the position + clock_pos = ANTENNA_DIRECTION_KEYWORDS[action.direction] + else: + # Shouldn't happen due to parser validation, but fallback + clock_pos = 0.0 + + # Convert clock position to angle + angle = self.clock_to_angle(clock_pos) + + # Set antenna positions (same angle for specified antenna(s)) + if right_idx is not None: + antennas[right_idx] = angle + if left_idx is not None: + antennas[left_idx] = angle + + # Build IRAction IR node + result = IRAction( + source_line=line, + duration=max_duration, + ) + + if has_head_movement: + result.head_pose = create_head_pose( + x=head_pose_params["x"], + y=head_pose_params["y"], + z=head_pose_params["z"], + roll=head_pose_params["roll"], + pitch=head_pose_params["pitch"], + yaw=head_pose_params["yaw"], + mm=True, + degrees=True, + ) + + if has_antenna_movement: + result.antennas = [np.deg2rad(antennas[0]), np.deg2rad(antennas[1])] + + if has_body_yaw: + result.body_yaw = np.deg2rad(body_yaw) + + return result + + +class ResolvedAction: + """Temporary structure for resolved action parameters.""" + + def __init__( + self, + keyword: str, + direction: str, + antenna_modifier: str, + strength: float, + duration: float, + line: int, + ): + """Initialize resolved action.""" + self.keyword = keyword + self.direction = direction + self.antenna_modifier = antenna_modifier + self.strength = strength + self.duration = duration + self.line = line diff --git a/rmscript/uv.lock b/rmscript/uv.lock new file mode 100644 index 0000000000000000000000000000000000000000..adf377fbe7c06797b885ff0f61078b4dff7280bd --- /dev/null +++ b/rmscript/uv.lock @@ -0,0 +1,2179 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" +resolution-markers = [ + "python_full_version >= '3.12' and sys_platform == 'darwin'", + "python_full_version >= '3.12' and platform_machine == 'aarch64' and sys_platform == 'linux'", + "(python_full_version >= '3.12' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.12' and sys_platform == 'darwin'", + "python_full_version < '3.12' and platform_machine == 'aarch64' and sys_platform == 'linux'", + "(python_full_version < '3.12' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.12' and sys_platform != 'darwin' and sys_platform != 'linux')", +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994, upload-time = "2025-10-28T20:59:39.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/74/b321e7d7ca762638cdf8cdeceb39755d9c745aff7a64c8789be96ddf6e96/aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0", size = 743409, upload-time = "2025-10-28T20:56:00.354Z" }, + { url = "https://files.pythonhosted.org/packages/99/3d/91524b905ec473beaf35158d17f82ef5a38033e5809fe8742e3657cdbb97/aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb", size = 497006, upload-time = "2025-10-28T20:56:01.85Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d3/7f68bc02a67716fe80f063e19adbd80a642e30682ce74071269e17d2dba1/aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9", size = 493195, upload-time = "2025-10-28T20:56:03.314Z" }, + { url = "https://files.pythonhosted.org/packages/98/31/913f774a4708775433b7375c4f867d58ba58ead833af96c8af3621a0d243/aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613", size = 1747759, upload-time = "2025-10-28T20:56:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/e8/63/04efe156f4326f31c7c4a97144f82132c3bb21859b7bb84748d452ccc17c/aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead", size = 1704456, upload-time = "2025-10-28T20:56:06.986Z" }, + { url = "https://files.pythonhosted.org/packages/8e/02/4e16154d8e0a9cf4ae76f692941fd52543bbb148f02f098ca73cab9b1c1b/aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780", size = 1807572, upload-time = "2025-10-28T20:56:08.558Z" }, + { url = "https://files.pythonhosted.org/packages/34/58/b0583defb38689e7f06798f0285b1ffb3a6fb371f38363ce5fd772112724/aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a", size = 1895954, upload-time = "2025-10-28T20:56:10.545Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f3/083907ee3437425b4e376aa58b2c915eb1a33703ec0dc30040f7ae3368c6/aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592", size = 1747092, upload-time = "2025-10-28T20:56:12.118Z" }, + { url = "https://files.pythonhosted.org/packages/ac/61/98a47319b4e425cc134e05e5f3fc512bf9a04bf65aafd9fdcda5d57ec693/aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab", size = 1606815, upload-time = "2025-10-28T20:56:14.191Z" }, + { url = "https://files.pythonhosted.org/packages/97/4b/e78b854d82f66bb974189135d31fce265dee0f5344f64dd0d345158a5973/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30", size = 1723789, upload-time = "2025-10-28T20:56:16.101Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fc/9d2ccc794fc9b9acd1379d625c3a8c64a45508b5091c546dea273a41929e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40", size = 1718104, upload-time = "2025-10-28T20:56:17.655Z" }, + { url = "https://files.pythonhosted.org/packages/66/65/34564b8765ea5c7d79d23c9113135d1dd3609173da13084830f1507d56cf/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948", size = 1785584, upload-time = "2025-10-28T20:56:19.238Z" }, + { url = "https://files.pythonhosted.org/packages/30/be/f6a7a426e02fc82781afd62016417b3948e2207426d90a0e478790d1c8a4/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf", size = 1595126, upload-time = "2025-10-28T20:56:20.836Z" }, + { url = "https://files.pythonhosted.org/packages/e5/c7/8e22d5d28f94f67d2af496f14a83b3c155d915d1fe53d94b66d425ec5b42/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782", size = 1800665, upload-time = "2025-10-28T20:56:22.922Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/91133c8b68b1da9fc16555706aa7276fdf781ae2bb0876c838dd86b8116e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8", size = 1739532, upload-time = "2025-10-28T20:56:25.924Z" }, + { url = "https://files.pythonhosted.org/packages/17/6b/3747644d26a998774b21a616016620293ddefa4d63af6286f389aedac844/aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec", size = 431876, upload-time = "2025-10-28T20:56:27.524Z" }, + { url = "https://files.pythonhosted.org/packages/c3/63/688462108c1a00eb9f05765331c107f95ae86f6b197b865d29e930b7e462/aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c", size = 456205, upload-time = "2025-10-28T20:56:29.062Z" }, + { url = "https://files.pythonhosted.org/packages/29/9b/01f00e9856d0a73260e86dd8ed0c2234a466c5c1712ce1c281548df39777/aiohttp-3.13.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b1e56bab2e12b2b9ed300218c351ee2a3d8c8fdab5b1ec6193e11a817767e47b", size = 737623, upload-time = "2025-10-28T20:56:30.797Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1b/4be39c445e2b2bd0aab4ba736deb649fabf14f6757f405f0c9685019b9e9/aiohttp-3.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:364e25edaabd3d37b1db1f0cbcee8c73c9a3727bfa262b83e5e4cf3489a2a9dc", size = 492664, upload-time = "2025-10-28T20:56:32.708Z" }, + { url = "https://files.pythonhosted.org/packages/28/66/d35dcfea8050e131cdd731dff36434390479b4045a8d0b9d7111b0a968f1/aiohttp-3.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5c94825f744694c4b8db20b71dba9a257cd2ba8e010a803042123f3a25d50d7", size = 491808, upload-time = "2025-10-28T20:56:34.57Z" }, + { url = "https://files.pythonhosted.org/packages/00/29/8e4609b93e10a853b65f8291e64985de66d4f5848c5637cddc70e98f01f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba2715d842ffa787be87cbfce150d5e88c87a98e0b62e0f5aa489169a393dbbb", size = 1738863, upload-time = "2025-10-28T20:56:36.377Z" }, + { url = "https://files.pythonhosted.org/packages/9d/fa/4ebdf4adcc0def75ced1a0d2d227577cd7b1b85beb7edad85fcc87693c75/aiohttp-3.13.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:585542825c4bc662221fb257889e011a5aa00f1ae4d75d1d246a5225289183e3", size = 1700586, upload-time = "2025-10-28T20:56:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/da/04/73f5f02ff348a3558763ff6abe99c223381b0bace05cd4530a0258e52597/aiohttp-3.13.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39d02cb6025fe1aabca329c5632f48c9532a3dabccd859e7e2f110668972331f", size = 1768625, upload-time = "2025-10-28T20:56:39.75Z" }, + { url = "https://files.pythonhosted.org/packages/f8/49/a825b79ffec124317265ca7d2344a86bcffeb960743487cb11988ffb3494/aiohttp-3.13.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e67446b19e014d37342f7195f592a2a948141d15a312fe0e700c2fd2f03124f6", size = 1867281, upload-time = "2025-10-28T20:56:41.471Z" }, + { url = "https://files.pythonhosted.org/packages/b9/48/adf56e05f81eac31edcfae45c90928f4ad50ef2e3ea72cb8376162a368f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4356474ad6333e41ccefd39eae869ba15a6c5299c9c01dfdcfdd5c107be4363e", size = 1752431, upload-time = "2025-10-28T20:56:43.162Z" }, + { url = "https://files.pythonhosted.org/packages/30/ab/593855356eead019a74e862f21523db09c27f12fd24af72dbc3555b9bfd9/aiohttp-3.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeacf451c99b4525f700f078becff32c32ec327b10dcf31306a8a52d78166de7", size = 1562846, upload-time = "2025-10-28T20:56:44.85Z" }, + { url = "https://files.pythonhosted.org/packages/39/0f/9f3d32271aa8dc35036e9668e31870a9d3b9542dd6b3e2c8a30931cb27ae/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8a9b889aeabd7a4e9af0b7f4ab5ad94d42e7ff679aaec6d0db21e3b639ad58d", size = 1699606, upload-time = "2025-10-28T20:56:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3c/52d2658c5699b6ef7692a3f7128b2d2d4d9775f2a68093f74bca06cf01e1/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fa89cb11bc71a63b69568d5b8a25c3ca25b6d54c15f907ca1c130d72f320b76b", size = 1720663, upload-time = "2025-10-28T20:56:48.528Z" }, + { url = "https://files.pythonhosted.org/packages/9b/d4/8f8f3ff1fb7fb9e3f04fcad4e89d8a1cd8fc7d05de67e3de5b15b33008ff/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8aa7c807df234f693fed0ecd507192fc97692e61fee5702cdc11155d2e5cadc8", size = 1737939, upload-time = "2025-10-28T20:56:50.77Z" }, + { url = "https://files.pythonhosted.org/packages/03/d3/ddd348f8a27a634daae39a1b8e291ff19c77867af438af844bf8b7e3231b/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9eb3e33fdbe43f88c3c75fa608c25e7c47bbd80f48d012763cb67c47f39a7e16", size = 1555132, upload-time = "2025-10-28T20:56:52.568Z" }, + { url = "https://files.pythonhosted.org/packages/39/b8/46790692dc46218406f94374903ba47552f2f9f90dad554eed61bfb7b64c/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9434bc0d80076138ea986833156c5a48c9c7a8abb0c96039ddbb4afc93184169", size = 1764802, upload-time = "2025-10-28T20:56:54.292Z" }, + { url = "https://files.pythonhosted.org/packages/ba/e4/19ce547b58ab2a385e5f0b8aa3db38674785085abcf79b6e0edd1632b12f/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff15c147b2ad66da1f2cbb0622313f2242d8e6e8f9b79b5206c84523a4473248", size = 1719512, upload-time = "2025-10-28T20:56:56.428Z" }, + { url = "https://files.pythonhosted.org/packages/70/30/6355a737fed29dcb6dfdd48682d5790cb5eab050f7b4e01f49b121d3acad/aiohttp-3.13.2-cp312-cp312-win32.whl", hash = "sha256:27e569eb9d9e95dbd55c0fc3ec3a9335defbf1d8bc1d20171a49f3c4c607b93e", size = 426690, upload-time = "2025-10-28T20:56:58.736Z" }, + { url = "https://files.pythonhosted.org/packages/0a/0d/b10ac09069973d112de6ef980c1f6bb31cb7dcd0bc363acbdad58f927873/aiohttp-3.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:8709a0f05d59a71f33fd05c17fc11fcb8c30140506e13c2f5e8ee1b8964e1b45", size = 453465, upload-time = "2025-10-28T20:57:00.795Z" }, + { url = "https://files.pythonhosted.org/packages/bf/78/7e90ca79e5aa39f9694dcfd74f4720782d3c6828113bb1f3197f7e7c4a56/aiohttp-3.13.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7519bdc7dfc1940d201651b52bf5e03f5503bda45ad6eacf64dda98be5b2b6be", size = 732139, upload-time = "2025-10-28T20:57:02.455Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/1f59215ab6853fbaa5c8495fa6cbc39edfc93553426152b75d82a5f32b76/aiohttp-3.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:088912a78b4d4f547a1f19c099d5a506df17eacec3c6f4375e2831ec1d995742", size = 490082, upload-time = "2025-10-28T20:57:04.784Z" }, + { url = "https://files.pythonhosted.org/packages/68/7b/fe0fe0f5e05e13629d893c760465173a15ad0039c0a5b0d0040995c8075e/aiohttp-3.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5276807b9de9092af38ed23ce120539ab0ac955547b38563a9ba4f5b07b95293", size = 489035, upload-time = "2025-10-28T20:57:06.894Z" }, + { url = "https://files.pythonhosted.org/packages/d2/04/db5279e38471b7ac801d7d36a57d1230feeee130bbe2a74f72731b23c2b1/aiohttp-3.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1237c1375eaef0db4dcd7c2559f42e8af7b87ea7d295b118c60c36a6e61cb811", size = 1720387, upload-time = "2025-10-28T20:57:08.685Z" }, + { url = "https://files.pythonhosted.org/packages/31/07/8ea4326bd7dae2bd59828f69d7fdc6e04523caa55e4a70f4a8725a7e4ed2/aiohttp-3.13.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96581619c57419c3d7d78703d5b78c1e5e5fc0172d60f555bdebaced82ded19a", size = 1688314, upload-time = "2025-10-28T20:57:10.693Z" }, + { url = "https://files.pythonhosted.org/packages/48/ab/3d98007b5b87ffd519d065225438cc3b668b2f245572a8cb53da5dd2b1bc/aiohttp-3.13.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2713a95b47374169409d18103366de1050fe0ea73db358fc7a7acb2880422d4", size = 1756317, upload-time = "2025-10-28T20:57:12.563Z" }, + { url = "https://files.pythonhosted.org/packages/97/3d/801ca172b3d857fafb7b50c7c03f91b72b867a13abca982ed6b3081774ef/aiohttp-3.13.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:228a1cd556b3caca590e9511a89444925da87d35219a49ab5da0c36d2d943a6a", size = 1858539, upload-time = "2025-10-28T20:57:14.623Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0d/4764669bdf47bd472899b3d3db91fffbe925c8e3038ec591a2fd2ad6a14d/aiohttp-3.13.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac6cde5fba8d7d8c6ac963dbb0256a9854e9fafff52fbcc58fdf819357892c3e", size = 1739597, upload-time = "2025-10-28T20:57:16.399Z" }, + { url = "https://files.pythonhosted.org/packages/c4/52/7bd3c6693da58ba16e657eb904a5b6decfc48ecd06e9ac098591653b1566/aiohttp-3.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2bef8237544f4e42878c61cef4e2839fee6346dc60f5739f876a9c50be7fcdb", size = 1555006, upload-time = "2025-10-28T20:57:18.288Z" }, + { url = "https://files.pythonhosted.org/packages/48/30/9586667acec5993b6f41d2ebcf96e97a1255a85f62f3c653110a5de4d346/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:16f15a4eac3bc2d76c45f7ebdd48a65d41b242eb6c31c2245463b40b34584ded", size = 1683220, upload-time = "2025-10-28T20:57:20.241Z" }, + { url = "https://files.pythonhosted.org/packages/71/01/3afe4c96854cfd7b30d78333852e8e851dceaec1c40fd00fec90c6402dd2/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bb7fb776645af5cc58ab804c58d7eba545a97e047254a52ce89c157b5af6cd0b", size = 1712570, upload-time = "2025-10-28T20:57:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/11/2c/22799d8e720f4697a9e66fd9c02479e40a49de3de2f0bbe7f9f78a987808/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1b4951125ec10c70802f2cb09736c895861cd39fd9dcb35107b4dc8ae6220b8", size = 1733407, upload-time = "2025-10-28T20:57:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/34/cb/90f15dd029f07cebbd91f8238a8b363978b530cd128488085b5703683594/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:550bf765101ae721ee1d37d8095f47b1f220650f85fe1af37a90ce75bab89d04", size = 1550093, upload-time = "2025-10-28T20:57:26.257Z" }, + { url = "https://files.pythonhosted.org/packages/69/46/12dce9be9d3303ecbf4d30ad45a7683dc63d90733c2d9fe512be6716cd40/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fe91b87fc295973096251e2d25a811388e7d8adf3bd2b97ef6ae78bc4ac6c476", size = 1758084, upload-time = "2025-10-28T20:57:28.349Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c8/0932b558da0c302ffd639fc6362a313b98fdf235dc417bc2493da8394df7/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0c8e31cfcc4592cb200160344b2fb6ae0f9e4effe06c644b5a125d4ae5ebe23", size = 1716987, upload-time = "2025-10-28T20:57:30.233Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8b/f5bd1a75003daed099baec373aed678f2e9b34f2ad40d85baa1368556396/aiohttp-3.13.2-cp313-cp313-win32.whl", hash = "sha256:0740f31a60848d6edb296a0df827473eede90c689b8f9f2a4cdde74889eb2254", size = 425859, upload-time = "2025-10-28T20:57:32.105Z" }, + { url = "https://files.pythonhosted.org/packages/5d/28/a8a9fc6957b2cee8902414e41816b5ab5536ecf43c3b1843c10e82c559b2/aiohttp-3.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:a88d13e7ca367394908f8a276b89d04a3652044612b9a408a0bb22a5ed976a1a", size = 452192, upload-time = "2025-10-28T20:57:34.166Z" }, + { url = "https://files.pythonhosted.org/packages/9b/36/e2abae1bd815f01c957cbf7be817b3043304e1c87bad526292a0410fdcf9/aiohttp-3.13.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2475391c29230e063ef53a66669b7b691c9bfc3f1426a0f7bcdf1216bdbac38b", size = 735234, upload-time = "2025-10-28T20:57:36.415Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e3/1ee62dde9b335e4ed41db6bba02613295a0d5b41f74a783c142745a12763/aiohttp-3.13.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f33c8748abef4d8717bb20e8fb1b3e07c6adacb7fd6beaae971a764cf5f30d61", size = 490733, upload-time = "2025-10-28T20:57:38.205Z" }, + { url = "https://files.pythonhosted.org/packages/1a/aa/7a451b1d6a04e8d15a362af3e9b897de71d86feac3babf8894545d08d537/aiohttp-3.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ae32f24bbfb7dbb485a24b30b1149e2f200be94777232aeadba3eecece4d0aa4", size = 491303, upload-time = "2025-10-28T20:57:40.122Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/209958dbb9b01174870f6a7538cd1f3f28274fdbc88a750c238e2c456295/aiohttp-3.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7f02042c1f009ffb70067326ef183a047425bb2ff3bc434ead4dd4a4a66a2b", size = 1717965, upload-time = "2025-10-28T20:57:42.28Z" }, + { url = "https://files.pythonhosted.org/packages/08/aa/6a01848d6432f241416bc4866cae8dc03f05a5a884d2311280f6a09c73d6/aiohttp-3.13.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93655083005d71cd6c072cdab54c886e6570ad2c4592139c3fb967bfc19e4694", size = 1667221, upload-time = "2025-10-28T20:57:44.869Z" }, + { url = "https://files.pythonhosted.org/packages/87/4f/36c1992432d31bbc789fa0b93c768d2e9047ec8c7177e5cd84ea85155f36/aiohttp-3.13.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0db1e24b852f5f664cd728db140cf11ea0e82450471232a394b3d1a540b0f906", size = 1757178, upload-time = "2025-10-28T20:57:47.216Z" }, + { url = "https://files.pythonhosted.org/packages/ac/b4/8e940dfb03b7e0f68a82b88fd182b9be0a65cb3f35612fe38c038c3112cf/aiohttp-3.13.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b009194665bcd128e23eaddef362e745601afa4641930848af4c8559e88f18f9", size = 1838001, upload-time = "2025-10-28T20:57:49.337Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ef/39f3448795499c440ab66084a9db7d20ca7662e94305f175a80f5b7e0072/aiohttp-3.13.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c038a8fdc8103cd51dbd986ecdce141473ffd9775a7a8057a6ed9c3653478011", size = 1716325, upload-time = "2025-10-28T20:57:51.327Z" }, + { url = "https://files.pythonhosted.org/packages/d7/51/b311500ffc860b181c05d91c59a1313bdd05c82960fdd4035a15740d431e/aiohttp-3.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66bac29b95a00db411cd758fea0e4b9bdba6d549dfe333f9a945430f5f2cc5a6", size = 1547978, upload-time = "2025-10-28T20:57:53.554Z" }, + { url = "https://files.pythonhosted.org/packages/31/64/b9d733296ef79815226dab8c586ff9e3df41c6aff2e16c06697b2d2e6775/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4ebf9cfc9ba24a74cf0718f04aac2a3bbe745902cc7c5ebc55c0f3b5777ef213", size = 1682042, upload-time = "2025-10-28T20:57:55.617Z" }, + { url = "https://files.pythonhosted.org/packages/3f/30/43d3e0f9d6473a6db7d472104c4eff4417b1e9df01774cb930338806d36b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a4b88ebe35ce54205c7074f7302bd08a4cb83256a3e0870c72d6f68a3aaf8e49", size = 1680085, upload-time = "2025-10-28T20:57:57.59Z" }, + { url = "https://files.pythonhosted.org/packages/16/51/c709f352c911b1864cfd1087577760ced64b3e5bee2aa88b8c0c8e2e4972/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98c4fb90bb82b70a4ed79ca35f656f4281885be076f3f970ce315402b53099ae", size = 1728238, upload-time = "2025-10-28T20:57:59.525Z" }, + { url = "https://files.pythonhosted.org/packages/19/e2/19bd4c547092b773caeb48ff5ae4b1ae86756a0ee76c16727fcfd281404b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:ec7534e63ae0f3759df3a1ed4fa6bc8f75082a924b590619c0dd2f76d7043caa", size = 1544395, upload-time = "2025-10-28T20:58:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/cf/87/860f2803b27dfc5ed7be532832a3498e4919da61299b4a1f8eb89b8ff44d/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5b927cf9b935a13e33644cbed6c8c4b2d0f25b713d838743f8fe7191b33829c4", size = 1742965, upload-time = "2025-10-28T20:58:03.972Z" }, + { url = "https://files.pythonhosted.org/packages/67/7f/db2fc7618925e8c7a601094d5cbe539f732df4fb570740be88ed9e40e99a/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:88d6c017966a78c5265d996c19cdb79235be5e6412268d7e2ce7dee339471b7a", size = 1697585, upload-time = "2025-10-28T20:58:06.189Z" }, + { url = "https://files.pythonhosted.org/packages/0c/07/9127916cb09bb38284db5036036042b7b2c514c8ebaeee79da550c43a6d6/aiohttp-3.13.2-cp314-cp314-win32.whl", hash = "sha256:f7c183e786e299b5d6c49fb43a769f8eb8e04a2726a2bd5887b98b5cc2d67940", size = 431621, upload-time = "2025-10-28T20:58:08.636Z" }, + { url = "https://files.pythonhosted.org/packages/fb/41/554a8a380df6d3a2bba8a7726429a23f4ac62aaf38de43bb6d6cde7b4d4d/aiohttp-3.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:fe242cd381e0fb65758faf5ad96c2e460df6ee5b2de1072fe97e4127927e00b4", size = 457627, upload-time = "2025-10-28T20:58:11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8e/3824ef98c039d3951cb65b9205a96dd2b20f22241ee17d89c5701557c826/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f10d9c0b0188fe85398c61147bbd2a657d616c876863bfeff43376e0e3134673", size = 767360, upload-time = "2025-10-28T20:58:13.358Z" }, + { url = "https://files.pythonhosted.org/packages/a4/0f/6a03e3fc7595421274fa34122c973bde2d89344f8a881b728fa8c774e4f1/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e7c952aefdf2460f4ae55c5e9c3e80aa72f706a6317e06020f80e96253b1accd", size = 504616, upload-time = "2025-10-28T20:58:15.339Z" }, + { url = "https://files.pythonhosted.org/packages/c6/aa/ed341b670f1bc8a6f2c6a718353d13b9546e2cef3544f573c6a1ff0da711/aiohttp-3.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c20423ce14771d98353d2e25e83591fa75dfa90a3c1848f3d7c68243b4fbded3", size = 509131, upload-time = "2025-10-28T20:58:17.693Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f0/c68dac234189dae5c4bbccc0f96ce0cc16b76632cfc3a08fff180045cfa4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e96eb1a34396e9430c19d8338d2ec33015e4a87ef2b4449db94c22412e25ccdf", size = 1864168, upload-time = "2025-10-28T20:58:20.113Z" }, + { url = "https://files.pythonhosted.org/packages/8f/65/75a9a76db8364b5d0e52a0c20eabc5d52297385d9af9c35335b924fafdee/aiohttp-3.13.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:23fb0783bc1a33640036465019d3bba069942616a6a2353c6907d7fe1ccdaf4e", size = 1719200, upload-time = "2025-10-28T20:58:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/8df2ed78d7f41d232f6bd3ff866b6f617026551aa1d07e2f03458f964575/aiohttp-3.13.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1a9bea6244a1d05a4e57c295d69e159a5c50d8ef16aa390948ee873478d9a5", size = 1843497, upload-time = "2025-10-28T20:58:24.672Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e0/94d7215e405c5a02ccb6a35c7a3a6cfff242f457a00196496935f700cde5/aiohttp-3.13.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a3d54e822688b56e9f6b5816fb3de3a3a64660efac64e4c2dc435230ad23bad", size = 1935703, upload-time = "2025-10-28T20:58:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/0b/78/1eeb63c3f9b2d1015a4c02788fb543141aad0a03ae3f7a7b669b2483f8d4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a653d872afe9f33497215745da7a943d1dc15b728a9c8da1c3ac423af35178e", size = 1792738, upload-time = "2025-10-28T20:58:29.787Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/aaf1eea4c188e51538c04cc568040e3082db263a57086ea74a7d38c39e42/aiohttp-3.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:56d36e80d2003fa3fc0207fac644216d8532e9504a785ef9a8fd013f84a42c61", size = 1624061, upload-time = "2025-10-28T20:58:32.529Z" }, + { url = "https://files.pythonhosted.org/packages/9b/c2/3b6034de81fbcc43de8aeb209073a2286dfb50b86e927b4efd81cf848197/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78cd586d8331fb8e241c2dd6b2f4061778cc69e150514b39a9e28dd050475661", size = 1789201, upload-time = "2025-10-28T20:58:34.618Z" }, + { url = "https://files.pythonhosted.org/packages/c9/38/c15dcf6d4d890217dae79d7213988f4e5fe6183d43893a9cf2fe9e84ca8d/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:20b10bbfbff766294fe99987f7bb3b74fdd2f1a2905f2562132641ad434dcf98", size = 1776868, upload-time = "2025-10-28T20:58:38.835Z" }, + { url = "https://files.pythonhosted.org/packages/04/75/f74fd178ac81adf4f283a74847807ade5150e48feda6aef024403716c30c/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9ec49dff7e2b3c85cdeaa412e9d438f0ecd71676fde61ec57027dd392f00c693", size = 1790660, upload-time = "2025-10-28T20:58:41.507Z" }, + { url = "https://files.pythonhosted.org/packages/e7/80/7368bd0d06b16b3aba358c16b919e9c46cf11587dc572091031b0e9e3ef0/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:94f05348c4406450f9d73d38efb41d669ad6cd90c7ee194810d0eefbfa875a7a", size = 1617548, upload-time = "2025-10-28T20:58:43.674Z" }, + { url = "https://files.pythonhosted.org/packages/7d/4b/a6212790c50483cb3212e507378fbe26b5086d73941e1ec4b56a30439688/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:fa4dcb605c6f82a80c7f95713c2b11c3b8e9893b3ebd2bc9bde93165ed6107be", size = 1817240, upload-time = "2025-10-28T20:58:45.787Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f7/ba5f0ba4ea8d8f3c32850912944532b933acbf0f3a75546b89269b9b7dde/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf00e5db968c3f67eccd2778574cf64d8b27d95b237770aa32400bd7a1ca4f6c", size = 1762334, upload-time = "2025-10-28T20:58:47.936Z" }, + { url = "https://files.pythonhosted.org/packages/7e/83/1a5a1856574588b1cad63609ea9ad75b32a8353ac995d830bf5da9357364/aiohttp-3.13.2-cp314-cp314t-win32.whl", hash = "sha256:d23b5fe492b0805a50d3371e8a728a9134d8de5447dce4c885f5587294750734", size = 464685, upload-time = "2025-10-28T20:58:50.642Z" }, + { url = "https://files.pythonhosted.org/packages/9f/4d/d22668674122c08f4d56972297c51a624e64b3ed1efaa40187607a7cb66e/aiohttp-3.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:ff0a7b0a82a7ab905cbda74006318d1b12e37c797eb1b0d4eb3e316cf47f658f", size = 498093, upload-time = "2025-10-28T20:58:52.782Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +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 = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, +] + +[[package]] +name = "asgiref" +version = "3.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/b9/4db2509eabd14b4a8c71d1b24c8d5734c52b8560a7b1e1a8b56c8d25568b/asgiref-3.11.0.tar.gz", hash = "sha256:13acff32519542a1736223fb79a715acdebe24286d98e8b164a73085f40da2c4", size = 37969, upload-time = "2025-11-19T15:32:20.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/be/317c2c55b8bbec407257d45f5c8d1b6867abc76d12043f2d3d58c538a4ea/asgiref-3.11.0-py3-none-any.whl", hash = "sha256:1db9021efadb0d9512ce8ffaf72fcef601c7b73a8807a1bb2ef143dc6b14846d", size = 24096, upload-time = "2025-11-19T15:32:19.004Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cv2-enumerate-cameras" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/cf/a6eb5fa54d7dfc87c93a6161aef57527c6ef4d8239be7cef10d13fb9efd6/cv2_enumerate_cameras-1.3.0.tar.gz", hash = "sha256:795d8005b0e92ca117e1b8c4849c752edb39b7e2a1818b2d7ac4463aa26caac1", size = 12455, upload-time = "2025-09-12T04:42:33.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/38/cc570b8579a2be52d0a3f6dba7afad536bc6d41cfc44108727ef7d8b185a/cv2_enumerate_cameras-1.3.0-cp32-abi3-win32.whl", hash = "sha256:bd24be3c2df42b88da59e9f6029b97484fc8468678a2be3900aa717835c40f6a", size = 20406, upload-time = "2025-09-12T04:42:28.463Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ef/0a6e095462e90d12358ef68653c7ea4d86dd6f5dd8f433279ecb5745e9ca/cv2_enumerate_cameras-1.3.0-cp32-abi3-win_amd64.whl", hash = "sha256:ef892cc7d92dec3ad0f696fa592a9d5461e593698048f84e877353cffcfc486f", size = 21296, upload-time = "2025-09-12T04:42:30.87Z" }, + { url = "https://files.pythonhosted.org/packages/7e/d5/6a6b74c92b6901d7077eb67284010354d90762702ed3451ea5d6297ef692/cv2_enumerate_cameras-1.3.0-py3-none-any.whl", hash = "sha256:7a67d8cc98fd112c3df51ff699c6953884e96088ced2ee05191bdeaaa2e1e847", size = 11571, upload-time = "2025-09-12T04:42:32.272Z" }, +] + +[[package]] +name = "eclipse-zenoh" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/3b/15bb190da421536b28de45438ad328925f203b5b274c5e92a7dcc6f7ac14/eclipse_zenoh-1.6.2.tar.gz", hash = "sha256:852b649a9d1c482edb690759311d5322fa10e5388ba6dec507d35151b48ceb35", size = 132916, upload-time = "2025-10-17T20:11:01.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/13/0e6511e1f007686084beff96d960407edc8303a0aac267689087e1be3e11/eclipse_zenoh-1.6.2-cp39-abi3-linux_armv6l.whl", hash = "sha256:b311c5e4626cc2faad367ef0edbb09079dafefc004531f135cafd22af48f362e", size = 9454073, upload-time = "2025-10-17T20:10:46.806Z" }, + { url = "https://files.pythonhosted.org/packages/1b/84/f36e224fb7eb05927e55ea7cd2ee000f7a9254d194f7ab539627a1635dd3/eclipse_zenoh-1.6.2-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:13d0b10c09fbd4233356a38b11cf008112acefda308a4dd4feb3c8e74c674065", size = 17565641, upload-time = "2025-10-17T20:10:49.061Z" }, + { url = "https://files.pythonhosted.org/packages/e0/7d/98194e5f4f369eb7f49024d7d4536342636bee216f191cbb111c7ee86764/eclipse_zenoh-1.6.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:29f081cf6ba5eee7c72606cab1e534e6e6a825c08899529c176d7a6fa1cff6c4", size = 8984387, upload-time = "2025-10-17T20:10:50.736Z" }, + { url = "https://files.pythonhosted.org/packages/04/17/0b550ec08095471bd099258ea23685f569dba79394fa22dd25c232d75cae/eclipse_zenoh-1.6.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c1c332334ec4bceb0856472146684cfb4230e55c0409cba6b369e34c87a5f5cb", size = 9337753, upload-time = "2025-10-17T20:10:52.696Z" }, + { url = "https://files.pythonhosted.org/packages/9c/bc/9c2196cc742ad0ccdcc9e942bea3d627f70e5a17708ab412e05bbca07180/eclipse_zenoh-1.6.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10cf678ed2578b954cf8d1863c897c9d4404d9bac1c9560dfdb9a300bb488e01", size = 10147324, upload-time = "2025-10-17T20:10:55.234Z" }, + { url = "https://files.pythonhosted.org/packages/dd/81/7ac634430be1fd15aea65d6e849f7d73d0a8cf285dd74e8e39cd7b7ea2e2/eclipse_zenoh-1.6.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5db633632e3da9c63ae70e219f2a84dca3dcb08125fb9aef9f11602104790afb", size = 9626850, upload-time = "2025-10-17T20:10:56.785Z" }, + { url = "https://files.pythonhosted.org/packages/29/fe/c5b2e65e0c2800b4e1a02b388e0ddf7c3b71f478757bb6a294c021d49e84/eclipse_zenoh-1.6.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e7f9bf3849567631caa3bdeecf2edce66461b1ae511f28dfafea6089022d02e1", size = 9487136, upload-time = "2025-10-17T20:10:58.359Z" }, + { url = "https://files.pythonhosted.org/packages/77/93/4df169108c4313d0f476bb9abd7d76496059e8bfcc3a98168aa26cc73b00/eclipse_zenoh-1.6.2-cp39-abi3-win_amd64.whl", hash = "sha256:f59f75f0d733daf5059843037e63bb62dd5268809d041a150bcfd8f8d62b9b08", size = 7805746, upload-time = "2025-10-17T20:11:00.257Z" }, +] + +[[package]] +name = "fastapi" +version = "0.122.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/de/3ee97a4f6ffef1fb70bf20561e4f88531633bb5045dc6cebc0f8471f764d/fastapi-0.122.0.tar.gz", hash = "sha256:cd9b5352031f93773228af8b4c443eedc2ac2aa74b27780387b853c3726fb94b", size = 346436, upload-time = "2025-11-24T19:17:47.95Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/93/aa8072af4ff37b795f6bbf43dcaf61115f40f49935c7dbb180c9afc3f421/fastapi-0.122.0-py3-none-any.whl", hash = "sha256:a456e8915dfc6c8914a50d9651133bd47ec96d331c5b44600baa635538a30d67", size = 110671, upload-time = "2025-11-24T19:17:45.96Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, +] + +[[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/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, + { 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 = "2025.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, +] + +[[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 = "hf-xet" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload-time = "2025-10-24T19:04:11.422Z" }, + { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload-time = "2025-10-24T19:04:09.586Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload-time = "2025-10-24T19:04:00.314Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload-time = "2025-10-24T19:03:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload-time = "2025-10-24T19:04:20.951Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload-time = "2025-10-24T19:04:22.549Z" }, + { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload-time = "2025-10-24T19:04:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" }, + { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" }, + { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, +] + +[[package]] +name = "httptools" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/08/17e07e8d89ab8f343c134616d72eebfe03798835058e2ab579dcc8353c06/httptools-0.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:474d3b7ab469fefcca3697a10d11a32ee2b9573250206ba1e50d5980910da657", size = 206521, upload-time = "2025-10-10T03:54:31.002Z" }, + { url = "https://files.pythonhosted.org/packages/aa/06/c9c1b41ff52f16aee526fd10fbda99fa4787938aa776858ddc4a1ea825ec/httptools-0.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3c3b7366bb6c7b96bd72d0dbe7f7d5eead261361f013be5f6d9590465ea1c70", size = 110375, upload-time = "2025-10-10T03:54:31.941Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cc/10935db22fda0ee34c76f047590ca0a8bd9de531406a3ccb10a90e12ea21/httptools-0.7.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:379b479408b8747f47f3b253326183d7c009a3936518cdb70db58cffd369d9df", size = 456621, upload-time = "2025-10-10T03:54:33.176Z" }, + { url = "https://files.pythonhosted.org/packages/0e/84/875382b10d271b0c11aa5d414b44f92f8dd53e9b658aec338a79164fa548/httptools-0.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cad6b591a682dcc6cf1397c3900527f9affef1e55a06c4547264796bbd17cf5e", size = 454954, upload-time = "2025-10-10T03:54:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/30/e1/44f89b280f7e46c0b1b2ccee5737d46b3bb13136383958f20b580a821ca0/httptools-0.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eb844698d11433d2139bbeeb56499102143beb582bd6c194e3ba69c22f25c274", size = 440175, upload-time = "2025-10-10T03:54:35.942Z" }, + { url = "https://files.pythonhosted.org/packages/6f/7e/b9287763159e700e335028bc1824359dc736fa9b829dacedace91a39b37e/httptools-0.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f65744d7a8bdb4bda5e1fa23e4ba16832860606fcc09d674d56e425e991539ec", size = 440310, upload-time = "2025-10-10T03:54:37.1Z" }, + { url = "https://files.pythonhosted.org/packages/b3/07/5b614f592868e07f5c94b1f301b5e14a21df4e8076215a3bccb830a687d8/httptools-0.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:135fbe974b3718eada677229312e97f3b31f8a9c8ffa3ae6f565bf808d5b6bcb", size = 86875, upload-time = "2025-10-10T03:54:38.421Z" }, + { url = "https://files.pythonhosted.org/packages/53/7f/403e5d787dc4942316e515e949b0c8a013d84078a915910e9f391ba9b3ed/httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5", size = 206280, upload-time = "2025-10-10T03:54:39.274Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0d/7f3fd28e2ce311ccc998c388dd1c53b18120fda3b70ebb022b135dc9839b/httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5", size = 110004, upload-time = "2025-10-10T03:54:40.403Z" }, + { url = "https://files.pythonhosted.org/packages/84/a6/b3965e1e146ef5762870bbe76117876ceba51a201e18cc31f5703e454596/httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03", size = 517655, upload-time = "2025-10-10T03:54:41.347Z" }, + { url = "https://files.pythonhosted.org/packages/11/7d/71fee6f1844e6fa378f2eddde6c3e41ce3a1fb4b2d81118dd544e3441ec0/httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2", size = 511440, upload-time = "2025-10-10T03:54:42.452Z" }, + { url = "https://files.pythonhosted.org/packages/22/a5/079d216712a4f3ffa24af4a0381b108aa9c45b7a5cc6eb141f81726b1823/httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362", size = 495186, upload-time = "2025-10-10T03:54:43.937Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/025ad7b65278745dee3bd0ebf9314934c4592560878308a6121f7f812084/httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c", size = 499192, upload-time = "2025-10-10T03:54:45.003Z" }, + { url = "https://files.pythonhosted.org/packages/6d/de/40a8f202b987d43afc4d54689600ff03ce65680ede2f31df348d7f368b8f/httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321", size = 86694, upload-time = "2025-10-10T03:54:45.923Z" }, + { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" }, + { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" }, + { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" }, + { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" }, + { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" }, + { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" }, + { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" }, + { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" }, + { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4a/a548bdfae6369c0d078bab5769f7b66f17f1bfaa6fa28f81d6be6959066b/httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b", size = 470831, upload-time = "2025-10-10T03:54:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" }, + { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" }, + { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.34.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/c9/bdbe19339f76d12985bc03572f330a01a93c04dffecaaea3061bdd7fb892/huggingface_hub-0.34.4.tar.gz", hash = "sha256:a4228daa6fb001be3f4f4bdaf9a0db00e1739235702848df00885c9b5742c85c", size = 459768, upload-time = "2025-08-08T09:14:52.365Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl", hash = "sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a", size = 561452, upload-time = "2025-08-08T09:14:50.159Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, +] + +[[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 = "libusb-package" +version = "1.0.26.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-resources" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/bf/3fe9d322e2dcd0437ae2bd6a039117965702ed473ca59d2d6a1c39838009/libusb_package-1.0.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:60e15d7d3e4aab31794da95641bc28c4ffec9e24f50891ce33f75794b8f531f3", size = 63864, upload-time = "2025-04-01T12:59:14.567Z" }, + { url = "https://files.pythonhosted.org/packages/bc/70/df0348c11e6aaead4a66cc59840e102ddf64baf8e4b2c1ad5cff1ca83554/libusb_package-1.0.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d93a6137609cf72dc5db69bc337ddf96520231e395beeff69fa77a923090003", size = 59502, upload-time = "2025-04-01T12:59:15.863Z" }, + { url = "https://files.pythonhosted.org/packages/27/67/6c84eebc9fcdf7f26704b5d32b51b3ee5bf4e9090d61286941257bdc8702/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fafb69c5fd42b241fbd20493d014328c507d34e1b7ceb883a20ef14565b26898", size = 70247, upload-time = "2025-04-01T14:53:07.606Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/cbcc42ca4b3d8778bf081b96e6e6288a437d82a4cc4e9b982bef40a88856/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c206cd8a30565a0cede3ba426929e70a37e7b769e41a5ac7f00ca6737dc5d", size = 74537, upload-time = "2025-04-01T14:53:08.61Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0f/fd203fb1fa5eda1d446f345d84205f23533767e6ef837a7c77a2599d5783/libusb_package-1.0.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a2041331c087d5887969405837f86c8422120fe9ba3e6faa44bf4810f07b71", size = 70653, upload-time = "2025-04-01T14:53:09.576Z" }, + { url = "https://files.pythonhosted.org/packages/79/ef/dcc682cb4b29c4d4cdb23df65825c6276753184f6a7b4338c54a59a54c20/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:48b536a1279ee0dbf70b898cffd16cd661774d2c8bbec8ff7178a5bc20196af3", size = 71859, upload-time = "2025-04-01T14:53:10.987Z" }, + { url = "https://files.pythonhosted.org/packages/62/4d/323d5ac4ba339362e4b148c291fbc6e7ee04c6395d5fec967b32432db5c5/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3f273e33ff1810242f81ea3a0286e25887d99d99019ba83e08be0d1ca456cc05", size = 76476, upload-time = "2025-04-01T14:53:12.019Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3b/506db7f6cbe5dc2f38c14b272b8faf4d43e5559ac99d4dce1a41026ec925/libusb_package-1.0.26.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:67476093601e1ea58a6130426795b906acd8d18d51c84e29a3a69548a5dfcf5d", size = 71037, upload-time = "2025-04-01T14:53:13.42Z" }, + { url = "https://files.pythonhosted.org/packages/3e/40/2538763c06e07bbbe0a5c8830779ef1ed1cea845264a91973bf31b9ecce5/libusb_package-1.0.26.3-cp311-cp311-win32.whl", hash = "sha256:8f3eed2852ee4f08847a221749a98d0f4f3962f8bed967e2253327db1171ba60", size = 77642, upload-time = "2025-04-01T12:58:03.106Z" }, + { url = "https://files.pythonhosted.org/packages/a4/46/0cd5ea91c5bbe6293c0936c96915051e31750f72e9556718af666af3fe45/libusb_package-1.0.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:b48b5f5b17c7ac5e315e233f9ee801f730aac6183eb53a3226b01245d7bcfe00", size = 90592, upload-time = "2025-04-01T12:58:04.103Z" }, + { url = "https://files.pythonhosted.org/packages/2e/f6/83e13936b5799360eae8f0e31b5b298dd092451b91136d7cd13852777954/libusb_package-1.0.26.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c9404298485762a4e73b416e8a3208d33aa3274fb9b870c2a1cacba7e2918f19", size = 62045, upload-time = "2025-04-01T12:59:16.817Z" }, + { url = "https://files.pythonhosted.org/packages/33/97/86ed73880b6734c9383be5f34061b541e8fe5bd0303580b1f5abe2962d58/libusb_package-1.0.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8126f6711318dad4cb2805ea20cd47b895a847207087d8fdb032e082dd7a2e24", size = 59502, upload-time = "2025-04-01T12:59:17.72Z" }, + { url = "https://files.pythonhosted.org/packages/95/f7/27b67b8fe63450abf0b0b66aacf75d5d64cdf30317e214409ceb534f34b4/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11c219366e4a2368117b9a9807261f3506b5623531f8b8ce41af5bbaec8156a0", size = 70247, upload-time = "2025-04-01T14:53:14.387Z" }, + { url = "https://files.pythonhosted.org/packages/8c/11/613543f9c6dab5a82eefd0c78d52d08b5d9eb93a0362151fbedf74b32541/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8809a50d8ab84297344c54e862027090c0d73b14abef843a8b5f783313f49457", size = 74537, upload-time = "2025-04-01T14:53:15.345Z" }, + { url = "https://files.pythonhosted.org/packages/f0/43/5a2331615693b56221a902869fb2094d9a0b9a764a8706c8ba16e915f77c/libusb_package-1.0.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a83067c3dfdbb3856badb4532eaea22e8502b52ce4245f5ab46acf93d7fbd471", size = 70652, upload-time = "2025-04-01T14:53:16.319Z" }, + { url = "https://files.pythonhosted.org/packages/44/1a/186d4ec86421b69feb45e214edb5301fbcb9e8dc9df963678aeff1a447d5/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b56be087ea9cde8e50fb02740a4f0cefb6f63c61ac2e7812a9244487614a3973", size = 71860, upload-time = "2025-04-01T14:53:17.87Z" }, + { url = "https://files.pythonhosted.org/packages/4b/3c/8cebdad822d7bfcb683a77d5fd113fbc6f72516cfb7c1c3a274fefafa8e9/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea0f6bf40e54b1671e763e40c9dbed46bf7f596a4cd98b7c827e147f176d8c97", size = 76476, upload-time = "2025-04-01T14:53:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/49/5f/30c625b6c4ecd14871644c1d16e97d7c971f82a0f87a9cfa81022f85bcfc/libusb_package-1.0.26.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b40f77df991c6db8621de9575504886eca03a00277e521a4d64b66cbef8f6997", size = 71037, upload-time = "2025-04-01T14:53:21.359Z" }, + { url = "https://files.pythonhosted.org/packages/7f/e9/3aa3ff3242867b7f22ee3ce28d0e93ff88547f170ca1b8a6edc59660d974/libusb_package-1.0.26.3-cp312-cp312-win32.whl", hash = "sha256:6eee99c9fde137443869c8604d0c01b2127a9545ebc59d06a3376cf1d891e786", size = 77642, upload-time = "2025-04-01T12:58:05.471Z" }, + { url = "https://files.pythonhosted.org/packages/15/0e/913ddb1849f828fc385438874c34541939d9b06c0e5616f48f24cddd24de/libusb_package-1.0.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:5e09c0b6b3cd475841cffe78e46e91df58f0c6c02ea105ea1a4d0755a07c8006", size = 90593, upload-time = "2025-04-01T12:58:06.798Z" }, + { url = "https://files.pythonhosted.org/packages/b4/b8/23bc7f3f53b4a5b1027c721ec3eb42324ca1ec56355f0d0851307adc7c6c/libusb_package-1.0.26.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:04c4505e2ca68d3dc6938f116ff9bf82daffb06c1a97aba08293a84715a998da", size = 62045, upload-time = "2025-04-01T12:59:18.698Z" }, + { url = "https://files.pythonhosted.org/packages/a2/f8/e3be96d0604070488ddc5ce5af1976992e1f4a00e6441c94edf807f274d5/libusb_package-1.0.26.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4961cdb3c622aa9f858d3e4f99a58ce5e822a97c22abc77040fd806cb5fa4c66", size = 59502, upload-time = "2025-04-01T12:59:19.632Z" }, + { url = "https://files.pythonhosted.org/packages/24/d5/df1508df5e6776ac8a09a2858991df29bc96ea6a0d1f90240b1c4d59b45d/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16182670e0c23235521b447054c5a01600bd8f1eed3bb08eedbb0d9f8a43249f", size = 70247, upload-time = "2025-04-01T14:53:22.328Z" }, + { url = "https://files.pythonhosted.org/packages/65/01/4cc9eed12b9214c088cfa8055ece3b1db970404400be9d7e3dda68d198f2/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75ea57b2cc903d28ec1d4b909902df442cbf21949d80d5b3d8b9dac36ac45d1a", size = 74537, upload-time = "2025-04-01T14:53:23.306Z" }, + { url = "https://files.pythonhosted.org/packages/99/83/9eb317f706f588f4b6679bddb8abee3b115ce53dc3fa560cca59910f8807/libusb_package-1.0.26.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d30b51b128ef5112fff73268b4696fea00b5676b3f39a5ee859bd76cb3ace5", size = 70651, upload-time = "2025-04-01T14:53:24.33Z" }, + { url = "https://files.pythonhosted.org/packages/22/49/85d3b307b4a20cf0150ab381e6e0385e5b78cb5dede8bade0a2d655d3fd3/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5c098dcfcfa8000cab42f33e19628c8fdb16111670db381048b2993651f2413b", size = 71860, upload-time = "2025-04-01T14:53:25.752Z" }, + { url = "https://files.pythonhosted.org/packages/da/7a/2271a5ae542d9036d9254415ae745d5c5d01a08d56d13054b2439bf9d392/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:93169aeab0657255fe6c9f757cf408f559db13827a1d122fc89239994d7d51f1", size = 76477, upload-time = "2025-04-01T14:53:27.564Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9d/d06d53994bb164564ec142ef631a4afa31e324994cf223f169ecca127f3a/libusb_package-1.0.26.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:63257653ee1ee06aa836e942f4bb89a1d7a0c6ae3d6183647a9011e585ffa1e3", size = 71036, upload-time = "2025-04-01T14:53:29.011Z" }, + { url = "https://files.pythonhosted.org/packages/32/3d/97f775a1d582548b1eb2a42444c58813e5fd93d568fc3b9ace59f64df527/libusb_package-1.0.26.3-cp313-cp313-win32.whl", hash = "sha256:05db4cc801db2e6373a808725748a701509f9450fecf393fbebab61c45d50b50", size = 77642, upload-time = "2025-04-01T12:58:07.774Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c4/d5234607697ca60593fbef88428a154317ac31f5c58ee23337b8a9360e91/libusb_package-1.0.26.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cd4aec825dac2b4fa5d23b37f6d72e63a1127987e5a073dabeb7b73528623a3", size = 90593, upload-time = "2025-04-01T12:58:08.676Z" }, +] + +[[package]] +name = "log-throttling" +version = "0.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/be/09fda383d82a7b91f12ff5002bc909e101769c802ff3b1d2cb9f533d1a2f/log-throttling-0.0.3.tar.gz", hash = "sha256:df714e1448cd9cb4c916cf668ab88323032e61ece733548708d996ecf63190b9", size = 3533, upload-time = "2022-03-08T16:29:23.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/6e/995ebad4ab08250b4afe1d91fe3086b863ed9bb74539d90485250a50f08a/log_throttling-0.0.3-py3-none-any.whl", hash = "sha256:a82508f489dd44a60b737a0339c784dd8ee2b9db16bdcf587a8ae1012a7f6ffc", size = 4081, upload-time = "2022-03-08T16:29:21.443Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/9e/5c727587644d67b2ed479041e4b1c58e30afc011e3d45d25bbe35781217c/multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc", size = 76604, upload-time = "2025-10-06T14:48:54.277Z" }, + { url = "https://files.pythonhosted.org/packages/17/e4/67b5c27bd17c085a5ea8f1ec05b8a3e5cba0ca734bfcad5560fb129e70ca/multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721", size = 44715, upload-time = "2025-10-06T14:48:55.445Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/866a5d77be6ea435711bef2a4291eed11032679b6b28b56b4776ab06ba3e/multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6", size = 44332, upload-time = "2025-10-06T14:48:56.706Z" }, + { url = "https://files.pythonhosted.org/packages/31/61/0c2d50241ada71ff61a79518db85ada85fdabfcf395d5968dae1cbda04e5/multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c", size = 245212, upload-time = "2025-10-06T14:48:58.042Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e0/919666a4e4b57fff1b57f279be1c9316e6cdc5de8a8b525d76f6598fefc7/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7", size = 246671, upload-time = "2025-10-06T14:49:00.004Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cc/d027d9c5a520f3321b65adea289b965e7bcbd2c34402663f482648c716ce/multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7", size = 225491, upload-time = "2025-10-06T14:49:01.393Z" }, + { url = "https://files.pythonhosted.org/packages/75/c4/bbd633980ce6155a28ff04e6a6492dd3335858394d7bb752d8b108708558/multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9", size = 257322, upload-time = "2025-10-06T14:49:02.745Z" }, + { url = "https://files.pythonhosted.org/packages/4c/6d/d622322d344f1f053eae47e033b0b3f965af01212de21b10bcf91be991fb/multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8", size = 254694, upload-time = "2025-10-06T14:49:04.15Z" }, + { url = "https://files.pythonhosted.org/packages/a8/9f/78f8761c2705d4c6d7516faed63c0ebdac569f6db1bef95e0d5218fdc146/multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd", size = 246715, upload-time = "2025-10-06T14:49:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/950818e04f91b9c2b95aab3d923d9eabd01689d0dcd889563988e9ea0fd8/multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb", size = 243189, upload-time = "2025-10-06T14:49:07.37Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3d/77c79e1934cad2ee74991840f8a0110966d9599b3af95964c0cd79bb905b/multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6", size = 237845, upload-time = "2025-10-06T14:49:08.759Z" }, + { url = "https://files.pythonhosted.org/packages/63/1b/834ce32a0a97a3b70f86437f685f880136677ac00d8bce0027e9fd9c2db7/multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2", size = 246374, upload-time = "2025-10-06T14:49:10.574Z" }, + { url = "https://files.pythonhosted.org/packages/23/ef/43d1c3ba205b5dec93dc97f3fba179dfa47910fc73aaaea4f7ceb41cec2a/multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff", size = 253345, upload-time = "2025-10-06T14:49:12.331Z" }, + { url = "https://files.pythonhosted.org/packages/6b/03/eaf95bcc2d19ead522001f6a650ef32811aa9e3624ff0ad37c445c7a588c/multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b", size = 246940, upload-time = "2025-10-06T14:49:13.821Z" }, + { url = "https://files.pythonhosted.org/packages/e8/df/ec8a5fd66ea6cd6f525b1fcbb23511b033c3e9bc42b81384834ffa484a62/multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34", size = 242229, upload-time = "2025-10-06T14:49:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a2/59b405d59fd39ec86d1142630e9049243015a5f5291ba49cadf3c090c541/multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff", size = 41308, upload-time = "2025-10-06T14:49:16.871Z" }, + { url = "https://files.pythonhosted.org/packages/32/0f/13228f26f8b882c34da36efa776c3b7348455ec383bab4a66390e42963ae/multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81", size = 46037, upload-time = "2025-10-06T14:49:18.457Z" }, + { url = "https://files.pythonhosted.org/packages/84/1f/68588e31b000535a3207fd3c909ebeec4fb36b52c442107499c18a896a2a/multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912", size = 43023, upload-time = "2025-10-06T14:49:19.648Z" }, + { url = "https://files.pythonhosted.org/packages/c2/9e/9f61ac18d9c8b475889f32ccfa91c9f59363480613fc807b6e3023d6f60b/multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184", size = 76877, upload-time = "2025-10-06T14:49:20.884Z" }, + { url = "https://files.pythonhosted.org/packages/38/6f/614f09a04e6184f8824268fce4bc925e9849edfa654ddd59f0b64508c595/multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45", size = 45467, upload-time = "2025-10-06T14:49:22.054Z" }, + { url = "https://files.pythonhosted.org/packages/b3/93/c4f67a436dd026f2e780c433277fff72be79152894d9fc36f44569cab1a6/multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa", size = 43834, upload-time = "2025-10-06T14:49:23.566Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f5/013798161ca665e4a422afbc5e2d9e4070142a9ff8905e482139cd09e4d0/multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7", size = 250545, upload-time = "2025-10-06T14:49:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/71/2f/91dbac13e0ba94669ea5119ba267c9a832f0cb65419aca75549fcf09a3dc/multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e", size = 258305, upload-time = "2025-10-06T14:49:26.778Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b0/754038b26f6e04488b48ac621f779c341338d78503fb45403755af2df477/multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546", size = 242363, upload-time = "2025-10-06T14:49:28.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/15/9da40b9336a7c9fa606c4cf2ed80a649dffeb42b905d4f63a1d7eb17d746/multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4", size = 268375, upload-time = "2025-10-06T14:49:29.96Z" }, + { url = "https://files.pythonhosted.org/packages/82/72/c53fcade0cc94dfaad583105fd92b3a783af2091eddcb41a6d5a52474000/multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1", size = 269346, upload-time = "2025-10-06T14:49:31.404Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e2/9baffdae21a76f77ef8447f1a05a96ec4bc0a24dae08767abc0a2fe680b8/multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d", size = 256107, upload-time = "2025-10-06T14:49:32.974Z" }, + { url = "https://files.pythonhosted.org/packages/3c/06/3f06f611087dc60d65ef775f1fb5aca7c6d61c6db4990e7cda0cef9b1651/multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304", size = 253592, upload-time = "2025-10-06T14:49:34.52Z" }, + { url = "https://files.pythonhosted.org/packages/20/24/54e804ec7945b6023b340c412ce9c3f81e91b3bf5fa5ce65558740141bee/multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12", size = 251024, upload-time = "2025-10-06T14:49:35.956Z" }, + { url = "https://files.pythonhosted.org/packages/14/48/011cba467ea0b17ceb938315d219391d3e421dfd35928e5dbdc3f4ae76ef/multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62", size = 251484, upload-time = "2025-10-06T14:49:37.631Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2f/919258b43bb35b99fa127435cfb2d91798eb3a943396631ef43e3720dcf4/multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0", size = 263579, upload-time = "2025-10-06T14:49:39.502Z" }, + { url = "https://files.pythonhosted.org/packages/31/22/a0e884d86b5242b5a74cf08e876bdf299e413016b66e55511f7a804a366e/multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a", size = 259654, upload-time = "2025-10-06T14:49:41.32Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/17e10e1b5c5f5a40f2fcbb45953c9b215f8a4098003915e46a93f5fcaa8f/multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8", size = 251511, upload-time = "2025-10-06T14:49:46.021Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9a/201bb1e17e7af53139597069c375e7b0dcbd47594604f65c2d5359508566/multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4", size = 41895, upload-time = "2025-10-06T14:49:48.718Z" }, + { url = "https://files.pythonhosted.org/packages/46/e2/348cd32faad84eaf1d20cce80e2bb0ef8d312c55bca1f7fa9865e7770aaf/multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b", size = 46073, upload-time = "2025-10-06T14:49:50.28Z" }, + { url = "https://files.pythonhosted.org/packages/25/ec/aad2613c1910dce907480e0c3aa306905830f25df2e54ccc9dea450cb5aa/multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec", size = 43226, upload-time = "2025-10-06T14:49:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/d2/86/33272a544eeb36d66e4d9a920602d1a2f57d4ebea4ef3cdfe5a912574c95/multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6", size = 76135, upload-time = "2025-10-06T14:49:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/1c/eb97db117a1ebe46d457a3d235a7b9d2e6dcab174f42d1b67663dd9e5371/multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159", size = 45117, upload-time = "2025-10-06T14:49:55.82Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d8/6c3442322e41fb1dd4de8bd67bfd11cd72352ac131f6368315617de752f1/multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca", size = 43472, upload-time = "2025-10-06T14:49:57.048Z" }, + { url = "https://files.pythonhosted.org/packages/75/3f/e2639e80325af0b6c6febdf8e57cc07043ff15f57fa1ef808f4ccb5ac4cd/multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8", size = 249342, upload-time = "2025-10-06T14:49:58.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cc/84e0585f805cbeaa9cbdaa95f9a3d6aed745b9d25700623ac89a6ecff400/multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60", size = 257082, upload-time = "2025-10-06T14:49:59.89Z" }, + { url = "https://files.pythonhosted.org/packages/b0/9c/ac851c107c92289acbbf5cfb485694084690c1b17e555f44952c26ddc5bd/multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4", size = 240704, upload-time = "2025-10-06T14:50:01.485Z" }, + { url = "https://files.pythonhosted.org/packages/50/cc/5f93e99427248c09da95b62d64b25748a5f5c98c7c2ab09825a1d6af0e15/multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f", size = 266355, upload-time = "2025-10-06T14:50:02.955Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0c/2ec1d883ceb79c6f7f6d7ad90c919c898f5d1c6ea96d322751420211e072/multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf", size = 267259, upload-time = "2025-10-06T14:50:04.446Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2d/f0b184fa88d6630aa267680bdb8623fb69cb0d024b8c6f0d23f9a0f406d3/multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32", size = 254903, upload-time = "2025-10-06T14:50:05.98Z" }, + { url = "https://files.pythonhosted.org/packages/06/c9/11ea263ad0df7dfabcad404feb3c0dd40b131bc7f232d5537f2fb1356951/multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036", size = 252365, upload-time = "2025-10-06T14:50:07.511Z" }, + { url = "https://files.pythonhosted.org/packages/41/88/d714b86ee2c17d6e09850c70c9d310abac3d808ab49dfa16b43aba9d53fd/multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec", size = 250062, upload-time = "2025-10-06T14:50:09.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/fe/ad407bb9e818c2b31383f6131ca19ea7e35ce93cf1310fce69f12e89de75/multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e", size = 249683, upload-time = "2025-10-06T14:50:10.714Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/a89abdb0229e533fb925e7c6e5c40201c2873efebc9abaf14046a4536ee6/multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64", size = 261254, upload-time = "2025-10-06T14:50:12.28Z" }, + { url = "https://files.pythonhosted.org/packages/8d/aa/0e2b27bd88b40a4fb8dc53dd74eecac70edaa4c1dd0707eb2164da3675b3/multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd", size = 257967, upload-time = "2025-10-06T14:50:14.16Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8e/0c67b7120d5d5f6d874ed85a085f9dc770a7f9d8813e80f44a9fec820bb7/multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288", size = 250085, upload-time = "2025-10-06T14:50:15.639Z" }, + { url = "https://files.pythonhosted.org/packages/ba/55/b73e1d624ea4b8fd4dd07a3bb70f6e4c7c6c5d9d640a41c6ffe5cdbd2a55/multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17", size = 41713, upload-time = "2025-10-06T14:50:17.066Z" }, + { url = "https://files.pythonhosted.org/packages/32/31/75c59e7d3b4205075b4c183fa4ca398a2daf2303ddf616b04ae6ef55cffe/multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390", size = 45915, upload-time = "2025-10-06T14:50:18.264Z" }, + { url = "https://files.pythonhosted.org/packages/31/2a/8987831e811f1184c22bc2e45844934385363ee61c0a2dcfa8f71b87e608/multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e", size = 43077, upload-time = "2025-10-06T14:50:19.853Z" }, + { url = "https://files.pythonhosted.org/packages/e8/68/7b3a5170a382a340147337b300b9eb25a9ddb573bcdfff19c0fa3f31ffba/multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00", size = 83114, upload-time = "2025-10-06T14:50:21.223Z" }, + { url = "https://files.pythonhosted.org/packages/55/5c/3fa2d07c84df4e302060f555bbf539310980362236ad49f50eeb0a1c1eb9/multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb", size = 48442, upload-time = "2025-10-06T14:50:22.871Z" }, + { url = "https://files.pythonhosted.org/packages/fc/56/67212d33239797f9bd91962bb899d72bb0f4c35a8652dcdb8ed049bef878/multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b", size = 46885, upload-time = "2025-10-06T14:50:24.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/d1/908f896224290350721597a61a69cd19b89ad8ee0ae1f38b3f5cd12ea2ac/multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c", size = 242588, upload-time = "2025-10-06T14:50:25.716Z" }, + { url = "https://files.pythonhosted.org/packages/ab/67/8604288bbd68680eee0ab568fdcb56171d8b23a01bcd5cb0c8fedf6e5d99/multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1", size = 249966, upload-time = "2025-10-06T14:50:28.192Z" }, + { url = "https://files.pythonhosted.org/packages/20/33/9228d76339f1ba51e3efef7da3ebd91964d3006217aae13211653193c3ff/multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b", size = 228618, upload-time = "2025-10-06T14:50:29.82Z" }, + { url = "https://files.pythonhosted.org/packages/f8/2d/25d9b566d10cab1c42b3b9e5b11ef79c9111eaf4463b8c257a3bd89e0ead/multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5", size = 257539, upload-time = "2025-10-06T14:50:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b1/8d1a965e6637fc33de3c0d8f414485c2b7e4af00f42cab3d84e7b955c222/multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad", size = 256345, upload-time = "2025-10-06T14:50:33.26Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/06b5a8adbdeedada6f4fb8d8f193d44a347223b11939b42953eeb6530b6b/multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c", size = 247934, upload-time = "2025-10-06T14:50:34.808Z" }, + { url = "https://files.pythonhosted.org/packages/8f/31/b2491b5fe167ca044c6eb4b8f2c9f3b8a00b24c432c365358eadac5d7625/multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5", size = 245243, upload-time = "2025-10-06T14:50:36.436Z" }, + { url = "https://files.pythonhosted.org/packages/61/1a/982913957cb90406c8c94f53001abd9eafc271cb3e70ff6371590bec478e/multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10", size = 235878, upload-time = "2025-10-06T14:50:37.953Z" }, + { url = "https://files.pythonhosted.org/packages/be/c0/21435d804c1a1cf7a2608593f4d19bca5bcbd7a81a70b253fdd1c12af9c0/multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754", size = 243452, upload-time = "2025-10-06T14:50:39.574Z" }, + { url = "https://files.pythonhosted.org/packages/54/0a/4349d540d4a883863191be6eb9a928846d4ec0ea007d3dcd36323bb058ac/multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c", size = 252312, upload-time = "2025-10-06T14:50:41.612Z" }, + { url = "https://files.pythonhosted.org/packages/26/64/d5416038dbda1488daf16b676e4dbfd9674dde10a0cc8f4fc2b502d8125d/multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762", size = 246935, upload-time = "2025-10-06T14:50:43.972Z" }, + { url = "https://files.pythonhosted.org/packages/9f/8c/8290c50d14e49f35e0bd4abc25e1bc7711149ca9588ab7d04f886cdf03d9/multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6", size = 243385, upload-time = "2025-10-06T14:50:45.648Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777, upload-time = "2025-10-06T14:50:47.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104, upload-time = "2025-10-06T14:50:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503, upload-time = "2025-10-06T14:50:50.16Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128, upload-time = "2025-10-06T14:50:51.92Z" }, + { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410, upload-time = "2025-10-06T14:50:53.275Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205, upload-time = "2025-10-06T14:50:54.911Z" }, + { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084, upload-time = "2025-10-06T14:50:56.369Z" }, + { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667, upload-time = "2025-10-06T14:50:57.991Z" }, + { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590, upload-time = "2025-10-06T14:50:59.589Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112, upload-time = "2025-10-06T14:51:01.183Z" }, + { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194, upload-time = "2025-10-06T14:51:02.794Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510, upload-time = "2025-10-06T14:51:04.724Z" }, + { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395, upload-time = "2025-10-06T14:51:06.306Z" }, + { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520, upload-time = "2025-10-06T14:51:08.091Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479, upload-time = "2025-10-06T14:51:10.365Z" }, + { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903, upload-time = "2025-10-06T14:51:12.466Z" }, + { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333, upload-time = "2025-10-06T14:51:14.48Z" }, + { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411, upload-time = "2025-10-06T14:51:16.072Z" }, + { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940, upload-time = "2025-10-06T14:51:17.544Z" }, + { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087, upload-time = "2025-10-06T14:51:18.875Z" }, + { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368, upload-time = "2025-10-06T14:51:20.225Z" }, + { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326, upload-time = "2025-10-06T14:51:21.588Z" }, + { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065, upload-time = "2025-10-06T14:51:22.93Z" }, + { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475, upload-time = "2025-10-06T14:51:24.352Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324, upload-time = "2025-10-06T14:51:25.822Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877, upload-time = "2025-10-06T14:51:27.604Z" }, + { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824, upload-time = "2025-10-06T14:51:29.664Z" }, + { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558, upload-time = "2025-10-06T14:51:31.684Z" }, + { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339, upload-time = "2025-10-06T14:51:33.699Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895, upload-time = "2025-10-06T14:51:36.189Z" }, + { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862, upload-time = "2025-10-06T14:51:41.291Z" }, + { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376, upload-time = "2025-10-06T14:51:43.55Z" }, + { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272, upload-time = "2025-10-06T14:51:45.265Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774, upload-time = "2025-10-06T14:51:46.836Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731, upload-time = "2025-10-06T14:51:48.541Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193, upload-time = "2025-10-06T14:51:50.355Z" }, + { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023, upload-time = "2025-10-06T14:51:51.883Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507, upload-time = "2025-10-06T14:51:53.672Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804, upload-time = "2025-10-06T14:51:55.415Z" }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, +] + +[[package]] +name = "numpy" +version = "2.3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/77/84dd1d2e34d7e2792a236ba180b5e8fcc1e3e414e761ce0253f63d7f572e/numpy-2.3.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de5672f4a7b200c15a4127042170a694d4df43c992948f5e1af57f0174beed10", size = 17034641, upload-time = "2025-11-16T22:49:19.336Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ea/25e26fa5837106cde46ae7d0b667e20f69cbbc0efd64cba8221411ab26ae/numpy-2.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acfd89508504a19ed06ef963ad544ec6664518c863436306153e13e94605c218", size = 12528324, upload-time = "2025-11-16T22:49:22.582Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1a/e85f0eea4cf03d6a0228f5c0256b53f2df4bc794706e7df019fc622e47f1/numpy-2.3.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ffe22d2b05504f786c867c8395de703937f934272eb67586817b46188b4ded6d", size = 5356872, upload-time = "2025-11-16T22:49:25.408Z" }, + { url = "https://files.pythonhosted.org/packages/5c/bb/35ef04afd567f4c989c2060cde39211e4ac5357155c1833bcd1166055c61/numpy-2.3.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:872a5cf366aec6bb1147336480fef14c9164b154aeb6542327de4970282cd2f5", size = 6893148, upload-time = "2025-11-16T22:49:27.549Z" }, + { url = "https://files.pythonhosted.org/packages/f2/2b/05bbeb06e2dff5eab512dfc678b1cc5ee94d8ac5956a0885c64b6b26252b/numpy-2.3.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3095bdb8dd297e5920b010e96134ed91d852d81d490e787beca7e35ae1d89cf7", size = 14557282, upload-time = "2025-11-16T22:49:30.964Z" }, + { url = "https://files.pythonhosted.org/packages/65/fb/2b23769462b34398d9326081fad5655198fcf18966fcb1f1e49db44fbf31/numpy-2.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cba086a43d54ca804ce711b2a940b16e452807acebe7852ff327f1ecd49b0d4", size = 16897903, upload-time = "2025-11-16T22:49:34.191Z" }, + { url = "https://files.pythonhosted.org/packages/ac/14/085f4cf05fc3f1e8aa95e85404e984ffca9b2275a5dc2b1aae18a67538b8/numpy-2.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cf9b429b21df6b99f4dee7a1218b8b7ffbbe7df8764dc0bd60ce8a0708fed1e", size = 16341672, upload-time = "2025-11-16T22:49:37.2Z" }, + { url = "https://files.pythonhosted.org/packages/6f/3b/1f73994904142b2aa290449b3bb99772477b5fd94d787093e4f24f5af763/numpy-2.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:396084a36abdb603546b119d96528c2f6263921c50df3c8fd7cb28873a237748", size = 18838896, upload-time = "2025-11-16T22:49:39.727Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b9/cf6649b2124f288309ffc353070792caf42ad69047dcc60da85ee85fea58/numpy-2.3.5-cp311-cp311-win32.whl", hash = "sha256:b0c7088a73aef3d687c4deef8452a3ac7c1be4e29ed8bf3b366c8111128ac60c", size = 6563608, upload-time = "2025-11-16T22:49:42.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/44/9fe81ae1dcc29c531843852e2874080dc441338574ccc4306b39e2ff6e59/numpy-2.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:a414504bef8945eae5f2d7cb7be2d4af77c5d1cb5e20b296c2c25b61dff2900c", size = 13078442, upload-time = "2025-11-16T22:49:43.99Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a7/f99a41553d2da82a20a2f22e93c94f928e4490bb447c9ff3c4ff230581d3/numpy-2.3.5-cp311-cp311-win_arm64.whl", hash = "sha256:0cd00b7b36e35398fa2d16af7b907b65304ef8bb4817a550e06e5012929830fa", size = 10458555, upload-time = "2025-11-16T22:49:47.092Z" }, + { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873, upload-time = "2025-11-16T22:49:49.84Z" }, + { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838, upload-time = "2025-11-16T22:49:52.863Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378, upload-time = "2025-11-16T22:49:55.055Z" }, + { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559, upload-time = "2025-11-16T22:49:57.371Z" }, + { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702, upload-time = "2025-11-16T22:49:59.632Z" }, + { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086, upload-time = "2025-11-16T22:50:02.127Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985, upload-time = "2025-11-16T22:50:04.536Z" }, + { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976, upload-time = "2025-11-16T22:50:07.557Z" }, + { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274, upload-time = "2025-11-16T22:50:10.746Z" }, + { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922, upload-time = "2025-11-16T22:50:12.811Z" }, + { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667, upload-time = "2025-11-16T22:50:16.16Z" }, + { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" }, + { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" }, + { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" }, + { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" }, + { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" }, + { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" }, + { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" }, + { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" }, + { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" }, + { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" }, + { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" }, + { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" }, + { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" }, + { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" }, + { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" }, + { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" }, + { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" }, + { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" }, + { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" }, + { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706, upload-time = "2025-11-16T22:51:19.558Z" }, + { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507, upload-time = "2025-11-16T22:51:22.492Z" }, + { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049, upload-time = "2025-11-16T22:51:25.171Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603, upload-time = "2025-11-16T22:51:27Z" }, + { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696, upload-time = "2025-11-16T22:51:29.402Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350, upload-time = "2025-11-16T22:51:32.167Z" }, + { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190, upload-time = "2025-11-16T22:51:35.403Z" }, + { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749, upload-time = "2025-11-16T22:51:39.698Z" }, + { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432, upload-time = "2025-11-16T22:51:42.476Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388, upload-time = "2025-11-16T22:51:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651, upload-time = "2025-11-16T22:51:47.749Z" }, + { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503, upload-time = "2025-11-16T22:51:50.443Z" }, + { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612, upload-time = "2025-11-16T22:51:53.609Z" }, + { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042, upload-time = "2025-11-16T22:51:56.213Z" }, + { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502, upload-time = "2025-11-16T22:51:58.584Z" }, + { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962, upload-time = "2025-11-16T22:52:01.698Z" }, + { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054, upload-time = "2025-11-16T22:52:04.267Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613, upload-time = "2025-11-16T22:52:08.651Z" }, + { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147, upload-time = "2025-11-16T22:52:11.453Z" }, + { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806, upload-time = "2025-11-16T22:52:14.641Z" }, + { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760, upload-time = "2025-11-16T22:52:17.975Z" }, + { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" }, + { url = "https://files.pythonhosted.org/packages/c6/65/f9dea8e109371ade9c782b4e4756a82edf9d3366bca495d84d79859a0b79/numpy-2.3.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f0963b55cdd70fad460fa4c1341f12f976bb26cb66021a5580329bd498988310", size = 16910689, upload-time = "2025-11-16T22:52:23.247Z" }, + { url = "https://files.pythonhosted.org/packages/00/4f/edb00032a8fb92ec0a679d3830368355da91a69cab6f3e9c21b64d0bb986/numpy-2.3.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4255143f5160d0de972d28c8f9665d882b5f61309d8362fdd3e103cf7bf010c", size = 12457053, upload-time = "2025-11-16T22:52:26.367Z" }, + { url = "https://files.pythonhosted.org/packages/16/a4/e8a53b5abd500a63836a29ebe145fc1ab1f2eefe1cfe59276020373ae0aa/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:a4b9159734b326535f4dd01d947f919c6eefd2d9827466a696c44ced82dfbc18", size = 5285635, upload-time = "2025-11-16T22:52:29.266Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2f/37eeb9014d9c8b3e9c55bc599c68263ca44fdbc12a93e45a21d1d56df737/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2feae0d2c91d46e59fcd62784a3a83b3fb677fead592ce51b5a6fbb4f95965ff", size = 6801770, upload-time = "2025-11-16T22:52:31.421Z" }, + { url = "https://files.pythonhosted.org/packages/7d/e4/68d2f474df2cb671b2b6c2986a02e520671295647dad82484cde80ca427b/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffac52f28a7849ad7576293c0cb7b9f08304e8f7d738a8cb8a90ec4c55a998eb", size = 14391768, upload-time = "2025-11-16T22:52:33.593Z" }, + { url = "https://files.pythonhosted.org/packages/b8/50/94ccd8a2b141cb50651fddd4f6a48874acb3c91c8f0842b08a6afc4b0b21/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63c0e9e7eea69588479ebf4a8a270d5ac22763cc5854e9a7eae952a3908103f7", size = 16729263, upload-time = "2025-11-16T22:52:36.369Z" }, + { url = "https://files.pythonhosted.org/packages/2d/ee/346fa473e666fe14c52fcdd19ec2424157290a032d4c41f98127bfb31ac7/numpy-2.3.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f16417ec91f12f814b10bafe79ef77e70113a2f5f7018640e7425ff979253425", size = 12967213, upload-time = "2025-11-16T22:52:39.38Z" }, +] + +[[package]] +name = "opencv-python" +version = "4.11.0.86" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/06/68c27a523103dad5837dc5b87e71285280c4f098c60e4fe8a8db6486ab09/opencv-python-4.11.0.86.tar.gz", hash = "sha256:03d60ccae62304860d232272e4a4fda93c39d595780cb40b161b310244b736a4", size = 95171956, upload-time = "2025-01-16T13:52:24.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/4d/53b30a2a3ac1f75f65a59eb29cf2ee7207ce64867db47036ad61743d5a23/opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:432f67c223f1dc2824f5e73cdfcd9db0efc8710647d4e813012195dc9122a52a", size = 37326322, upload-time = "2025-01-16T13:52:25.887Z" }, + { url = "https://files.pythonhosted.org/packages/3b/84/0a67490741867eacdfa37bc18df96e08a9d579583b419010d7f3da8ff503/opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:9d05ef13d23fe97f575153558653e2d6e87103995d54e6a35db3f282fe1f9c66", size = 56723197, upload-time = "2025-01-16T13:55:21.222Z" }, + { url = "https://files.pythonhosted.org/packages/f3/bd/29c126788da65c1fb2b5fb621b7fed0ed5f9122aa22a0868c5e2c15c6d23/opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b92ae2c8852208817e6776ba1ea0d6b1e0a1b5431e971a2a0ddd2a8cc398202", size = 42230439, upload-time = "2025-01-16T13:51:35.822Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8b/90eb44a40476fa0e71e05a0283947cfd74a5d36121a11d926ad6f3193cc4/opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b02611523803495003bd87362db3e1d2a0454a6a63025dc6658a9830570aa0d", size = 62986597, upload-time = "2025-01-16T13:52:08.836Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/1d5941a9dde095468b288d989ff6539dd69cd429dbf1b9e839013d21b6f0/opencv_python-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:810549cb2a4aedaa84ad9a1c92fbfdfc14090e2749cedf2c1589ad8359aa169b", size = 29384337, upload-time = "2025-01-16T13:52:13.549Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/f1c30a92854540bf789e9cd5dde7ef49bbe63f855b85a2e6b3db8135c591/opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec", size = 39488044, upload-time = "2025-01-16T13:52:21.928Z" }, +] + +[[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 = "pip" +version = "25.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, +] + +[[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 = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, + { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, + { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" }, + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, + { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, + { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, + { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, + { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, + { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, + { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, + { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, + { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, + { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, + { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + +[[package]] +name = "psutil" +version = "7.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/88/bdd0a41e5857d5d703287598cbf08dad90aed56774ea52ae071bae9071b6/psutil-7.1.3.tar.gz", hash = "sha256:6c86281738d77335af7aec228328e944b30930899ea760ecf33a4dba66be5e74", size = 489059, upload-time = "2025-11-02T12:25:54.619Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/93/0c49e776b8734fef56ec9c5c57f923922f2cf0497d62e0f419465f28f3d0/psutil-7.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0005da714eee687b4b8decd3d6cc7c6db36215c9e74e5ad2264b90c3df7d92dc", size = 239751, upload-time = "2025-11-02T12:25:58.161Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8d/b31e39c769e70780f007969815195a55c81a63efebdd4dbe9e7a113adb2f/psutil-7.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:19644c85dcb987e35eeeaefdc3915d059dac7bd1167cdcdbf27e0ce2df0c08c0", size = 240368, upload-time = "2025-11-02T12:26:00.491Z" }, + { url = "https://files.pythonhosted.org/packages/62/61/23fd4acc3c9eebbf6b6c78bcd89e5d020cfde4acf0a9233e9d4e3fa698b4/psutil-7.1.3-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95ef04cf2e5ba0ab9eaafc4a11eaae91b44f4ef5541acd2ee91d9108d00d59a7", size = 287134, upload-time = "2025-11-02T12:26:02.613Z" }, + { url = "https://files.pythonhosted.org/packages/30/1c/f921a009ea9ceb51aa355cb0cc118f68d354db36eae18174bab63affb3e6/psutil-7.1.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1068c303be3a72f8e18e412c5b2a8f6d31750fb152f9cb106b54090296c9d251", size = 289904, upload-time = "2025-11-02T12:26:05.207Z" }, + { url = "https://files.pythonhosted.org/packages/a6/82/62d68066e13e46a5116df187d319d1724b3f437ddd0f958756fc052677f4/psutil-7.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:18349c5c24b06ac5612c0428ec2a0331c26443d259e2a0144a9b24b4395b58fa", size = 249642, upload-time = "2025-11-02T12:26:07.447Z" }, + { url = "https://files.pythonhosted.org/packages/df/ad/c1cd5fe965c14a0392112f68362cfceb5230819dbb5b1888950d18a11d9f/psutil-7.1.3-cp313-cp313t-win_arm64.whl", hash = "sha256:c525ffa774fe4496282fb0b1187725793de3e7c6b29e41562733cae9ada151ee", size = 245518, upload-time = "2025-11-02T12:26:09.719Z" }, + { url = "https://files.pythonhosted.org/packages/2e/bb/6670bded3e3236eb4287c7bcdc167e9fae6e1e9286e437f7111caed2f909/psutil-7.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b403da1df4d6d43973dc004d19cee3b848e998ae3154cc8097d139b77156c353", size = 239843, upload-time = "2025-11-02T12:26:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/b8/66/853d50e75a38c9a7370ddbeefabdd3d3116b9c31ef94dc92c6729bc36bec/psutil-7.1.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad81425efc5e75da3f39b3e636293360ad8d0b49bed7df824c79764fb4ba9b8b", size = 240369, upload-time = "2025-11-02T12:26:14.358Z" }, + { url = "https://files.pythonhosted.org/packages/41/bd/313aba97cb5bfb26916dc29cf0646cbe4dd6a89ca69e8c6edce654876d39/psutil-7.1.3-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f33a3702e167783a9213db10ad29650ebf383946e91bc77f28a5eb083496bc9", size = 288210, upload-time = "2025-11-02T12:26:16.699Z" }, + { url = "https://files.pythonhosted.org/packages/c2/fa/76e3c06e760927a0cfb5705eb38164254de34e9bd86db656d4dbaa228b04/psutil-7.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fac9cd332c67f4422504297889da5ab7e05fd11e3c4392140f7370f4208ded1f", size = 291182, upload-time = "2025-11-02T12:26:18.848Z" }, + { url = "https://files.pythonhosted.org/packages/0f/1d/5774a91607035ee5078b8fd747686ebec28a962f178712de100d00b78a32/psutil-7.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:3792983e23b69843aea49c8f5b8f115572c5ab64c153bada5270086a2123c7e7", size = 250466, upload-time = "2025-11-02T12:26:21.183Z" }, + { url = "https://files.pythonhosted.org/packages/00/ca/e426584bacb43a5cb1ac91fae1937f478cd8fbe5e4ff96574e698a2c77cd/psutil-7.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:31d77fcedb7529f27bb3a0472bea9334349f9a04160e8e6e5020f22c59893264", size = 245756, upload-time = "2025-11-02T12:26:23.148Z" }, + { url = "https://files.pythonhosted.org/packages/ef/94/46b9154a800253e7ecff5aaacdf8ebf43db99de4a2dfa18575b02548654e/psutil-7.1.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2bdbcd0e58ca14996a42adf3621a6244f1bb2e2e528886959c72cf1e326677ab", size = 238359, upload-time = "2025-11-02T12:26:25.284Z" }, + { url = "https://files.pythonhosted.org/packages/68/3a/9f93cff5c025029a36d9a92fef47220ab4692ee7f2be0fba9f92813d0cb8/psutil-7.1.3-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31fa00f1fbc3c3802141eede66f3a2d51d89716a194bf2cd6fc68310a19880", size = 239171, upload-time = "2025-11-02T12:26:27.23Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b1/5f49af514f76431ba4eea935b8ad3725cdeb397e9245ab919dbc1d1dc20f/psutil-7.1.3-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb428f9f05c1225a558f53e30ccbad9930b11c3fc206836242de1091d3e7dd3", size = 263261, upload-time = "2025-11-02T12:26:29.48Z" }, + { url = "https://files.pythonhosted.org/packages/e0/95/992c8816a74016eb095e73585d747e0a8ea21a061ed3689474fabb29a395/psutil-7.1.3-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56d974e02ca2c8eb4812c3f76c30e28836fffc311d55d979f1465c1feeb2b68b", size = 264635, upload-time = "2025-11-02T12:26:31.74Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/c3ed1a622b6ae2fd3c945a366e64eb35247a31e4db16cf5095e269e8eb3c/psutil-7.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:f39c2c19fe824b47484b96f9692932248a54c43799a84282cfe58d05a6449efd", size = 247633, upload-time = "2025-11-02T12:26:33.887Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ad/33b2ccec09bf96c2b2ef3f9a6f66baac8253d7565d8839e024a6b905d45d/psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1", size = 244608, upload-time = "2025-11-02T12:26:36.136Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.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/96/ad/a17bc283d7d81837c061c49e3eaa27a45991759a1b7eae1031921c6bd924/pydantic-2.12.4.tar.gz", hash = "sha256:0f8cb9555000a4b5b617f66bfd2566264c4984b27589d3b845685983e8ea85ac", size = 821038, upload-time = "2025-11-05T10:50:08.59Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/2f/e68750da9b04856e2a7ec56fc6f034a5a79775e9b9a81882252789873798/pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e", size = 463400, upload-time = "2025-11-05T10:50:06.732Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyobjc-core" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/b6/d5612eb40be4fd5ef88c259339e6313f46ba67577a95d86c3470b951fce0/pyobjc_core-12.1.tar.gz", hash = "sha256:2bb3903f5387f72422145e1466b3ac3f7f0ef2e9960afa9bcd8961c5cbf8bd21", size = 1000532, upload-time = "2025-11-14T10:08:28.292Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/df/d2b290708e9da86d6e7a9a2a2022b91915cf2e712a5a82e306cb6ee99792/pyobjc_core-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c918ebca280925e7fcb14c5c43ce12dcb9574a33cccb889be7c8c17f3bcce8b6", size = 671263, upload-time = "2025-11-14T09:31:35.231Z" }, + { url = "https://files.pythonhosted.org/packages/64/5a/6b15e499de73050f4a2c88fff664ae154307d25dc04da8fb38998a428358/pyobjc_core-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:818bcc6723561f207e5b5453efe9703f34bc8781d11ce9b8be286bb415eb4962", size = 678335, upload-time = "2025-11-14T09:32:20.107Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d2/29e5e536adc07bc3d33dd09f3f7cf844bf7b4981820dc2a91dd810f3c782/pyobjc_core-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:01c0cf500596f03e21c23aef9b5f326b9fb1f8f118cf0d8b66749b6cf4cbb37a", size = 677370, upload-time = "2025-11-14T09:33:05.273Z" }, + { url = "https://files.pythonhosted.org/packages/1b/f0/4b4ed8924cd04e425f2a07269943018d43949afad1c348c3ed4d9d032787/pyobjc_core-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:177aaca84bb369a483e4961186704f64b2697708046745f8167e818d968c88fc", size = 719586, upload-time = "2025-11-14T09:33:53.302Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/9f4ed07162de69603144ff480be35cd021808faa7f730d082b92f7ebf2b5/pyobjc_core-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:844515f5d86395b979d02152576e7dee9cc679acc0b32dc626ef5bda315eaa43", size = 670164, upload-time = "2025-11-14T09:34:37.458Z" }, + { url = "https://files.pythonhosted.org/packages/62/50/dc076965c96c7f0de25c0a32b7f8aa98133ed244deaeeacfc758783f1f30/pyobjc_core-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:453b191df1a4b80e756445b935491b974714456ae2cbae816840bd96f86db882", size = 712204, upload-time = "2025-11-14T09:35:24.148Z" }, +] + +[[package]] +name = "pyobjc-framework-avfoundation" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/42/c026ab308edc2ed5582d8b4b93da6b15d1b6557c0086914a4aabedd1f032/pyobjc_framework_avfoundation-12.1.tar.gz", hash = "sha256:eda0bb60be380f9ba2344600c4231dd58a3efafa99fdc65d3673ecfbb83f6fcb", size = 310047, upload-time = "2025-11-14T10:09:40.069Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/5a/4ef36b309138840ff8cd85364f66c29e27023f291004c335a99f6e87e599/pyobjc_framework_avfoundation-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:82cc2c2d9ab6cc04feeb4700ff251d00f1fcafff573c63d4e87168ff80adb926", size = 83328, upload-time = "2025-11-14T09:37:40.808Z" }, + { url = "https://files.pythonhosted.org/packages/a6/00/ca471e5dd33f040f69320832e45415d00440260bf7f8221a9df4c4662659/pyobjc_framework_avfoundation-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bf634f89265b4d93126153200d885b6de4859ed6b3bc65e69ff75540bc398406", size = 83375, upload-time = "2025-11-14T09:37:47.262Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d4/ade88067deff45858b457648dd82c9363977eb1915efd257232cd06bdac1/pyobjc_framework_avfoundation-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f8ac7f7e0884ac8f12009cdb9d4fefc2f269294ab2ccfd84520a560859b69cec", size = 83413, upload-time = "2025-11-14T09:37:53.759Z" }, + { url = "https://files.pythonhosted.org/packages/a7/3a/fa699d748d6351fa0aeca656ea2f9eacc36e31203dfa56bc13c8a3d26d7d/pyobjc_framework_avfoundation-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:51aba2c6816badfb1fb5a2de1b68b33a23f065bf9e3b99d46ede0c8c774ac7a4", size = 83860, upload-time = "2025-11-14T09:38:00.051Z" }, + { url = "https://files.pythonhosted.org/packages/0c/65/a79cf3b8935a78329ac1107056b91868a581096a90ab6ddff5fd28db4947/pyobjc_framework_avfoundation-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:9a3ffd1ae90bd72dbcf2875aa9254369e805b904140362a7338ebf1af54201a6", size = 83629, upload-time = "2025-11-14T09:38:06.697Z" }, + { url = "https://files.pythonhosted.org/packages/8a/03/4125204a17cd7b4de1fdfc38b280a47d0d8f8691a4ee306ebb41b58ff030/pyobjc_framework_avfoundation-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:394c99876b9a38db4851ddf8146db363556895c12e9c711ccd3c3f907ac8e273", size = 83962, upload-time = "2025-11-14T09:38:13.153Z" }, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/a3/16ca9a15e77c061a9250afbae2eae26f2e1579eb8ca9462ae2d2c71e1169/pyobjc_framework_cocoa-12.1.tar.gz", hash = "sha256:5556c87db95711b985d5efdaaf01c917ddd41d148b1e52a0c66b1a2e2c5c1640", size = 2772191, upload-time = "2025-11-14T10:13:02.069Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/07/5760735c0fffc65107e648eaf7e0991f46da442ac4493501be5380e6d9d4/pyobjc_framework_cocoa-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f52228bcf38da64b77328787967d464e28b981492b33a7675585141e1b0a01e6", size = 383812, upload-time = "2025-11-14T09:40:53.169Z" }, + { url = "https://files.pythonhosted.org/packages/95/bf/ee4f27ec3920d5c6fc63c63e797c5b2cc4e20fe439217085d01ea5b63856/pyobjc_framework_cocoa-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:547c182837214b7ec4796dac5aee3aa25abc665757b75d7f44f83c994bcb0858", size = 384590, upload-time = "2025-11-14T09:41:17.336Z" }, + { url = "https://files.pythonhosted.org/packages/ad/31/0c2e734165abb46215797bd830c4bdcb780b699854b15f2b6240515edcc6/pyobjc_framework_cocoa-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5a3dcd491cacc2f5a197142b3c556d8aafa3963011110102a093349017705118", size = 384689, upload-time = "2025-11-14T09:41:41.478Z" }, + { url = "https://files.pythonhosted.org/packages/23/3b/b9f61be7b9f9b4e0a6db18b3c35c4c4d589f2d04e963e2174d38c6555a92/pyobjc_framework_cocoa-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:914b74328c22d8ca261d78c23ef2befc29776e0b85555973927b338c5734ca44", size = 388843, upload-time = "2025-11-14T09:42:05.719Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/f777cc9e775fc7dae77b569254570fe46eb842516b3e4fe383ab49eab598/pyobjc_framework_cocoa-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:03342a60fc0015bcdf9b93ac0b4f457d3938e9ef761b28df9564c91a14f0129a", size = 384932, upload-time = "2025-11-14T09:42:29.771Z" }, + { url = "https://files.pythonhosted.org/packages/58/27/b457b7b37089cad692c8aada90119162dfb4c4a16f513b79a8b2b022b33b/pyobjc_framework_cocoa-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6ba1dc1bfa4da42d04e93d2363491275fb2e2be5c20790e561c8a9e09b8cf2cc", size = 388970, upload-time = "2025-11-14T09:42:53.964Z" }, +] + +[[package]] +name = "pyobjc-framework-coreaudio" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/d1/0b884c5564ab952ff5daa949128c64815300556019c1bba0cf2ca752a1a0/pyobjc_framework_coreaudio-12.1.tar.gz", hash = "sha256:a9e72925fcc1795430496ce0bffd4ddaa92c22460a10308a7283ade830089fe1", size = 75077, upload-time = "2025-11-14T10:13:22.345Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/25/491ff549fd9a40be4416793d335bff1911d3d1d1e1635e3b0defbd2cf585/pyobjc_framework_coreaudio-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a452de6b509fa4a20160c0410b72330ac871696cd80237883955a5b3a4de8f2a", size = 35327, upload-time = "2025-11-14T09:43:32.523Z" }, + { url = "https://files.pythonhosted.org/packages/a9/48/05b5192122e23140cf583eac99ccc5bf615591d6ff76483ba986c38ee750/pyobjc_framework_coreaudio-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a5ad6309779663f846ab36fe6c49647e470b7e08473c3e48b4f004017bdb68a4", size = 36908, upload-time = "2025-11-14T09:43:36.108Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ce/45808618fefc760e2948c363e0a3402ff77690c8934609cd07b19bc5b15f/pyobjc_framework_coreaudio-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3d8ef424850c8ae2146f963afaec6c4f5bf0c2e412871e68fb6ecfb209b8376f", size = 36935, upload-time = "2025-11-14T09:43:39.414Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f6/0d74d9464bfb4f39451abf745174ec0c4d5c5ebf1c2fcb7556263ae3f75a/pyobjc_framework_coreaudio-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6552624df39dbc68ff9328f244ba56f59234ecbde8455db1e617a71bc4f3dd3a", size = 38390, upload-time = "2025-11-14T09:43:43.194Z" }, + { url = "https://files.pythonhosted.org/packages/cf/f2/c5ca32d01c9d892bf189cfe9b17deaf996db3b4013f8a8ba9b0d22730d70/pyobjc_framework_coreaudio-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:78ea67483a5deb21625c189328152008d278fe1da4304da9fcc1babd12627038", size = 37012, upload-time = "2025-11-14T09:43:46.54Z" }, + { url = "https://files.pythonhosted.org/packages/00/be/c3d660cef1ef874f42057a74931a7a05f581f6a647f5209bef96b372db86/pyobjc_framework_coreaudio-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:8d81b0d0296ab4571a4ff302e5cdb52386e486eb8749e99b95b9141438558ca2", size = 38485, upload-time = "2025-11-14T09:43:49.883Z" }, +] + +[[package]] +name = "pyobjc-framework-coremedia" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/7d/5ad600ff7aedfef8ba8f51b11d9aaacdf247b870bd14045d6e6f232e3df9/pyobjc_framework_coremedia-12.1.tar.gz", hash = "sha256:166c66a9c01e7a70103f3ca44c571431d124b9070612ef63a1511a4e6d9d84a7", size = 89566, upload-time = "2025-11-14T10:13:49.788Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/bc/e66de468b3777d8fece69279cf6d2af51d2263e9a1ccad21b90c35c74b1b/pyobjc_framework_coremedia-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ee7b822c9bb674b5b0a70bfb133410acae354e9241b6983f075395f3562f3c46", size = 29503, upload-time = "2025-11-14T09:44:54.716Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ae/f773cdc33c34a3f9ce6db829dbf72661b65c28ea9efaec8940364185b977/pyobjc_framework_coremedia-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:161a627f5c8cd30a5ebb935189f740e21e6cd94871a9afd463efdb5d51e255fa", size = 29396, upload-time = "2025-11-14T09:44:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ea/aee26a475b4af8ed4152d3c50b1b8955241b8e95ae789aa9ee296953bc6a/pyobjc_framework_coremedia-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:98e885b7a092083fceaef0a7fc406a01ba7bcd3318fb927e59e055931c99cac8", size = 29414, upload-time = "2025-11-14T09:45:01.336Z" }, + { url = "https://files.pythonhosted.org/packages/db/9d/5ff10ee0ff539e125c96b8cff005457558766f942919814c968c3367cc32/pyobjc_framework_coremedia-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:d2b84149c1b3e65ec9050a3e5b617e6c0b4cdad2ab622c2d8c5747a20f013e16", size = 29477, upload-time = "2025-11-14T09:45:04.218Z" }, + { url = "https://files.pythonhosted.org/packages/08/e2/b890658face1290c8b6b6b53a1159c822bece248f883e42302548bef38da/pyobjc_framework_coremedia-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:737ec6e0b63414f42f7188030c85975d6d2124fbf6b15b52c99b6cc20250af4d", size = 29447, upload-time = "2025-11-14T09:45:07.17Z" }, + { url = "https://files.pythonhosted.org/packages/a4/9e/16981d0ee04b182481ce1e497b5e0326bad6d698fe0265bb7db72b1b26b5/pyobjc_framework_coremedia-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6a9419e0d143df16a1562520a13a389417386e2a53031530af6da60c34058ced", size = 29500, upload-time = "2025-11-14T09:45:10.506Z" }, +] + +[[package]] +name = "pyobjc-framework-quartz" +version = "12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/18/cc59f3d4355c9456fc945eae7fe8797003c4da99212dd531ad1b0de8a0c6/pyobjc_framework_quartz-12.1.tar.gz", hash = "sha256:27f782f3513ac88ec9b6c82d9767eef95a5cf4175ce88a1e5a65875fee799608", size = 3159099, upload-time = "2025-11-14T10:21:24.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ef/dcd22b743e38b3c430fce4788176c2c5afa8bfb01085b8143b02d1e75201/pyobjc_framework_quartz-12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:19f99ac49a0b15dd892e155644fe80242d741411a9ed9c119b18b7466048625a", size = 217795, upload-time = "2025-11-14T09:59:46.922Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9b/780f057e5962f690f23fdff1083a4cfda5a96d5b4d3bb49505cac4f624f2/pyobjc_framework_quartz-12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7730cdce46c7e985535b5a42c31381af4aa6556e5642dc55b5e6597595e57a16", size = 218798, upload-time = "2025-11-14T10:00:01.236Z" }, + { url = "https://files.pythonhosted.org/packages/ba/2d/e8f495328101898c16c32ac10e7b14b08ff2c443a756a76fd1271915f097/pyobjc_framework_quartz-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:629b7971b1b43a11617f1460cd218bd308dfea247cd4ee3842eb40ca6f588860", size = 219206, upload-time = "2025-11-14T10:00:15.623Z" }, + { url = "https://files.pythonhosted.org/packages/67/43/b1f0ad3b842ab150a7e6b7d97f6257eab6af241b4c7d14cb8e7fde9214b8/pyobjc_framework_quartz-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:53b84e880c358ba1ddcd7e8d5ea0407d760eca58b96f0d344829162cda5f37b3", size = 224317, upload-time = "2025-11-14T10:00:30.703Z" }, + { url = "https://files.pythonhosted.org/packages/4a/00/96249c5c7e5aaca5f688ca18b8d8ad05cd7886ebd639b3c71a6a4cadbe75/pyobjc_framework_quartz-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:42d306b07f05ae7d155984503e0fb1b701fecd31dcc5c79fe8ab9790ff7e0de0", size = 219558, upload-time = "2025-11-14T10:00:45.476Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a6/708a55f3ff7a18c403b30a29a11dccfed0410485a7548c60a4b6d4cc0676/pyobjc_framework_quartz-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0cc08fddb339b2760df60dea1057453557588908e42bdc62184b6396ce2d6e9a", size = 224580, upload-time = "2025-11-14T10:01:00.091Z" }, +] + +[[package]] +name = "pyserial" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/7d/ae3f0a63f41e4d2f6cb66a5b57197850f919f59e558159a4dd3a818f5082/pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", size = 159125, upload-time = "2020-11-23T03:59:15.045Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0", size = 90585, upload-time = "2020-11-23T03:59:13.41Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, +] + +[[package]] +name = "pyusb" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/6b/ce3727395e52b7b76dfcf0c665e37d223b680b9becc60710d4bc08b7b7cb/pyusb-1.3.1.tar.gz", hash = "sha256:3af070b607467c1c164f49d5b0caabe8ac78dbed9298d703a8dbf9df4052d17e", size = 77281, upload-time = "2025-01-08T23:45:01.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/b8/27e6312e86408a44fe16bd28ee12dd98608b39f7e7e57884a24e8f29b573/pyusb-1.3.1-py3-none-any.whl", hash = "sha256:bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430", size = 58465, upload-time = "2025-01-08T23:45:00.029Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "reachy-mini" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "asgiref" }, + { name = "cv2-enumerate-cameras" }, + { name = "eclipse-zenoh" }, + { name = "fastapi" }, + { name = "huggingface-hub" }, + { name = "jinja2" }, + { name = "libusb-package" }, + { name = "log-throttling" }, + { name = "numpy" }, + { name = "opencv-python" }, + { name = "pip" }, + { name = "psutil" }, + { name = "pyserial" }, + { name = "pyusb" }, + { name = "reachy-mini-motor-controller" }, + { name = "reachy-mini-rust-kinematics" }, + { name = "scipy" }, + { name = "sounddevice" }, + { name = "soundfile" }, + { name = "uvicorn", extra = ["standard"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/6e/0ced70f87d1482a1e10d3b1cd0d72154013890e14c8b51a41fed696b78f1/reachy_mini-1.1.1.tar.gz", hash = "sha256:dfcac20e09869284bffc5e3243e4a3556eb9efd2ca1485ce752daabe4c5f74dc", size = 24573874, upload-time = "2025-11-25T18:03:18.583Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/41/4640e247a92f10d4e727ae50d158e44b277a7ac56cf53742fc08aec14b61/reachy_mini-1.1.1-py3-none-any.whl", hash = "sha256:9371fa52686c548817659a60170139520789be177315680465b4b6122f27fd61", size = 24632472, upload-time = "2025-11-25T18:03:15.914Z" }, +] + +[[package]] +name = "reachy-mini-motor-controller" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/8d/353b13636ebffae848c0d0b8c4bfc15c4673b059f62f9c310ee98986b0b7/reachy_mini_motor_controller-1.4.2.tar.gz", hash = "sha256:bd6e9f5c13394bc57478a09e76e01c28854ae0c80a9335a3a1b78dc80e0ee150", size = 28248, upload-time = "2025-11-25T17:56:55.263Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/20/ac97ac49969c02e0384888c73cccf0b50a7bba48b18842a96b082a8c8e89/reachy_mini_motor_controller-1.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f405d5f948abd26e423f156fc0d165b69ec964d3a4cbfa7d2d952313cc0ff972", size = 586684, upload-time = "2025-11-25T17:56:24.378Z" }, + { url = "https://files.pythonhosted.org/packages/68/21/796b9fd0616600b93d5b74ce2b4eb0f525f2773aae8635a8c0506a4145d7/reachy_mini_motor_controller-1.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:835e1d7e9383615b2684fb97cf18065f80498bb7d7d9ba980f8fe295cda68109", size = 572449, upload-time = "2025-11-25T17:56:17.627Z" }, + { url = "https://files.pythonhosted.org/packages/07/bd/661f6a44bd436c069d38ba0fdc1c1524178c4d039dcd4326fb1918bccf91/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8403bb4b6c23c088493967c8445e5cd1ec4784f5c2ae1dab289fb9ba456055b", size = 642034, upload-time = "2025-11-25T17:55:56.725Z" }, + { url = "https://files.pythonhosted.org/packages/cd/82/12b52b5eeee59387866db9370e43894f66dda8feedc15be38a6963be3e9a/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1cf6d2a6dc10b5f8acc4c61a89e2e201eca84c6be741becbf9775084d29fc6e", size = 647692, upload-time = "2025-11-25T17:56:02.499Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a0/4ad6ca320e303de61135219c3b9953b1ec1f7375181dbaaa98a43b65ecae/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a366aa59f9bde4f80f6c03757e431a3cea80f0b18992401169b484cf8928d14", size = 696265, upload-time = "2025-11-25T17:56:07.722Z" }, + { url = "https://files.pythonhosted.org/packages/8f/98/14cb24c497c295f91b11144bf639304116630de6862ba3095fe3a18dc3ff/reachy_mini_motor_controller-1.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df475384deadcea1c8b430839addecb84126002d54649283cce5e6465d51b543", size = 660553, upload-time = "2025-11-25T17:56:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/c1/cb/9bc5c91075d5e551deb2d93fae89062bb94b5edd5f658b66c97c11c460d8/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e09e99bb325405f414013ce7d13f7ed36af5b9278dce2ee6bda9ea2affe6baf", size = 825331, upload-time = "2025-11-25T17:56:30.458Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/fd404636cb980604ed82dea5e7ec9c4de78a76324d36ff9efc55bb7549a7/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2f35c0b54ed396b8d9eb98dfe6dcc6d3b059433c2181030591dc84483531a25b", size = 911925, upload-time = "2025-11-25T17:56:36.802Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1c/6d48c4c3c5c9705e20265db04f040f42d1955cb0ded817e8915684999386/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:af23d02daff28470be0e775ce63666bea06ad24ce948649751f7122996d5363d", size = 854410, upload-time = "2025-11-25T17:56:43.296Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b8/55955b7b47c8ed65bda69a221cd4805bad3d07c3c95b7002e67deec43dff/reachy_mini_motor_controller-1.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:610d74c3cfc28854137d00d206a6b4c4942a371376611781a244376fe3175277", size = 815823, upload-time = "2025-11-25T17:56:50.274Z" }, + { url = "https://files.pythonhosted.org/packages/12/7c/20672ab40d1d25cdddf49cb969bfa36043d9b760e4e82275a32853846192/reachy_mini_motor_controller-1.4.2-cp311-cp311-win32.whl", hash = "sha256:abe319839f78cc3e4e8ed0ced0bc519f97bfc1e6ff6b320dc8f84b772123237d", size = 377969, upload-time = "2025-11-25T17:57:02.781Z" }, + { url = "https://files.pythonhosted.org/packages/b5/5e/0725df6e698fe9a83eff0f86d61c5e62878c864ce521c1a1c12645409bc5/reachy_mini_motor_controller-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:d8f7ea29ca78ee86206989c30066e17b213f4cc8975f0a275f092588cd2debc8", size = 401027, upload-time = "2025-11-25T17:56:57.17Z" }, + { url = "https://files.pythonhosted.org/packages/e6/6a/af2786310d5ccf84a48ff0153c7be2346ef3730ca540b20d998020c36cb8/reachy_mini_motor_controller-1.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a41cc1bdc08b2fbba681804c6143319a6b4ef2d30093910f9776db01c5ba9595", size = 583808, upload-time = "2025-11-25T17:56:25.635Z" }, + { url = "https://files.pythonhosted.org/packages/dc/d3/6354fd9b34b89d2b5a639c56ae05f393d2ae7cef187bfcce60a71a40202d/reachy_mini_motor_controller-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af3cdd5197f57108044af81166dd755214f469c368e79221521b9a698da45223", size = 570332, upload-time = "2025-11-25T17:56:18.828Z" }, + { url = "https://files.pythonhosted.org/packages/da/eb/d30bc7517a2f7c860b95978af73beede33819e717978d5560f4b5b8a2953/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed2537a512098664d73a7575af763acd5446fc2325f37cf3b9b84d37368b5f7f", size = 641541, upload-time = "2025-11-25T17:55:58.117Z" }, + { url = "https://files.pythonhosted.org/packages/a4/63/8f9c091d0b210ebc6aa7762fa09155456a088df987d73dc39cda4fb9c241/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:554dd7392b9fef86cca8c12d5861d8f17e2eb7e1d69b49c65fbf54e1410f9567", size = 648054, upload-time = "2025-11-25T17:56:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/ac/15/a1bebc7acfcb02c12ba32e00dc1f9346fdf2468e441f983daf86ee4c7df3/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3f6ddd91e0228b3396f2c027f3e55eac0d3c4f280968ec73f2bdac37cdeda0", size = 696773, upload-time = "2025-11-25T17:56:08.895Z" }, + { url = "https://files.pythonhosted.org/packages/06/9f/a3ab6942383198e4c105075582c2355350ef33f90ef4f877105ada181e88/reachy_mini_motor_controller-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0b357e49773bcd338e24ed17c4a93fb1890c97513c4cd07eec8c4f3ba06bc48", size = 660676, upload-time = "2025-11-25T17:56:13.77Z" }, + { url = "https://files.pythonhosted.org/packages/4c/09/7da09c39d2722d6323ed719de95f2f7777699b0049b81d25aaff9b0cc2db/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dd05b4bbf2aa30674b2955edf8fefbdb90b522077b3c549719afd4a1d2dd325b", size = 824841, upload-time = "2025-11-25T17:56:31.967Z" }, + { url = "https://files.pythonhosted.org/packages/97/68/2c4e8160a3d8e0e20a61ad491dccb9d17febbaa434da83e38060a7517fc9/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:377d47674a0429a01f509d9fe9b52365a715ca132bfdf4956a3b5bb219723941", size = 912195, upload-time = "2025-11-25T17:56:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/14/5f/a547e59efd62518afbb616c9e3bc2f057662fdd209f75b218ef1917bcd7b/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:742c1e077669c198a4261acf3213789ed679846a25714e74e9774984862bbc7a", size = 855751, upload-time = "2025-11-25T17:56:44.595Z" }, + { url = "https://files.pythonhosted.org/packages/76/58/8720be3e52e302052c6d10e3c0937271e8c376d6e5a10b2dac480c94c7f2/reachy_mini_motor_controller-1.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9b2eb49965f2dba93a1d251b0beb4b22b81f5b18946d53ff8761097011ffaa43", size = 815778, upload-time = "2025-11-25T17:56:51.74Z" }, + { url = "https://files.pythonhosted.org/packages/aa/52/7af3228652ce3503243cbce68d736af00b11afd07f0f96effa6faaca677d/reachy_mini_motor_controller-1.4.2-cp312-cp312-win32.whl", hash = "sha256:e59bd6a1b89b94da835b1fbe3f483470ea0471fdb1b92d0d4bbb93a24ab7a1aa", size = 377018, upload-time = "2025-11-25T17:57:03.815Z" }, + { url = "https://files.pythonhosted.org/packages/a0/7a/090705f6e62ec10107ea20e78fd8b8f26f6421b9db49f7bf5e275084aa02/reachy_mini_motor_controller-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:ae99c65942130ce04a01d50dae359694a42fa91ede864ead0defd9a693b30b05", size = 399902, upload-time = "2025-11-25T17:56:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ac/fc016600786fbcdc8d048f7e42c946aa1a488e382e08b83e39934ee5f381/reachy_mini_motor_controller-1.4.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:43064e6c97be9f6fb2494ebf56dda18daa0366cd70b32ee548818c908d8b3564", size = 583599, upload-time = "2025-11-25T17:56:27.042Z" }, + { url = "https://files.pythonhosted.org/packages/07/c7/c79c33cf46bbe6301fef5520445649ce10a85a30754fce975df41f7b80b7/reachy_mini_motor_controller-1.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ebe3f763c011ecd3dc4bd017dfc886ecaf455d9866cab1ce8b81116d22eb6a3d", size = 570309, upload-time = "2025-11-25T17:56:20.391Z" }, + { url = "https://files.pythonhosted.org/packages/78/e0/d301987769c1504549c06cf0ce8e132df48bde0f47d28a8768c25b7ed8ae/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c86146d3631dd73efb77d591f8a33c288b9ad394d3a6805c0685f3c5ec05266f", size = 641472, upload-time = "2025-11-25T17:55:59.645Z" }, + { url = "https://files.pythonhosted.org/packages/ff/52/7884ee1c04b480f8e34b4c97697a0977d314a22f6766fd5e246dfbddb404/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36052e08d331ae768f4b562e950eaa767ae4ee8a91e9334498c1bcbafe841514", size = 648510, upload-time = "2025-11-25T17:56:05.286Z" }, + { url = "https://files.pythonhosted.org/packages/03/56/619bb25bb31f96d6172d1bfd5bbf516b5985b595f6e1c7c82481fff95c55/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b2ac6712f7a5493bb3be276fa53bb9b9e4770f13783f26ff0a18e7fc6f800d4", size = 697241, upload-time = "2025-11-25T17:56:09.99Z" }, + { url = "https://files.pythonhosted.org/packages/5a/b2/c82a31cf252ff6fb4d4c59a208d8375159cc796326812b7e946eea5c00a4/reachy_mini_motor_controller-1.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fcb404dc2021175d4339fb3a8f9334cd999bf8a0369e0dacb02c430edf46a0b", size = 660207, upload-time = "2025-11-25T17:56:15.23Z" }, + { url = "https://files.pythonhosted.org/packages/83/6e/b2d9aecc4144cffcee14b023da20b8850a11cd35375561a7e60be7132e10/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f482f61eecdeb72a7722399d0d549872a239023c263968f9e2ffac9ee69687dc", size = 824941, upload-time = "2025-11-25T17:56:33.129Z" }, + { url = "https://files.pythonhosted.org/packages/c0/68/72b7d8a405fe7b1785b2caaaf917958dc6691015f6c15089bfee8b35f65d/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:88e1a5c1d4afe4e695d589715f0628536fe7399ec6d2751025dd785f4282a62e", size = 912805, upload-time = "2025-11-25T17:56:39.585Z" }, + { url = "https://files.pythonhosted.org/packages/c0/62/4ce77e08ea5dc428835202723671026f52d46e20ee2642af24ecd2c64858/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2d5c9e2645d7c6b29a8a46b4ecef72540bb2c0f983349cfcaf7c681386e7a002", size = 856256, upload-time = "2025-11-25T17:56:45.894Z" }, + { url = "https://files.pythonhosted.org/packages/71/a6/c031586c9dd8fc735b427c5fcdd20d9360c02a6c61ab3cbb59589ad15d9d/reachy_mini_motor_controller-1.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffb5331150c0cdfac9910d341e82d788bc173e473e893e3f8e54938ede1e3523", size = 815565, upload-time = "2025-11-25T17:56:52.837Z" }, + { url = "https://files.pythonhosted.org/packages/c6/e3/5316b60491ecf3384b1b51db49317bc175561411edcc83fe1398b68736f4/reachy_mini_motor_controller-1.4.2-cp313-cp313-win32.whl", hash = "sha256:6edcf88f5d4c1bf3948328a6f65cd4518fda8cefbe55fb884fda088f363c2b60", size = 377394, upload-time = "2025-11-25T17:57:05.059Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/41f4efca4abaf31bff5fa891ae0f594623539afd936abea51e0e546a6700/reachy_mini_motor_controller-1.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:602cf3294f54ceae4fa84d006aa0e97dcfcd99f7ee556cbbcf3546ac42fe8fb3", size = 399788, upload-time = "2025-11-25T17:56:59.383Z" }, + { url = "https://files.pythonhosted.org/packages/3a/0b/3b118d1ed20da22c3844c88247a78f6fdee679fff149d0e1ee64fc5d8aa8/reachy_mini_motor_controller-1.4.2-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:aedcbebb270c3e6ad8898aac321f82a3d3060898ee33d75ae181b0f1df278f93", size = 581082, upload-time = "2025-11-25T17:56:28.189Z" }, + { url = "https://files.pythonhosted.org/packages/5a/e7/c24da5194f16714d6f2a67fefaba817e2a22f68f58269500fa4495d6a29e/reachy_mini_motor_controller-1.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4d8d7626e3655a96266cc88d9ae1327c8b42512b61e8acaeb782d8d3352125c2", size = 567918, upload-time = "2025-11-25T17:56:21.842Z" }, + { url = "https://files.pythonhosted.org/packages/89/69/cc9a51e04c1523213a8f4121bb1c454293d287f8c0fc4998e2640d053169/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8b27d6769f12a4bf75b8b6cb0e0dc20d154bc1422ff9e046f530434050552b86", size = 823910, upload-time = "2025-11-25T17:56:34.482Z" }, + { url = "https://files.pythonhosted.org/packages/cd/76/1f283234ec0fb1b349a24930485a9c584d94f064eb4d3d2e32e5607ec64e/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:07118c8cafed873541fb716928a3d4f807ac6ac7f769d7307faa4cd9bead6e6d", size = 910812, upload-time = "2025-11-25T17:56:40.804Z" }, + { url = "https://files.pythonhosted.org/packages/5c/22/771e3e02872c319f999c5e0830787c926d2b74b976c71f041d5429c4f785/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:d552fdf890c3040232b2db783fc03ffcee230b633208e62b7a4265fa5d076598", size = 856433, upload-time = "2025-11-25T17:56:47.095Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a3/c897ed4e7a43d205d43a985669dfbbc3943d1df8a101038c5384f34b9617/reachy_mini_motor_controller-1.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4b250a7763a72d6864ef4cdcec088d56e4d17947a10493f7347f2001502f05ed", size = 816617, upload-time = "2025-11-25T17:56:54.099Z" }, + { url = "https://files.pythonhosted.org/packages/03/67/63dc13fe0fad1bafe12122b10479b2e22bb4562e58ed45e14f18b3f076c5/reachy_mini_motor_controller-1.4.2-cp314-cp314-win32.whl", hash = "sha256:d9a6be4852cb8cbec2e19d2037234dce39defce653f3af9d4a46cd56d624c617", size = 376862, upload-time = "2025-11-25T17:57:06.232Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/0c4b6fc4a761ad8bd362f571d3693c94aa0c15121e122f1c01e3f38bc873/reachy_mini_motor_controller-1.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:aa7b6ca1b6db09e6249fdb5a31376974e82928292950cd7df4480cbd5707a425", size = 400104, upload-time = "2025-11-25T17:57:00.616Z" }, +] + +[[package]] +name = "reachy-mini-rust-kinematics" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/82/485aa2f28973eee6198b2af0db9e76314fd909076f06782228fa686f0e3d/reachy_mini_rust_kinematics-1.0.2.tar.gz", hash = "sha256:ca14f9193c73a53612a32cd0bfb9abecb13343bc94fe5feb95f54736b7f3cd64", size = 17187, upload-time = "2025-10-22T08:35:50.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/fd/c3801f0579da40147c7cadc1226bc3f5b7413cc590b13f53822674a910f7/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b9fe481d3ae29415e9be3358493bd6d26add4b494650384c650181595da10204", size = 303080, upload-time = "2025-10-22T08:34:54.167Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5f/1b28508a05fde9bf80277222991273721462afa84a7a0ede6227692b6a75/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58c87c6cb62a020f325caf8344f003ba4ebb783e20f417c6d89e3b63a72bc8a1", size = 278691, upload-time = "2025-10-22T08:34:44.295Z" }, + { url = "https://files.pythonhosted.org/packages/de/22/9b4c4b007085db8fb329656146742414e64051d9deb8e108020fbb3aafa8/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af2f330760b5519dcf556c728ddaa889fbc1b5ef6d76a4f3ef2eee1ddd032cb4", size = 312649, upload-time = "2025-10-22T08:34:02.52Z" }, + { url = "https://files.pythonhosted.org/packages/c1/e7/b50b441d287e72864e32b1049ab6d740158a8330deba5ec2cfa62d5125e0/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d8bffa448b0a75a570c5b8625344de3a755bca7f3a7450b045df153cef0cb402", size = 321102, upload-time = "2025-10-22T08:34:14.669Z" }, + { url = "https://files.pythonhosted.org/packages/3b/4b/cddf709a7012450d3255d7ab6ee6a1216e761664657ffe68806712d95c42/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27ae0811ccc4132f9b034771af061c513bcb0bd18a73dad1d16abc6bad366caa", size = 337443, upload-time = "2025-10-22T08:34:35.544Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6d/908fca70c2dee3e066831fcde011fb0d8c563418c75e052208bc538105cb/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5777d235930be71186adf948388580317943a022aa3761d6f78bcffe7dfc5ee4", size = 351864, upload-time = "2025-10-22T08:34:26.064Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e8/ddbfbc71cc2a7246de06cd4a0e934c9613a3a814406afbf8dfcd071813bf/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cbf226d07d34a6a395635b90ebb4d6e083136f07ca2e746d4431c44b00fd2d5", size = 493208, upload-time = "2025-10-22T08:35:01.445Z" }, + { url = "https://files.pythonhosted.org/packages/75/d1/51af83f5b70c2eaf5f871efdf62c7d88116af2d5309898b2de9925857556/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bab5d550e2225c9d4d6ee69b98fd13cf75b8b3df4ab9824d7759668e04a6e5bf", size = 585005, upload-time = "2025-10-22T08:35:14.756Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a8/cef7d415d864c8fa04362485ecb1648947a194b90426d147972ce59f4263/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7fc0243f9abc3d14aadaaa19b86d4930bf1e3bace0bfbbde73048ed80928b0f5", size = 526789, upload-time = "2025-10-22T08:35:27.367Z" }, + { url = "https://files.pythonhosted.org/packages/d2/4e/98e8e72f3cf0758eb4e6eb7320438dfb9e08d6ff593f6cc3661e726cf9a1/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a060b9022becd8decf9868063099fe68e598f7c07406d96795408ca862d208b3", size = 498731, upload-time = "2025-10-22T08:35:38.944Z" }, + { url = "https://files.pythonhosted.org/packages/26/fc/d9b66b439ea27c20d01e6cc841b34b3a8cc17fb0e79acaaa8ba4f5a4c587/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-win32.whl", hash = "sha256:ebf961d3ae3cd0798ed8d4e2bec8aec57f33fe2fb713852ad0ba2de4386c9c1a", size = 176607, upload-time = "2025-10-22T08:35:58.496Z" }, + { url = "https://files.pythonhosted.org/packages/9b/be/848776e83114ee92d9799860860be6dff036f22c9d01e85805c02a6d05fc/reachy_mini_rust_kinematics-1.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:8afa30ed7da49544c8215033d2375c2f76f3311a6a1f380fe9acd2c076f9d45f", size = 187332, upload-time = "2025-10-22T08:35:51.994Z" }, + { url = "https://files.pythonhosted.org/packages/11/39/6c40cca1970ce47d9ae1661c87230cd37a6e2d782f34e0aec745f155d831/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:356134c5df18a01226432fbd1fb24649aced5a14da3c0406ebe2d1b3b8c002d2", size = 299587, upload-time = "2025-10-22T08:34:55.208Z" }, + { url = "https://files.pythonhosted.org/packages/5c/30/f9ba417bc1782d6a256ef9024eb0329c50cb7a3d12e83afd4b67047a01d6/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a232408fb7c58d6da73c40a40a120bae4f51bf9119de108530572723a00280d7", size = 276656, upload-time = "2025-10-22T08:34:46.904Z" }, + { url = "https://files.pythonhosted.org/packages/75/e7/e3bb2597d86f2037a1e4537f2352d7e92ff4699ee725b43a90400f15894e/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e7c3d2c73f89bf817d8c3abb8f0b23a6efdfce330a749c6e29e1e0cf6db9d7d", size = 312798, upload-time = "2025-10-22T08:34:04.219Z" }, + { url = "https://files.pythonhosted.org/packages/62/2f/64d2c4b434ef413c948935a0f57b4a502cc7effad68dd97263cdee22df64/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba0faba18be71b68026c70ccf4db6d9ea588774053d22487f228b490204a8a00", size = 321023, upload-time = "2025-10-22T08:34:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/c8/0e/f4cbddd5c0ed10cdba7f4baffc68f2e8102eb1d55b309690a52af3b067f8/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bed2ec420ea354ce62572afe8672ae8701a139781d9d8da97932597907019ee", size = 337756, upload-time = "2025-10-22T08:34:36.66Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d5/ac043e65949ba904b7ac901d74b8514ab47203de3af44e96c44dd2da7a94/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a79f6517728463294d5ca4945b18d843dd16cc410815ce039b35c1198bdc355d", size = 351251, upload-time = "2025-10-22T08:34:27.06Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ef/80bb31cee07d2336013808ce3b76dee29ae04274f053e1694e3a285da555/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5404cf14cc8894962dbbc82594af453588539b4b9458b8f95f43c29bc8bd2e34", size = 493292, upload-time = "2025-10-22T08:35:02.56Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e2/4f6c5a0d2a77111a9806243160b1aa3531ad3024a59f05c7f6157917bcc5/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:2e1f9d9ce4222d7ecda5cb77c96fed763de3ac94993e60c73adf9749d26e16df", size = 584893, upload-time = "2025-10-22T08:35:15.981Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/b0b57c9c46b77aa3c03f4071fca0c92809e23f9b22df5f85446ec5329fe2/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7c29c3d7b70d0576c740969cfa3e35ba98cc8e378c0867a79f53d5fee3568f77", size = 525948, upload-time = "2025-10-22T08:35:28.451Z" }, + { url = "https://files.pythonhosted.org/packages/06/12/f4d94e8c0b1b19b47072c2041f31fb83701cff1a199d0fcf012c0489f32f/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5b94ca8e94058efcd89553144b0a0b0f7c4abfe67a4cd60e2993cd0833c9e130", size = 499239, upload-time = "2025-10-22T08:35:40.026Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b6/907870cb3f588a6da58b64357c03241a28dac8a9ec9f42e91c291cb95c51/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-win32.whl", hash = "sha256:edcbcedaa4aa99684588bd897733a33ff8f8d9eed8ae39bd7d0fd691874f0457", size = 176379, upload-time = "2025-10-22T08:35:59.841Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c0/a5c1db0bf8dc55cf6b41a11463285ef440a2efa74d8b75be8443234c1acf/reachy_mini_rust_kinematics-1.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:eb5d6d27ce08e8816496b6049979cf64ffbf3901dd5bb290efe439f5455526c2", size = 187469, upload-time = "2025-10-22T08:35:53.307Z" }, + { url = "https://files.pythonhosted.org/packages/13/5c/fffb02be21f666cf880042804c703de2410f32a44b0412d6df20bb156d15/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2aae2b9424a111935e26977fe2ab25c130c766e8049d72073e31a7ad78c84fb5", size = 299868, upload-time = "2025-10-22T08:34:56.48Z" }, + { url = "https://files.pythonhosted.org/packages/a3/33/b7e610c6325ed4fe439bd0be3e96850b5a5b6dc360116741bdf4c3a57ce9/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38ba383417c472ac67945a57c62ba621128b4486bd9d818512929454f47ce76d", size = 276655, upload-time = "2025-10-22T08:34:47.905Z" }, + { url = "https://files.pythonhosted.org/packages/93/bf/a1f579e4a6930b2155c99f80ac5b96d256c0047537c0802c34f0adfcde81/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3788d9c5b5315eff026486c3367e97ea23cd4ccd3eb6c7c1e37e0d00ec6b7128", size = 312962, upload-time = "2025-10-22T08:34:05.504Z" }, + { url = "https://files.pythonhosted.org/packages/89/cf/bf2a450adb2e6fbc5a9baa3ad9bece4d7272341723f4e76eff710463b484/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6983b555c1af6fd2c1ca8b32ae374c2b060239bb04b9b562806771ddafe81abf", size = 320871, upload-time = "2025-10-22T08:34:16.889Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ad/1eab50e3c56a65ac2f14a4890ae5370984586f52adf13cd8a7963ebf423c/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca28a8cda1ab4973259ed9aa06c7173ac5899492a3140075c58225a0ed96be52", size = 337653, upload-time = "2025-10-22T08:34:37.679Z" }, + { url = "https://files.pythonhosted.org/packages/a0/ce/8d3802dde54f9595daa9bd7b12a3de42ba4b4b48d92d8abe7a43919d74a8/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c8591616ef354d4f0724affef58eb14374f4a06b649b7947e94b97ec22d2fb9", size = 351553, upload-time = "2025-10-22T08:34:28.126Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/5e1de72d044440afb8cb7480af0c9ddcdcd9654b0ac62c11113fedc731d4/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45f4d9f159714e60eef22c9c00232beb34a8d27a89acce7d3ffcec2b86992b06", size = 493556, upload-time = "2025-10-22T08:35:03.963Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8b/1a33d934b9720586dc261349b500fb6a969ff1d3ba7c6f9bb7ba87d61d37/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:02a525696238dc85e9a1f3260d7d0db25074bb54f1cc2a0a4052849344026806", size = 585019, upload-time = "2025-10-22T08:35:17.344Z" }, + { url = "https://files.pythonhosted.org/packages/b9/5e/8cf4011456e3262f2a67b66ee77838cc56655cdcd7941efd44cb6ff8eb85/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:342b4a9adb9714f98d6569121c053800ae0a5b3904a9863ca65603bb3b9e7f0a", size = 526143, upload-time = "2025-10-22T08:35:29.636Z" }, + { url = "https://files.pythonhosted.org/packages/0f/3e/0d1168324c288693c07abd0050b83f682cf12a27c850e42d2601d3da84ef/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b596910a1ba0aaf79fc525ec5a8405dcd41c28946667faa549e789e5c1b93a5", size = 499284, upload-time = "2025-10-22T08:35:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/66/4e/0f69c0287a9289a0bc78d623cbf8cbd652e54ff6e854979b4985eb7fa75e/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-win32.whl", hash = "sha256:d5437b5d7f9093e879859d83da6888738f281fe728fad0a9f1678fe01035b4d3", size = 176631, upload-time = "2025-10-22T08:36:00.974Z" }, + { url = "https://files.pythonhosted.org/packages/94/00/eff3fa6480da3c2b486b8bcec55ea650b4955fb874664e9e7dce205a9885/reachy_mini_rust_kinematics-1.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:c3c813012eacc7e779c81388f3dcb30811bee461672f9f9dc03835c73e3a5bc4", size = 187334, upload-time = "2025-10-22T08:35:54.464Z" }, + { url = "https://files.pythonhosted.org/packages/0a/e2/2c19fbf08a5e3836147ee345b9d75fbe1cd26df8d1f9e83b9cefa4bc80ae/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e1f563b31cbb0e0ee9f015801ef2eba31b9c37c306e3ca7737097a482355e0a", size = 312043, upload-time = "2025-10-22T08:34:06.505Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d4/873c4317a598e9709dd2aa68f0a072568b1f2db3616a2ffa76259618889e/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:874b986c44a94e1e1752f8f0b159342b0f60d4610e4df9c4bdf421e2749d949e", size = 320190, upload-time = "2025-10-22T08:34:17.889Z" }, + { url = "https://files.pythonhosted.org/packages/1f/11/64941229b39bfb1c39ea2ccb5fd02998915f87e40e277e4b0b744a2c3a2b/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f5060865aba96d3ffe1ac5cb93dc6439154a78ef8fdbb8a4313e4dc33064efb5", size = 492437, upload-time = "2025-10-22T08:35:05.014Z" }, + { url = "https://files.pythonhosted.org/packages/20/47/82704725e0d5cae887a4604e9bbf7688e6a676768ab47202b018ef9f7f32/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f7ddeef8610a936afbfd7dda1713be18d207032e18604e46963729996c3d1a41", size = 583980, upload-time = "2025-10-22T08:35:18.517Z" }, + { url = "https://files.pythonhosted.org/packages/97/6d/bfcdc6912531c62885450646f629aa581fb116ee5806dba00c01712b02f4/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2f498398c933e87a63a5747a2c813df09dcb68ded3ba79f86d092801ced36da8", size = 525181, upload-time = "2025-10-22T08:35:30.819Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6d/4f32bc65f83307a6eba5b62231e276bde8509d26dd8ba1a9997fb6c4b924/reachy_mini_rust_kinematics-1.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6464868b209ec5cc0e50829b25bdad8cf765a48c943a5a7f504a3ec4ed7aedcb", size = 498743, upload-time = "2025-10-22T08:35:42.183Z" }, + { url = "https://files.pythonhosted.org/packages/85/26/2af509eb72c556a5f8628454122f61bcd55ae760ed74c2a1d8cfe21ebafe/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:419cba0b2ca01b52aba79004681201e1ad16d5a06a2ae9f4f74c45ea82e88f11", size = 276979, upload-time = "2025-10-22T08:34:49.023Z" }, + { url = "https://files.pythonhosted.org/packages/82/62/5fdf253c4293447fe2b95329891a46292fed02fd15f71a7eafbcca842194/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c654f6e06da8c6f8f5f2613c7a8d1841dca730ba2397125418f1b26bfeb46330", size = 337650, upload-time = "2025-10-22T08:34:38.745Z" }, + { url = "https://files.pythonhosted.org/packages/01/2e/eee9bed34de89569f52965fdbf6bd16c914c1b87f4f233e49ffa1f3f0590/reachy_mini_rust_kinematics-1.0.2-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:58a36591b27a80c0836ab08ff21bf605413213f079baeef6fd1e3d6b47d8a341", size = 352082, upload-time = "2025-10-22T08:34:29.451Z" }, + { url = "https://files.pythonhosted.org/packages/bc/2d/c4492e19625f81348c812e5e17e97e777c521fe7200006bc41ebc904dd14/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305793e3097db1a93eabeeb5bcf7a581dedb859740d5f5164d7f2b695ce90953", size = 312932, upload-time = "2025-10-22T08:34:11.265Z" }, + { url = "https://files.pythonhosted.org/packages/9a/b2/d6cdc7960650c609b3e902734dcd10d6eb44373ba4f0aadaefde401244ba/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dda63846d7196737bad42d9de847b3c4702e68e40fc0a691fed50a87b9ef0898", size = 321183, upload-time = "2025-10-22T08:34:22.468Z" }, + { url = "https://files.pythonhosted.org/packages/51/74/d92143a61237d3f83ba9f6398f7d546cdefd8d43f820677bcf4d7ed3a265/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b307111f6ff46a1e8dc5b0d600c836ccf237106cf0bb9b87d85e079199fb733", size = 337577, upload-time = "2025-10-22T08:34:42.092Z" }, + { url = "https://files.pythonhosted.org/packages/05/e4/5ab1e64bd201e388f3fc0bb1ee89ef166479c8482d582ee58d603ba1b6ba/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64649a8ca74f3f528d57adf02f3b5ad6eaab4e5ab40bf837554ad878f0f4ea64", size = 351547, upload-time = "2025-10-22T08:34:33.109Z" }, + { url = "https://files.pythonhosted.org/packages/5f/19/f754c4cac653d3133145694abb6bb2d0da15b2459c1361b35528b3d16287/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6f0eda0e6cb8d86e80937a78b44e3db5e338039480fc077503aca3c23af008e6", size = 493554, upload-time = "2025-10-22T08:35:10.535Z" }, + { url = "https://files.pythonhosted.org/packages/af/81/14e1848dc1fb662a9dd8108bb3be4161a241055d38bac65eb9ee1fe5926c/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:12b9c538544352ee829338b3ae34623e3903294cd09ebb286f9467cad9882360", size = 585142, upload-time = "2025-10-22T08:35:23.413Z" }, + { url = "https://files.pythonhosted.org/packages/bb/47/a74608d37b58a162a3204ad4a1b7981ca79dc598b6c76533922cdc2bcb48/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:56eb81ad90e2b04506b4adf809b48a449fbd3972e2b32bd49038b745a6ff2d38", size = 526427, upload-time = "2025-10-22T08:35:35.379Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8e/c48f621c8d954849deb081a7a8840c57e38385dad999aaf5b82e10a09f84/reachy_mini_rust_kinematics-1.0.2-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2af9062ffb5970b3318a85eaa7ce78042e7b023e7c096e34002da5aa083920dd", size = 499551, upload-time = "2025-10-22T08:35:47.616Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "rmscript" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "numpy" }, + { name = "reachy-mini" }, +] + +[package.optional-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, + { name = "scipy" }, +] + +[package.metadata] +requires-dist = [ + { name = "numpy", specifier = ">=1.24.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, + { name = "reachy-mini", specifier = ">=1.0.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, + { name = "scipy", marker = "extra == 'dev'", specifier = ">=1.10.0" }, +] +provides-extras = ["dev"] + +[[package]] +name = "ruff" +version = "0.14.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/f0/62b5a1a723fe183650109407fa56abb433b00aa1c0b9ba555f9c4efec2c6/ruff-0.14.6.tar.gz", hash = "sha256:6f0c742ca6a7783a736b867a263b9a7a80a45ce9bee391eeda296895f1b4e1cc", size = 5669501, upload-time = "2025-11-21T14:26:17.903Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/d2/7dd544116d107fffb24a0064d41a5d2ed1c9d6372d142f9ba108c8e39207/ruff-0.14.6-py3-none-linux_armv6l.whl", hash = "sha256:d724ac2f1c240dbd01a2ae98db5d1d9a5e1d9e96eba999d1c48e30062df578a3", size = 13326119, upload-time = "2025-11-21T14:25:24.2Z" }, + { url = "https://files.pythonhosted.org/packages/36/6a/ad66d0a3315d6327ed6b01f759d83df3c4d5f86c30462121024361137b6a/ruff-0.14.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9f7539ea257aa4d07b7ce87aed580e485c40143f2473ff2f2b75aee003186004", size = 13526007, upload-time = "2025-11-21T14:25:26.906Z" }, + { url = "https://files.pythonhosted.org/packages/a3/9d/dae6db96df28e0a15dea8e986ee393af70fc97fd57669808728080529c37/ruff-0.14.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7f6007e55b90a2a7e93083ba48a9f23c3158c433591c33ee2e99a49b889c6332", size = 12676572, upload-time = "2025-11-21T14:25:29.826Z" }, + { url = "https://files.pythonhosted.org/packages/76/a4/f319e87759949062cfee1b26245048e92e2acce900ad3a909285f9db1859/ruff-0.14.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8e7b9d73d8728b68f632aa8e824ef041d068d231d8dbc7808532d3629a6bef", size = 13140745, upload-time = "2025-11-21T14:25:32.788Z" }, + { url = "https://files.pythonhosted.org/packages/95/d3/248c1efc71a0a8ed4e8e10b4b2266845d7dfc7a0ab64354afe049eaa1310/ruff-0.14.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d50d45d4553a3ebcbd33e7c5e0fe6ca4aafd9a9122492de357205c2c48f00775", size = 13076486, upload-time = "2025-11-21T14:25:35.601Z" }, + { url = "https://files.pythonhosted.org/packages/a5/19/b68d4563fe50eba4b8c92aa842149bb56dd24d198389c0ed12e7faff4f7d/ruff-0.14.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:118548dd121f8a21bfa8ab2c5b80e5b4aed67ead4b7567790962554f38e598ce", size = 13727563, upload-time = "2025-11-21T14:25:38.514Z" }, + { url = "https://files.pythonhosted.org/packages/47/ac/943169436832d4b0e867235abbdb57ce3a82367b47e0280fa7b4eabb7593/ruff-0.14.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:57256efafbfefcb8748df9d1d766062f62b20150691021f8ab79e2d919f7c11f", size = 15199755, upload-time = "2025-11-21T14:25:41.516Z" }, + { url = "https://files.pythonhosted.org/packages/c9/b9/288bb2399860a36d4bb0541cb66cce3c0f4156aaff009dc8499be0c24bf2/ruff-0.14.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff18134841e5c68f8e5df1999a64429a02d5549036b394fafbe410f886e1989d", size = 14850608, upload-time = "2025-11-21T14:25:44.428Z" }, + { url = "https://files.pythonhosted.org/packages/ee/b1/a0d549dd4364e240f37e7d2907e97ee80587480d98c7799d2d8dc7a2f605/ruff-0.14.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c4b7ec1e66a105d5c27bd57fa93203637d66a26d10ca9809dc7fc18ec58440", size = 14118754, upload-time = "2025-11-21T14:25:47.214Z" }, + { url = "https://files.pythonhosted.org/packages/13/ac/9b9fe63716af8bdfddfacd0882bc1586f29985d3b988b3c62ddce2e202c3/ruff-0.14.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167843a6f78680746d7e226f255d920aeed5e4ad9c03258094a2d49d3028b105", size = 13949214, upload-time = "2025-11-21T14:25:50.002Z" }, + { url = "https://files.pythonhosted.org/packages/12/27/4dad6c6a77fede9560b7df6802b1b697e97e49ceabe1f12baf3ea20862e9/ruff-0.14.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:16a33af621c9c523b1ae006b1b99b159bf5ac7e4b1f20b85b2572455018e0821", size = 14106112, upload-time = "2025-11-21T14:25:52.841Z" }, + { url = "https://files.pythonhosted.org/packages/6a/db/23e322d7177873eaedea59a7932ca5084ec5b7e20cb30f341ab594130a71/ruff-0.14.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1432ab6e1ae2dc565a7eea707d3b03a0c234ef401482a6f1621bc1f427c2ff55", size = 13035010, upload-time = "2025-11-21T14:25:55.536Z" }, + { url = "https://files.pythonhosted.org/packages/a8/9c/20e21d4d69dbb35e6a1df7691e02f363423658a20a2afacf2a2c011800dc/ruff-0.14.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4c55cfbbe7abb61eb914bfd20683d14cdfb38a6d56c6c66efa55ec6570ee4e71", size = 13054082, upload-time = "2025-11-21T14:25:58.625Z" }, + { url = "https://files.pythonhosted.org/packages/66/25/906ee6a0464c3125c8d673c589771a974965c2be1a1e28b5c3b96cb6ef88/ruff-0.14.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:efea3c0f21901a685fff4befda6d61a1bf4cb43de16da87e8226a281d614350b", size = 13303354, upload-time = "2025-11-21T14:26:01.816Z" }, + { url = "https://files.pythonhosted.org/packages/4c/58/60577569e198d56922b7ead07b465f559002b7b11d53f40937e95067ca1c/ruff-0.14.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:344d97172576d75dc6afc0e9243376dbe1668559c72de1864439c4fc95f78185", size = 14054487, upload-time = "2025-11-21T14:26:05.058Z" }, + { url = "https://files.pythonhosted.org/packages/67/0b/8e4e0639e4cc12547f41cb771b0b44ec8225b6b6a93393176d75fe6f7d40/ruff-0.14.6-py3-none-win32.whl", hash = "sha256:00169c0c8b85396516fdd9ce3446c7ca20c2a8f90a77aa945ba6b8f2bfe99e85", size = 13013361, upload-time = "2025-11-21T14:26:08.152Z" }, + { url = "https://files.pythonhosted.org/packages/fb/02/82240553b77fd1341f80ebb3eaae43ba011c7a91b4224a9f317d8e6591af/ruff-0.14.6-py3-none-win_amd64.whl", hash = "sha256:390e6480c5e3659f8a4c8d6a0373027820419ac14fa0d2713bd8e6c3e125b8b9", size = 14432087, upload-time = "2025-11-21T14:26:10.891Z" }, + { url = "https://files.pythonhosted.org/packages/a5/1f/93f9b0fad9470e4c829a5bb678da4012f0c710d09331b860ee555216f4ea/ruff-0.14.6-py3-none-win_arm64.whl", hash = "sha256:d43c81fbeae52cfa8728d8766bbf46ee4298c888072105815b392da70ca836b2", size = 13520930, upload-time = "2025-11-21T14:26:13.951Z" }, +] + +[[package]] +name = "scipy" +version = "1.16.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/5f/6f37d7439de1455ce9c5a556b8d1db0979f03a796c030bafdf08d35b7bf9/scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97", size = 36630881, upload-time = "2025-10-28T17:31:47.104Z" }, + { url = "https://files.pythonhosted.org/packages/7c/89/d70e9f628749b7e4db2aa4cd89735502ff3f08f7b9b27d2e799485987cd9/scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511", size = 28941012, upload-time = "2025-10-28T17:31:53.411Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a8/0e7a9a6872a923505dbdf6bb93451edcac120363131c19013044a1e7cb0c/scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005", size = 20931935, upload-time = "2025-10-28T17:31:57.361Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c7/020fb72bd79ad798e4dbe53938543ecb96b3a9ac3fe274b7189e23e27353/scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb", size = 23534466, upload-time = "2025-10-28T17:32:01.875Z" }, + { url = "https://files.pythonhosted.org/packages/be/a0/668c4609ce6dbf2f948e167836ccaf897f95fb63fa231c87da7558a374cd/scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876", size = 33593618, upload-time = "2025-10-28T17:32:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6e/8942461cf2636cdae083e3eb72622a7fbbfa5cf559c7d13ab250a5dbdc01/scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2", size = 35899798, upload-time = "2025-10-28T17:32:12.665Z" }, + { url = "https://files.pythonhosted.org/packages/79/e8/d0f33590364cdbd67f28ce79368b373889faa4ee959588beddf6daef9abe/scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e", size = 36226154, upload-time = "2025-10-28T17:32:17.961Z" }, + { url = "https://files.pythonhosted.org/packages/39/c1/1903de608c0c924a1749c590064e65810f8046e437aba6be365abc4f7557/scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733", size = 38878540, upload-time = "2025-10-28T17:32:23.907Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d0/22ec7036ba0b0a35bccb7f25ab407382ed34af0b111475eb301c16f8a2e5/scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78", size = 38722107, upload-time = "2025-10-28T17:32:29.921Z" }, + { url = "https://files.pythonhosted.org/packages/7b/60/8a00e5a524bb3bf8898db1650d350f50e6cffb9d7a491c561dc9826c7515/scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184", size = 25506272, upload-time = "2025-10-28T17:32:34.577Z" }, + { url = "https://files.pythonhosted.org/packages/40/41/5bf55c3f386b1643812f3a5674edf74b26184378ef0f3e7c7a09a7e2ca7f/scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6", size = 36659043, upload-time = "2025-10-28T17:32:40.285Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0f/65582071948cfc45d43e9870bf7ca5f0e0684e165d7c9ef4e50d783073eb/scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07", size = 28898986, upload-time = "2025-10-28T17:32:45.325Z" }, + { url = "https://files.pythonhosted.org/packages/96/5e/36bf3f0ac298187d1ceadde9051177d6a4fe4d507e8f59067dc9dd39e650/scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9", size = 20889814, upload-time = "2025-10-28T17:32:49.277Z" }, + { url = "https://files.pythonhosted.org/packages/80/35/178d9d0c35394d5d5211bbff7ac4f2986c5488b59506fef9e1de13ea28d3/scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686", size = 23565795, upload-time = "2025-10-28T17:32:53.337Z" }, + { url = "https://files.pythonhosted.org/packages/fa/46/d1146ff536d034d02f83c8afc3c4bab2eddb634624d6529a8512f3afc9da/scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203", size = 33349476, upload-time = "2025-10-28T17:32:58.353Z" }, + { url = "https://files.pythonhosted.org/packages/79/2e/415119c9ab3e62249e18c2b082c07aff907a273741b3f8160414b0e9193c/scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1", size = 35676692, upload-time = "2025-10-28T17:33:03.88Z" }, + { url = "https://files.pythonhosted.org/packages/27/82/df26e44da78bf8d2aeaf7566082260cfa15955a5a6e96e6a29935b64132f/scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe", size = 36019345, upload-time = "2025-10-28T17:33:09.773Z" }, + { url = "https://files.pythonhosted.org/packages/82/31/006cbb4b648ba379a95c87262c2855cd0d09453e500937f78b30f02fa1cd/scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70", size = 38678975, upload-time = "2025-10-28T17:33:15.809Z" }, + { url = "https://files.pythonhosted.org/packages/c2/7f/acbd28c97e990b421af7d6d6cd416358c9c293fc958b8529e0bd5d2a2a19/scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc", size = 38555926, upload-time = "2025-10-28T17:33:21.388Z" }, + { url = "https://files.pythonhosted.org/packages/ce/69/c5c7807fd007dad4f48e0a5f2153038dc96e8725d3345b9ee31b2b7bed46/scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2", size = 25463014, upload-time = "2025-10-28T17:33:25.975Z" }, + { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" }, + { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" }, + { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" }, + { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" }, + { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" }, + { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" }, + { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" }, + { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" }, + { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" }, + { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" }, + { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" }, + { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" }, + { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" }, + { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" }, + { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" }, + { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" }, + { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" }, + { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" }, + { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" }, + { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" }, + { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" }, + { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" }, + { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" }, + { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" }, + { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, +] + +[[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 = "sounddevice" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/2d/b04ae180312b81dbb694504bee170eada5372242e186f6298139fd3a0513/sounddevice-0.5.1.tar.gz", hash = "sha256:09ca991daeda8ce4be9ac91e15a9a81c8f81efa6b695a348c9171ea0c16cb041", size = 52896, upload-time = "2024-10-12T09:40:12.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/d1/464b5fca3decdd0cfec8c47f7b4161a0b12972453201c1bf03811f367c5e/sounddevice-0.5.1-py3-none-any.whl", hash = "sha256:e2017f182888c3f3c280d9fbac92e5dbddac024a7e3442f6e6116bd79dab8a9c", size = 32276, upload-time = "2024-10-12T09:40:05.605Z" }, + { url = "https://files.pythonhosted.org/packages/6f/f6/6703fe7cf3d7b7279040c792aeec6334e7305956aba4a80f23e62c8fdc44/sounddevice-0.5.1-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d16cb23d92322526a86a9490c427bf8d49e273d9ccc0bd096feecd229cde6031", size = 107916, upload-time = "2024-10-12T09:40:07.436Z" }, + { url = "https://files.pythonhosted.org/packages/57/a5/78a5e71f5ec0faedc54f4053775d61407bfbd7d0c18228c7f3d4252fd276/sounddevice-0.5.1-py3-none-win32.whl", hash = "sha256:d84cc6231526e7a08e89beff229c37f762baefe5e0cc2747cbe8e3a565470055", size = 312494, upload-time = "2024-10-12T09:40:09.355Z" }, + { url = "https://files.pythonhosted.org/packages/af/9b/15217b04f3b36d30de55fef542389d722de63f1ad81f9c72d8afc98cb6ab/sounddevice-0.5.1-py3-none-win_amd64.whl", hash = "sha256:4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1", size = 363634, upload-time = "2024-10-12T09:40:11.065Z" }, +] + +[[package]] +name = "soundfile" +version = "0.13.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/41/9b873a8c055582859b239be17902a85339bec6a30ad162f98c9b0288a2cc/soundfile-0.13.1.tar.gz", hash = "sha256:b2c68dab1e30297317080a5b43df57e302584c49e2942defdde0acccc53f0e5b", size = 46156, upload-time = "2025-01-25T09:17:04.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/28/e2a36573ccbcf3d57c00626a21fe51989380636e821b341d36ccca0c1c3a/soundfile-0.13.1-py2.py3-none-any.whl", hash = "sha256:a23c717560da2cf4c7b5ae1142514e0fd82d6bbd9dfc93a50423447142f2c445", size = 25751, upload-time = "2025-01-25T09:16:44.235Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ab/73e97a5b3cc46bba7ff8650a1504348fa1863a6f9d57d7001c6b67c5f20e/soundfile-0.13.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:82dc664d19831933fe59adad199bf3945ad06d84bc111a5b4c0d3089a5b9ec33", size = 1142250, upload-time = "2025-01-25T09:16:47.583Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e5/58fd1a8d7b26fc113af244f966ee3aecf03cb9293cb935daaddc1e455e18/soundfile-0.13.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:743f12c12c4054921e15736c6be09ac26b3b3d603aef6fd69f9dde68748f2593", size = 1101406, upload-time = "2025-01-25T09:16:49.662Z" }, + { url = "https://files.pythonhosted.org/packages/58/ae/c0e4a53d77cf6e9a04179535766b3321b0b9ced5f70522e4caf9329f0046/soundfile-0.13.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9c9e855f5a4d06ce4213f31918653ab7de0c5a8d8107cd2427e44b42df547deb", size = 1235729, upload-time = "2025-01-25T09:16:53.018Z" }, + { url = "https://files.pythonhosted.org/packages/57/5e/70bdd9579b35003a489fc850b5047beeda26328053ebadc1fb60f320f7db/soundfile-0.13.1-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:03267c4e493315294834a0870f31dbb3b28a95561b80b134f0bd3cf2d5f0e618", size = 1313646, upload-time = "2025-01-25T09:16:54.872Z" }, + { url = "https://files.pythonhosted.org/packages/fe/df/8c11dc4dfceda14e3003bb81a0d0edcaaf0796dd7b4f826ea3e532146bba/soundfile-0.13.1-py2.py3-none-win32.whl", hash = "sha256:c734564fab7c5ddf8e9be5bf70bab68042cd17e9c214c06e365e20d64f9a69d5", size = 899881, upload-time = "2025-01-25T09:16:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/14/e9/6b761de83277f2f02ded7e7ea6f07828ec78e4b229b80e4ca55dd205b9dc/soundfile-0.13.1-py2.py3-none-win_amd64.whl", hash = "sha256:1e70a05a0626524a69e9f0f4dd2ec174b4e9567f4d8b6c11d38b5c289be36ee9", size = 1019162, upload-time = "2025-01-25T09:16:59.573Z" }, +] + +[[package]] +name = "starlette" +version = "0.50.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[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 = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/f06b84e2697fef4688ca63bdb2fdf113ca0a3be33f94488f2cadb690b0cf/uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d", size = 80605, upload-time = "2025-10-18T13:46:44.63Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109, upload-time = "2025-10-18T13:46:42.958Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9", size = 1352420, upload-time = "2025-10-16T22:16:21.187Z" }, + { url = "https://files.pythonhosted.org/packages/a8/73/c4e271b3bce59724e291465cc936c37758886a4868787da0278b3b56b905/uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77", size = 748677, upload-time = "2025-10-16T22:16:22.558Z" }, + { url = "https://files.pythonhosted.org/packages/86/94/9fb7fad2f824d25f8ecac0d70b94d0d48107ad5ece03769a9c543444f78a/uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21", size = 3753819, upload-time = "2025-10-16T22:16:23.903Z" }, + { url = "https://files.pythonhosted.org/packages/74/4f/256aca690709e9b008b7108bc85fba619a2bc37c6d80743d18abad16ee09/uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702", size = 3804529, upload-time = "2025-10-16T22:16:25.246Z" }, + { url = "https://files.pythonhosted.org/packages/7f/74/03c05ae4737e871923d21a76fe28b6aad57f5c03b6e6bfcfa5ad616013e4/uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733", size = 3621267, upload-time = "2025-10-16T22:16:26.819Z" }, + { url = "https://files.pythonhosted.org/packages/75/be/f8e590fe61d18b4a92070905497aec4c0e64ae1761498cad09023f3f4b3e/uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473", size = 3723105, upload-time = "2025-10-16T22:16:28.252Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, + { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, + { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" }, + { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/60249e9fd07b32c665192cec7af29e06c7cd96fa1d08b84f012a56a0b38e/uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25", size = 4292101, upload-time = "2025-10-16T22:16:49.318Z" }, + { url = "https://files.pythonhosted.org/packages/02/62/67d382dfcb25d0a98ce73c11ed1a6fba5037a1a1d533dcbb7cab033a2636/uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6", size = 4114158, upload-time = "2025-10-16T22:16:50.517Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/f1171b4a882a5d13c8b7576f348acfe6074d72eaf52cccef752f748d4a9f/uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079", size = 4177360, upload-time = "2025-10-16T22:16:52.646Z" }, + { url = "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289", size = 1454790, upload-time = "2025-10-16T22:16:54.355Z" }, + { url = "https://files.pythonhosted.org/packages/d4/31/0bb232318dd838cad3fa8fb0c68c8b40e1145b32025581975e18b11fab40/uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3", size = 796783, upload-time = "2025-10-16T22:16:55.906Z" }, + { url = "https://files.pythonhosted.org/packages/42/38/c9b09f3271a7a723a5de69f8e237ab8e7803183131bc57c890db0b6bb872/uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c", size = 4647548, upload-time = "2025-10-16T22:16:57.008Z" }, + { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" }, + { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f8/2c5f479fb531ce2f0564eda479faecf253d886b1ab3630a39b7bf7362d46/watchfiles-1.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f57b396167a2565a4e8b5e56a5a1c537571733992b226f4f1197d79e94cf0ae5", size = 406529, upload-time = "2025-10-14T15:04:32.899Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cd/f515660b1f32f65df671ddf6f85bfaca621aee177712874dc30a97397977/watchfiles-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:421e29339983e1bebc281fab40d812742268ad057db4aee8c4d2bce0af43b741", size = 394384, upload-time = "2025-10-14T15:04:33.761Z" }, + { url = "https://files.pythonhosted.org/packages/7b/c3/28b7dc99733eab43fca2d10f55c86e03bd6ab11ca31b802abac26b23d161/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e43d39a741e972bab5d8100b5cdacf69db64e34eb19b6e9af162bccf63c5cc6", size = 448789, upload-time = "2025-10-14T15:04:34.679Z" }, + { url = "https://files.pythonhosted.org/packages/4a/24/33e71113b320030011c8e4316ccca04194bf0cbbaeee207f00cbc7d6b9f5/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f537afb3276d12814082a2e9b242bdcf416c2e8fd9f799a737990a1dbe906e5b", size = 460521, upload-time = "2025-10-14T15:04:35.963Z" }, + { url = "https://files.pythonhosted.org/packages/f4/c3/3c9a55f255aa57b91579ae9e98c88704955fa9dac3e5614fb378291155df/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2cd9e04277e756a2e2d2543d65d1e2166d6fd4c9b183f8808634fda23f17b14", size = 488722, upload-time = "2025-10-14T15:04:37.091Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/506447b73eb46c120169dc1717fe2eff07c234bb3232a7200b5f5bd816e9/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3f58818dc0b07f7d9aa7fe9eb1037aecb9700e63e1f6acfed13e9fef648f5d", size = 596088, upload-time = "2025-10-14T15:04:38.39Z" }, + { url = "https://files.pythonhosted.org/packages/82/ab/5f39e752a9838ec4d52e9b87c1e80f1ee3ccdbe92e183c15b6577ab9de16/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb9f66367023ae783551042d31b1d7fd422e8289eedd91f26754a66f44d5cff", size = 472923, upload-time = "2025-10-14T15:04:39.666Z" }, + { url = "https://files.pythonhosted.org/packages/af/b9/a419292f05e302dea372fa7e6fda5178a92998411f8581b9830d28fb9edb/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aebfd0861a83e6c3d1110b78ad54704486555246e542be3e2bb94195eabb2606", size = 456080, upload-time = "2025-10-14T15:04:40.643Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c3/d5932fd62bde1a30c36e10c409dc5d54506726f08cb3e1d8d0ba5e2bc8db/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5fac835b4ab3c6487b5dbad78c4b3724e26bcc468e886f8ba8cc4306f68f6701", size = 629432, upload-time = "2025-10-14T15:04:41.789Z" }, + { url = "https://files.pythonhosted.org/packages/f7/77/16bddd9779fafb795f1a94319dc965209c5641db5bf1edbbccace6d1b3c0/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:399600947b170270e80134ac854e21b3ccdefa11a9529a3decc1327088180f10", size = 623046, upload-time = "2025-10-14T15:04:42.718Z" }, + { url = "https://files.pythonhosted.org/packages/46/ef/f2ecb9a0f342b4bfad13a2787155c6ee7ce792140eac63a34676a2feeef2/watchfiles-1.1.1-cp311-cp311-win32.whl", hash = "sha256:de6da501c883f58ad50db3a32ad397b09ad29865b5f26f64c24d3e3281685849", size = 271473, upload-time = "2025-10-14T15:04:43.624Z" }, + { url = "https://files.pythonhosted.org/packages/94/bc/f42d71125f19731ea435c3948cad148d31a64fccde3867e5ba4edee901f9/watchfiles-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:35c53bd62a0b885bf653ebf6b700d1bf05debb78ad9292cf2a942b23513dc4c4", size = 287598, upload-time = "2025-10-14T15:04:44.516Z" }, + { url = "https://files.pythonhosted.org/packages/57/c9/a30f897351f95bbbfb6abcadafbaca711ce1162f4db95fc908c98a9165f3/watchfiles-1.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:57ca5281a8b5e27593cb7d82c2ac927ad88a96ed406aa446f6344e4328208e9e", size = 277210, upload-time = "2025-10-14T15:04:45.883Z" }, + { url = "https://files.pythonhosted.org/packages/74/d5/f039e7e3c639d9b1d09b07ea412a6806d38123f0508e5f9b48a87b0a76cc/watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d", size = 404745, upload-time = "2025-10-14T15:04:46.731Z" }, + { url = "https://files.pythonhosted.org/packages/a5/96/a881a13aa1349827490dab2d363c8039527060cfcc2c92cc6d13d1b1049e/watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610", size = 391769, upload-time = "2025-10-14T15:04:48.003Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5b/d3b460364aeb8da471c1989238ea0e56bec24b6042a68046adf3d9ddb01c/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af", size = 449374, upload-time = "2025-10-14T15:04:49.179Z" }, + { url = "https://files.pythonhosted.org/packages/b9/44/5769cb62d4ed055cb17417c0a109a92f007114a4e07f30812a73a4efdb11/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6", size = 459485, upload-time = "2025-10-14T15:04:50.155Z" }, + { url = "https://files.pythonhosted.org/packages/19/0c/286b6301ded2eccd4ffd0041a1b726afda999926cf720aab63adb68a1e36/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce", size = 488813, upload-time = "2025-10-14T15:04:51.059Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2b/8530ed41112dd4a22f4dcfdb5ccf6a1baad1ff6eed8dc5a5f09e7e8c41c7/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa", size = 594816, upload-time = "2025-10-14T15:04:52.031Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d2/f5f9fb49489f184f18470d4f99f4e862a4b3e9ac2865688eb2099e3d837a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb", size = 475186, upload-time = "2025-10-14T15:04:53.064Z" }, + { url = "https://files.pythonhosted.org/packages/cf/68/5707da262a119fb06fbe214d82dd1fe4a6f4af32d2d14de368d0349eb52a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803", size = 456812, upload-time = "2025-10-14T15:04:55.174Z" }, + { url = "https://files.pythonhosted.org/packages/66/ab/3cbb8756323e8f9b6f9acb9ef4ec26d42b2109bce830cc1f3468df20511d/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94", size = 630196, upload-time = "2025-10-14T15:04:56.22Z" }, + { url = "https://files.pythonhosted.org/packages/78/46/7152ec29b8335f80167928944a94955015a345440f524d2dfe63fc2f437b/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43", size = 622657, upload-time = "2025-10-14T15:04:57.521Z" }, + { url = "https://files.pythonhosted.org/packages/0a/bf/95895e78dd75efe9a7f31733607f384b42eb5feb54bd2eb6ed57cc2e94f4/watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9", size = 272042, upload-time = "2025-10-14T15:04:59.046Z" }, + { url = "https://files.pythonhosted.org/packages/87/0a/90eb755f568de2688cb220171c4191df932232c20946966c27a59c400850/watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9", size = 288410, upload-time = "2025-10-14T15:05:00.081Z" }, + { url = "https://files.pythonhosted.org/packages/36/76/f322701530586922fbd6723c4f91ace21364924822a8772c549483abed13/watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404", size = 278209, upload-time = "2025-10-14T15:05:01.168Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, + { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, + { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, + { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, + { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, + { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, + { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, + { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, + { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, + { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, + { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, + { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, + { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, + { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" }, + { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" }, + { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" }, + { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" }, + { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" }, + { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" }, + { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" }, + { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" }, + { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" }, + { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" }, + { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" }, + { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, + { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, + { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8e/e500f8b0b77be4ff753ac94dc06b33d8f0d839377fee1b78e8c8d8f031bf/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db476ab59b6765134de1d4fe96a1a9c96ddf091683599be0f26147ea1b2e4b88", size = 408250, upload-time = "2025-10-14T15:06:10.264Z" }, + { url = "https://files.pythonhosted.org/packages/bd/95/615e72cd27b85b61eec764a5ca51bd94d40b5adea5ff47567d9ebc4d275a/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89eef07eee5e9d1fda06e38822ad167a044153457e6fd997f8a858ab7564a336", size = 396117, upload-time = "2025-10-14T15:06:11.28Z" }, + { url = "https://files.pythonhosted.org/packages/c9/81/e7fe958ce8a7fb5c73cc9fb07f5aeaf755e6aa72498c57d760af760c91f8/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce19e06cbda693e9e7686358af9cd6f5d61312ab8b00488bc36f5aabbaf77e24", size = 450493, upload-time = "2025-10-14T15:06:12.321Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" }, +] + +[[package]] +name = "websockets" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +] + +[[package]] +name = "yarl" +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, + { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, + { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, + { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, + { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, + { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, + { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, + { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, + { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, + { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, + { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, + { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, + { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" }, + { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" }, + { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" }, + { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" }, + { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" }, + { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" }, + { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" }, + { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" }, + { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" }, + { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" }, + { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" }, + { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, + { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, + { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, + { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, + { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, + { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, + { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, + { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, + { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, + { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, + { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, + { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, + { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, + { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, + { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, + { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, + { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, + { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, + { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, + { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, + { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, + { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +]