commit ddbb79b9f678c6f016ca788c69adf3c3f8ca9898 Author: xiaopeng <1509442308@qq.com> Date: Fri May 22 09:40:18 2026 +0800 Initial commit: 国土空间规划课程智能体 v1.0 单容器 Docker 架构的国土空间规划课程智能问答系统,集成 FastAPI 后端与 Next.js 前端。 Co-Authored-By: Claude Opus 4.7 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a85a04c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,79 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info/ +dist/ +build/ +.venv/ +venv/ +env/ +ENV/ + +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* +.next/ +out/ +build/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +logs/ + +# Database +*.db +*.sqlite +*.sqlite3 + +# Data directories (will be mounted as volumes) +data/ +vector_store/ +uploads/ +generated_images/ + +# Git +.git/ +.gitignore + +# Docker +Dockerfile* +docker-compose*.yml +.dockerignore + +# Documentation +*.md +!README.md + +# Environment files +.env +.env.local +.env.*.local + +# Test files +tests/ +test_*.py +*_test.py + +# Temporary files +*.tmp +*.temp +.cache/ + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..25e579c --- /dev/null +++ b/.gitignore @@ -0,0 +1,68 @@ +# 环境变量与密钥 +.env +.env.local +.env.*.local + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.venv/ +venv/ +env/ +*.egg-info/ +dist/ +build/ + +# Node.js +node_modules/ +.next/ +out/ + +# 运行时数据 +runtime/ +vector_store/ +logs/ +*.log + +# 上传与生成文件 +uploads/ +generated_images/ + +# 数据目录中的运行时文件(保留源文件如 .tex) +data/database/ +data/knowledge_base/ + +# LaTeX 中间文件 +*.aux +*.bbl +*.blg +*.toc +*.out +*.fdb_latexmk +*.fls +*.synctex.gz + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Claude Code +.claude/ + +# OS +.DS_Store +Thumbs.db +Desktop.ini + +# 其他 +*.tmp +*.temp +.cache/ +*.coverage +.coverage +htmlcov/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..aca23a8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,136 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +国土空间规划课程智能体 (Territorial Spatial Planning Course Agent) — an AI-powered Q&A system for a territorial spatial planning course. Single-container Docker deployment with supervisor managing a FastAPI backend and Next.js frontend. + +## Development Commands + +### Local Development + +**Backend** (from project root): +```bash +cd backend +uv sync # install Python deps (requires uv >= 0.6.15, Python >= 3.12) +uv run main.py # start backend on :8000 +``` + +**Frontend** (separate terminal): +```bash +cd web +pnpm install # install Node deps (pnpm 10.6.5) +pnpm dev # start Next.js on :8001 with Turbopack +pnpm build # production build +pnpm check # lint + typecheck +pnpm lint:fix # auto-fix lint issues +``` + +### Docker + +```bash +docker-compose up -d # build & start all services +docker-compose logs -f app # follow logs +docker-compose exec app bash # shell into container +docker-compose exec db psql -U user -d course_agent_db # database shell +``` + +Ports: backend API `:8000`, frontend `:8001`, PostgreSQL `:5433` (mapped from container's 5432). + +### Environment Setup + +Copy `env.example` to `.env` and configure. Critical variables: +- `SILICONFLOW_API_KEY` — LLM provider API key +- `DATABASE_URL` — `sqlite:///...` for local dev, `postgresql+psycopg://...` for Docker +- `SECRET_KEY` — JWT signing key + +## Architecture + +### Backend (`backend/src/`) + +``` +api/ FastAPI routers: auth, chat, document, image, knowledge_base, + course_content, forum, analytics +core/ config.py (pydantic-settings), database.py (SQLAlchemy, lazy engine), + security.py (JWT) +llm/ siliconflow.py — ChatOpenAI wrapper over SiliconFlow API +rag/ The RAG pipeline: + embeddings.py → SentenceTransformer (text2vec-base-chinese) + vector_store.py → Chroma singleton (langchain-chroma) + retrievers.py → KnowledgeBaseRetriever (BaseRetriever subclass, + filters by knowledge_base_id, distance→score conversion) + chains.py → RAGChain (LangChain Runnable API, supports + invoke/ainvoke/astream/astream_with_sources) + conversation_chains.py → non-RAG conversation chain + prompts.py → prompt templates +graph/ LangGraph workflow: qa_graph.py defines a linear pipeline + analyze → retrieve → generate → format + (nodes.py has the node implementations) +models/ SQLAlchemy ORM: User, ChatSession, ChatMessage, Document, + DocumentChunk, KnowledgeBase, Book/Chapter/Section/Subsection, + ForumCategory/Post/Reply, GeneratedImage, CourseModule +services/ Business logic: auth, document processing, knowledge base management, + LaTeX parser, file watcher, image generation (text-to-image, image-to-image) +migrations/ Database migration scripts +``` + +### Frontend (`web/src/`) + +Next.js 15 App Router + React 19 + TypeScript + TailwindCSS + shadcn/ui. + +``` +app/ + (auth)/ login, register pages + (main)/ chat, knowledge, course-content, forum, analytics, + spatial (text-to-image, image-to-image), profile, settings +components/ + chat/ chat-interface, message-list, sidebar, knowledge-selector, + model-selector, mode-selector, source-references + course-content/ knowledge-graph, node-detail-dialog + home/ landing page sections + ui/ shadcn/ui primitives +store/ + auth.ts Zustand auth store + chat.ts Zustand chat store (session management, streaming SSE handling) +lib/ + api.ts All API client functions (auth, chat, image, knowledgeBase, + document, forum, analytics, courseContent, book) + auth.ts NextAuth config +types/index.ts TypeScript type definitions +``` + +### Key Data Flows + +**Chat modes:** +- `normal` — ConversationChain (LLM only, with chat history) +- `rag` — RAGChain: embed query → Chroma similarity search (filtered by `knowledge_base_ids`) → LLM answer generation + +**Streaming:** Backend sends SSE events (`data: {type: "thinking"|"chunk"|"sources"|"done", ...}`). Frontend's Zustand store accumulates chunks via `requestAnimationFrame` updates. + +**Knowledge base pipeline:** Upload PDF/DOCX/TXT/MD → `document_service` extracts text → `text_splitters` chunks → embeddings → stored in Chroma with `knowledge_base_id` metadata for filtering. + +**LLM integration:** All LLM calls go through `SiliconFlowLLM` which wraps `ChatOpenAI` pointed at SiliconFlow API (`https://api.siliconflow.cn/v1`). Default model is configurable via `SILICONFLOW_MODEL` env var. Supports model selection per-request via `model` parameter. + +### Database + +SQLAlchemy ORM with dual support: +- **SQLite** — local development default +- **PostgreSQL** — Docker deployment (lazy engine initialization with retry for DNS resolution) + +Engine creation is deferred (lazy) to handle Docker startup ordering — the engine connects only on first actual use, with 10 retries. + +## Docker Deployment + +Multi-stage `Dockerfile`: (1) builds Next.js frontend, (2) installs Python deps via uv, (3) final slim image with Node.js + supervisor. `supervisord` manages both `uvicorn` (backend) and `next start` (frontend) in a single container. + +Persistent volumes: `./data`, `./runtime` (contains vector_store, logs, generated_images). + +## Code Conventions + +- Backend Python code uses Chinese docstrings and log messages; variable/function names in English +- Ruff for Python linting (line-length 88, target Python 3.12) +- Frontend uses pnpm (not npm/yarn), ESLint + Prettier with Tailwind plugin +- API responses are JSON; streaming uses SSE (`text/plain` with `data: {...}\n\n` lines) +- All API endpoints require JWT auth except login/register; tokens stored in `localStorage` as `auth_token` +- Embedding model downloads go through `HF_ENDPOINT=https://hf-mirror.com` (China mirror) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..85aa594 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,146 @@ +# 多阶段构建:整合前端和后端到单个容器 + +# ==================== 阶段1: 构建前端 ==================== +FROM node:22-alpine AS frontend-builder + +# 安装pnpm +RUN npm install -g pnpm + +# 设置工作目录 +WORKDIR /app/web + +# 复制前端依赖文件 +COPY web/package.json web/pnpm-lock.yaml* ./ + +# 安装依赖 +RUN pnpm install --frozen-lockfile + +# 复制前端源代码 +COPY web/src ./src +COPY web/public ./public +COPY web/next.config.js ./ +COPY web/tailwind.config.ts ./ +COPY web/postcss.config.js ./ +COPY web/tsconfig.json ./ +COPY web/next-env.d.ts ./ + +# 构建前端应用 +RUN pnpm build + +# ==================== 阶段2: 准备后端 ==================== +FROM python:3.12-slim AS backend-builder + +# 设置工作目录 +WORKDIR /app + +# 设置环境变量 +ENV PYTHONPATH=/app +ENV PYTHONUNBUFFERED=1 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV TZ=Asia/Shanghai +ENV UV_HTTP_TIMEOUT=600 + +# 安装系统依赖 +RUN apt-get update && apt-get install -y \ + curl \ + gcc \ + g++ \ + libpq-dev \ + postgresql-client \ + poppler-utils \ + libmagic1 \ + && rm -rf /var/lib/apt/lists/* + +# 设置时区 +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# 配置 pip 使用国内镜像源 +RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple + +# 安装uv +RUN pip install uv + +# 复制后端依赖文件(包括README.md,因为pyproject.toml引用了它) +COPY backend/pyproject.toml backend/uv.lock ./ +COPY backend/README.md* ./ + +# 安装Python依赖 +RUN UV_HTTP_TIMEOUT=600 uv sync --frozen + +# ==================== 阶段3: 最终镜像 ==================== +FROM python:3.12-slim + +# 设置工作目录 +WORKDIR /app + +# 设置环境变量 +ENV PYTHONPATH=/app +ENV PYTHONUNBUFFERED=1 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV TZ=Asia/Shanghai +ENV NODE_ENV=production +ENV PORT=8001 +ENV HOSTNAME=0.0.0.0 + +# 安装系统依赖(包括 Node.js 用于运行前端) +RUN apt-get update && apt-get install -y \ + curl \ + gcc \ + g++ \ + libpq-dev \ + postgresql-client \ + poppler-utils \ + libmagic1 \ + nodejs \ + npm \ + supervisor \ + && rm -rf /var/lib/apt/lists/* + +# 设置时区 +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# 安装uv +RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \ + pip install uv + +# 从后端构建阶段复制Python虚拟环境 +# uv 会在 /app/.venv 创建虚拟环境 +COPY --from=backend-builder /app/.venv /app/.venv + +# 复制后端代码和依赖文件 +COPY backend/pyproject.toml backend/uv.lock ./ +COPY backend/src ./src +COPY backend/main.py ./ +COPY backend/migrations ./migrations +COPY backend/scripts ./scripts + +# 确保使用虚拟环境中的Python +ENV PATH="/app/.venv/bin:$PATH" + +# 从前端构建阶段复制构建产物 +COPY --from=frontend-builder /app/web/.next/standalone ./web +COPY --from=frontend-builder /app/web/.next/static ./web/.next/static +COPY --from=frontend-builder /app/web/public ./web/public + +# 创建必要的目录 +RUN mkdir -p /app/data /app/vector_store /app/uploads /app/logs /app/generated_images && \ + chmod 755 /app/data /app/vector_store /app/uploads /app/logs /app/generated_images + +# 创建supervisor配置文件 +RUN mkdir -p /etc/supervisor/conf.d +COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf + +# 创建启动脚本 +COPY docker/start.sh /app/start.sh +RUN chmod +x /app/start.sh + +# 暴露端口 +EXPOSE 8000 8001 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:8000/health && curl -f http://localhost:8001 || exit 1 + +# 启动命令 +CMD ["/app/start.sh"] + diff --git a/README.md b/README.md new file mode 100644 index 0000000..92f59de --- /dev/null +++ b/README.md @@ -0,0 +1,291 @@ +# 国土空间规划课程智能体 - Docker单容器版本 + +一个基于大模型的智能问答系统,专门为国土空间规划课程设计。本版本将所有服务整合到单个Docker容器中,简化部署和管理。 + +## 🎯 项目特色 + +- **单容器架构**: 前端和后端服务整合在一个容器中,使用supervisor管理进程 +- **AI驱动**: 集成硅基流动大模型和LangGraph工作流 +- **RAG增强**: 基于Chroma向量数据库的智能检索 +- **响应式设计**: 完美适配手机、平板、桌面设备 +- **现代化技术栈**: Next.js 15 + React 19 + FastAPI + Python 3.12 + +## 🏗️ 技术架构 + +### 单容器架构 + +``` +┌─────────────────────────────────────┐ +│ Docker Container │ +│ ┌─────────────┐ ┌──────────────┐ │ +│ │ Backend │ │ Frontend │ │ +│ │ FastAPI │ │ Next.js │ │ +│ │ :8000 │ │ :8001 │ │ +│ └─────────────┘ └──────────────┘ │ +│ │ │ │ +│ └──────┬─────────┘ │ +│ Supervisor │ +└─────────────────────────────────────┘ + │ + ▼ + ┌──────────────────┐ + │ PostgreSQL │ + │ Database │ + └──────────────────┘ +``` + +### 技术栈 + +**后端**: +- FastAPI + Uvicorn +- LangChain + LangGraph +- 硅基流动API (Qwen3-30B) +- Chroma向量数据库 +- PostgreSQL + +**前端**: +- Next.js 15 (App Router) +- React 19 +- TypeScript +- TailwindCSS + shadcn/ui + +## 📁 项目结构 + +``` +course_Agent/ +├── backend/ # Python后端代码 +│ ├── src/ # 源代码 +│ ├── main.py # 应用入口 +│ ├── pyproject.toml # 依赖配置 +│ └── migrations/ # 数据库迁移 +├── web/ # Next.js前端代码 +│ ├── src/ # 源代码 +│ ├── public/ # 静态资源 +│ └── package.json # 依赖配置 +├── docker/ # Docker相关文件 +│ ├── supervisord.conf # Supervisor配置 +│ └── start.sh # 启动脚本 +├── data/ # 数据目录(挂载卷) +├── vector_store/ # 向量数据库(挂载卷) +├── uploads/ # 上传文件(挂载卷) +├── logs/ # 日志文件(挂载卷) +├── generated_images/ # 生成的图像(挂载卷) +├── Dockerfile # Docker构建文件 +├── docker-compose.yml # Docker Compose配置 +└── README.md # 本文件 +``` + +## 🚀 快速开始 + +### 前置要求 + +- Docker 20.10+ +- Docker Compose 2.0+ + +### 1. 克隆项目 + +```bash +cd course_Agent +``` + +### 2. 配置环境变量 + +复制环境变量模板: + +```bash +cp env.example .env +``` + +编辑 `.env` 文件,配置必要的参数(API密钥、数据库密码等)。 + +### 3. 启动服务 + +```bash +# 构建并启动所有服务 +docker-compose up -d + +# 查看日志 +docker-compose logs -f + +# 查看服务状态 +docker-compose ps +``` + +### 4. 访问应用 + +- **前端应用**: http://localhost:8001 +- **后端API**: http://localhost:8000 +- **API文档**: http://localhost:8000/docs + +### 5. 停止服务 + +```bash +docker-compose down +``` + +## 🔧 服务管理 + +### 查看日志 + +```bash +# 查看所有服务日志 +docker-compose logs -f + +# 查看特定服务日志 +docker-compose logs -f app +docker-compose logs -f db +``` + +### 重启服务 + +```bash +# 重启所有服务 +docker-compose restart + +# 重启特定服务 +docker-compose restart app +``` + +### 进入容器 + +```bash +# 进入应用容器 +docker-compose exec app bash + +# 在容器内查看进程状态 +supervisorctl status +``` + +### 数据库操作 + +```bash +# 进入数据库容器 +docker-compose exec db psql -U user -d course_agent_db + +# 备份数据库 +docker-compose exec db pg_dump -U user course_agent_db > backup.sql + +# 恢复数据库 +docker-compose exec -T db psql -U user course_agent_db < backup.sql +``` + +## 📊 数据持久化 + +以下目录通过Docker volumes挂载,数据会持久化到宿主机: + +- `./data` → `/app/data` - 知识库数据 +- `./vector_store` → `/app/vector_store` - 向量数据库 +- `./uploads` → `/app/uploads` - 用户上传文件 +- `./logs` → `/app/logs` - 日志文件 +- `./generated_images` → `/app/generated_images` - 生成的图像 + +## 🔍 故障排除 + +### 服务无法启动 + +1. 检查端口是否被占用: +```bash +netstat -ano | findstr :8000 +netstat -ano | findstr :8001 +``` + +2. 查看容器日志: +```bash +docker-compose logs app +``` + +3. 检查环境变量配置: +```bash +docker-compose exec app env | grep DATABASE_URL +``` + +### 数据库连接失败 + +1. 确保数据库服务已启动: +```bash +docker-compose ps db +``` + +2. 检查数据库连接字符串: +```bash +docker-compose exec app env | grep DATABASE_URL +``` + +### 前端无法访问后端 + +1. 检查后端服务是否运行: +```bash +curl http://localhost:8000/health +``` + +2. 检查CORS配置: +```bash +docker-compose exec app env | grep ALLOWED_ORIGINS +``` + +## 🛠️ 开发指南 + +### 本地开发 + +如果需要本地开发(不使用Docker): + +1. **启动后端**: +```bash +cd backend +uv sync +uv run main.py +``` + +2. **启动前端** (新终端): +```bash +cd web +pnpm install +pnpm dev +``` + +### 修改代码后重建镜像 + +```bash +# 重新构建镜像 +docker-compose build app + +# 重启服务 +docker-compose up -d app +``` + +## 📝 环境变量说明 + +主要环境变量(完整列表见 `env.example`): + +- `DATABASE_URL`: 数据库连接字符串 +- `SILICONFLOW_API_KEY`: 硅基流动API密钥 +- `SECRET_KEY`: JWT密钥 +- `VECTOR_STORE_PATH`: 向量数据库路径 +- `KNOWLEDGE_BASE_DIR`: 知识库目录 + +## 🔐 安全建议 + +1. **生产环境**: + - 修改所有默认密码和密钥 + - 使用强密码 + - 配置HTTPS(通过Nginx反向代理) + - 限制数据库访问 + +2. **数据备份**: + - 定期备份PostgreSQL数据库 + - 备份向量数据库和知识库文件 + +## 📄 许可证 + +MIT License + +## 📞 技术支持 + +如有问题或建议,请联系开发团队。 + +--- + +**版本**: v1.0.0 (单容器版本) +**最后更新**: 2025年1月 + + diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..4f3f845 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,32 @@ +# 国土空间规划课程智能体后端服务 + +基于FastAPI和LangGraph的智能问答系统后端服务。 + +## 技术栈 + +- **框架**: FastAPI + Uvicorn +- **AI框架**: LangChain + LangGraph +- **大模型**: 硅基流动API (Qwen3-30B) +- **向量数据库**: Chroma +- **数据库**: PostgreSQL + +## 快速开始 + +### 使用Docker(推荐) + +```bash +docker-compose up -d +``` + +### 本地开发 + +```bash +uv sync +uv run main.py +``` + +## API文档 + +启动服务后访问:http://localhost:8000/docs + + diff --git a/backend/init_postgres.sql b/backend/init_postgres.sql new file mode 100644 index 0000000..4fa58b8 --- /dev/null +++ b/backend/init_postgres.sql @@ -0,0 +1,26 @@ +-- PostgreSQL数据库初始化脚本 +-- 为国土空间规划课程智能体创建扩展和配置 + +-- 创建扩展(如果需要) +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +-- 设置数据库编码(lc_collate 和 lc_ctype 只能在创建数据库时设置,不能通过 ALTER DATABASE 修改) +ALTER DATABASE course_agent_db SET client_encoding TO 'UTF8'; + +-- 创建表空间(可选) +-- CREATE TABLESPACE course_agent_space LOCATION '/var/lib/postgresql/data'; + +-- 设置搜索路径 +ALTER DATABASE course_agent_db SET search_path TO public; + +-- 创建用于监控的只读用户(可选) +-- CREATE USER monitor WITH PASSWORD 'monitor_password'; +-- GRANT CONNECT ON DATABASE course_agent_db TO monitor; +-- GRANT USAGE ON SCHEMA public TO monitor; +-- GRANT SELECT ON ALL TABLES IN SCHEMA public TO monitor; + +-- 设置连接限制 +ALTER DATABASE course_agent_db CONNECTION LIMIT 100; + +-- 记录初始化完成 +COMMENT ON DATABASE course_agent_db IS '国土空间规划课程智能体数据库 - 初始化于 ' || current_timestamp; diff --git a/backend/main.py b/backend/main.py new file mode 100644 index 0000000..8f1a70d --- /dev/null +++ b/backend/main.py @@ -0,0 +1,275 @@ +""" +国土空间规划课程智能体后端服务 +FastAPI应用入口 +""" +import os +import sys +from pathlib import Path +from datetime import datetime +from fastapi import FastAPI, HTTPException +from fastapi.middleware.cors import CORSMiddleware +from fastapi.staticfiles import StaticFiles +from fastapi.responses import FileResponse +import uvicorn + +# 设置系统时区为北京时间 +os.environ['TZ'] = 'Asia/Shanghai' + +# 添加src目录到Python路径 +sys.path.append(str(Path(__file__).parent / "src")) + +from src.core.config import get_settings, ensure_directories, is_postgresql_database +from src.core.database import create_tables, check_database_connection, get_database_info +from src.api import auth, chat + +# 获取配置 +settings = get_settings() + +# 确保必要目录存在 +ensure_directories() + +# 创建FastAPI应用 +app = FastAPI( + title=settings.app_name, + version=settings.app_version, + description="基于大模型的国土空间规划课程智能体系统", + docs_url="/docs", + redoc_url="/redoc" +) + +# 配置CORS +app.add_middleware( + CORSMiddleware, + allow_origins=settings.allowed_origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +# 启动知识库文件监控服务 +def startup_knowledge_base(): + """启动知识库服务""" + try: + from src.services.file_watcher_service import start_file_watcher + start_file_watcher() + print("知识库文件监控服务启动成功") + except Exception as e: + print(f"启动知识库文件监控服务失败: {str(e)}") + +# 应用启动事件 +@app.on_event("startup") +async def startup_event(): + """应用启动时执行""" + import time + import asyncio + import sys + + print("=" * 50, file=sys.stderr) + print("应用启动事件开始", file=sys.stderr) + print("=" * 50, file=sys.stderr) + sys.stderr.flush() + + # 等待数据库可用(重试机制,处理 DNS 解析延迟) + max_retries = 10 + retry_delay = 2 + + for attempt in range(max_retries): + try: + print(f"尝试连接数据库(尝试 {attempt + 1}/{max_retries})...", file=sys.stderr) + sys.stderr.flush() + # 尝试创建数据库表 + create_tables() + print("数据库表创建成功", file=sys.stderr) + sys.stderr.flush() + break + except Exception as e: + if attempt < max_retries - 1: + print(f"数据库连接失败(尝试 {attempt + 1}/{max_retries}): {e}", file=sys.stderr) + print(f"等待 {retry_delay} 秒后重试...", file=sys.stderr) + sys.stderr.flush() + await asyncio.sleep(retry_delay) + else: + print(f"数据库连接失败,已达到最大重试次数: {e}", file=sys.stderr) + sys.stderr.flush() + # 不抛出异常,让应用继续启动,但数据库操作会失败 + + try: + startup_knowledge_base() + except Exception as e: + print(f"启动知识库服务失败: {e}", file=sys.stderr) + sys.stderr.flush() + + print("应用启动事件完成", file=sys.stderr) + sys.stderr.flush() + +# 应用关闭事件 +@app.on_event("shutdown") +async def shutdown_event(): + """应用关闭时执行""" + try: + from src.services.file_watcher_service import stop_file_watcher + stop_file_watcher() + print("知识库文件监控服务已停止") + except Exception as e: + print(f"停止知识库文件监控服务失败: {str(e)}") + +# 注册路由 +app.include_router(auth.router) +app.include_router(chat.router) + +# 导入并注册文档API +from src.api import document +app.include_router(document.router) + +# 导入并注册图像API +from src.api import image +app.include_router(image.router) + +# 导入并注册分析API +from src.api import analytics +app.include_router(analytics.router) + +# 导入并注册知识库API(已合并knowledge.py的功能) +from src.api import knowledge_base +app.include_router(knowledge_base.router) + +# 导入并注册课程内容API +from src.api import course_content, forum +app.include_router(course_content.router) +app.include_router(forum.router) + +# 静态文件服务 +if os.path.exists("uploads"): + app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads") + +# 挂载生成图像目录 +if os.path.exists("generated_images"): + app.mount("/generated_images", StaticFiles(directory="generated_images"), name="generated_images") + +# 根路径 +@app.get("/") +async def root(): + """根路径""" + return { + "message": f"欢迎使用{settings.app_name}", + "version": settings.app_version, + "docs": "/docs" + } + +# 健康检查端点 +@app.get("/health") +async def health_check(): + """健康检查端点""" + # 检查数据库连接 + db_healthy = check_database_connection() + + status = "healthy" if db_healthy else "unhealthy" + + return { + "status": status, + "timestamp": datetime.now().isoformat(), + "version": settings.app_version, + "database": "connected" if db_healthy else "disconnected", + "services": { + "api": "running", + "database": "connected" if db_healthy else "disconnected" + } + } + + +# 系统状态端点 +@app.get("/system/status") +async def system_status(): + """系统状态端点""" + db_info = get_database_info() + + # 获取系统信息 + import psutil + import platform + + system_info = { + "platform": platform.platform(), + "python_version": platform.python_version(), + "cpu_count": psutil.cpu_count(), + "memory_total": psutil.virtual_memory().total, + "memory_available": psutil.virtual_memory().available, + } + + # 检查磁盘使用情况 + try: + disk_usage = psutil.disk_usage("/")._asdict() + system_info["disk_usage"] = disk_usage + except: + system_info["disk_usage"] = None + + # 获取服务状态 + services_status = { + "api": "running", + "database": db_info.get("type", "unknown"), + "vector_store": "available" if os.path.exists(settings.vector_store_path) else "unavailable" + } + + return { + "status": "operational", + "timestamp": datetime.now().isoformat(), + "system": system_info, + "services": services_status, + "database": db_info, + "config": { + "app_name": settings.app_name, + "app_version": settings.app_version, + "debug": settings.debug, + "database_type": "postgresql" if is_postgresql_database() else "sqlite" + } + } + + +# 服务发现端点 +@app.get("/services") +async def list_services(): + """列出所有服务""" + services = { + "backend": { + "name": "FastAPI后端服务", + "endpoint": f"http://localhost:{settings.port}", + "health": "/health", + "docs": "/docs" + }, + "database": { + "name": "数据库服务", + "type": "postgresql" if is_postgresql_database() else "sqlite", + "status": "running" + }, + "vectorizer": { + "name": "向量化服务", + "description": "独立文档向量化处理服务", + "status": "available" + }, + "frontend": { + "name": "Next.js前端服务", + "endpoint": "http://localhost:8001", + "status": "external" + } + } + + return { + "services": services, + "timestamp": datetime.now().isoformat() + } + +if __name__ == "__main__": + import sys + print("=" * 50, file=sys.stderr) + print("启动 Uvicorn 服务器...", file=sys.stderr) + print(f"Host: {settings.host}, Port: {settings.port}", file=sys.stderr) + print("=" * 50, file=sys.stderr) + sys.stderr.flush() + + uvicorn.run( + "main:app", + host=settings.host, + port=settings.port, + reload=settings.debug, + log_level=settings.log_level.lower(), + log_config=None # 使用默认日志配置 + ) diff --git a/backend/pyproject.toml b/backend/pyproject.toml new file mode 100644 index 0000000..9a65e05 --- /dev/null +++ b/backend/pyproject.toml @@ -0,0 +1,70 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "course-agent-backend" +version = "0.1.0" +description = "国土空间规划课程智能体后端服务" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "fastapi>=0.110.0", + "uvicorn[standard]>=0.27.1", + "langchain>=1.0.0", + "langchain-openai>=0.3.0", + "langchain-community>=0.3.0", + "langchain-chroma>=0.2.0", + "langchain-text-splitters>=0.3.0", + "langgraph>=0.3.5", + "chromadb>=0.4.0", + "sentence-transformers>=2.2.2", + "pypdf2>=3.0.0", + "python-jose[cryptography]>=3.3.0", + "passlib[bcrypt]>=1.7.4", + "python-multipart>=0.0.6", + "sqlalchemy>=2.0.0", + "psycopg[binary]>=3.1.0", + "sse-starlette>=1.6.5", + "pydantic[email]>=2.5.0", + "pydantic-settings>=2.1.0", + "python-dotenv>=1.0.1", + "httpx>=0.28.1", + "jinja2>=3.1.3", + "markdownify>=1.1.0", + "watchdog>=3.0.0", + "numpy>=2.2.3", + "pandas>=2.2.3", + "zstandard>=0.25.0", + "lxml>=6.0.2", + "python-docx>=1.2.0", + "bcrypt==4.0.1", + "duckduckgo-search>=6.0.0", + "docx2txt>=0.9", + "pypdf>=6.12.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.4.0", + "pytest-asyncio>=1.0.0", + "pytest-cov>=6.0.0", + "black>=24.0.0", + "ruff>=0.1.0", + "mypy>=1.8.0" +] + +[tool.hatch.build.targets.wheel] +packages = ["src"] + +[tool.uv] +required-version = ">=0.6.15" + +[tool.ruff] +line-length = 88 +indent-width = 4 +target-version = "py312" + +[tool.ruff.format] +indent-style = "space" +line-ending = "auto" diff --git a/backend/scripts/data_backup.py b/backend/scripts/data_backup.py new file mode 100644 index 0000000..b7942d3 --- /dev/null +++ b/backend/scripts/data_backup.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python3 +""" +数据备份脚本 - 备份数据库和向量存储 +""" + +import os +import sys +import shutil +import json +import tarfile +from datetime import datetime +from pathlib import Path +import logging +from typing import Dict, List, Optional + +# 配置日志 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +class DataBackup: + """数据备份类""" + + def __init__(self, backup_dir: str = "./backups"): + self.backup_dir = Path(backup_dir) + self.backup_dir.mkdir(parents=True, exist_ok=True) + + # 备份配置 + self.backup_items = { + "database": { + "name": "数据库", + "paths": ["course_agent.db"], + "enabled": True + }, + "vector_store": { + "name": "向量存储", + "paths": ["vector_store"], + "enabled": True + }, + "knowledge_base": { + "name": "知识库", + "paths": ["data/knowledge_base"], + "enabled": True + }, + "uploads": { + "name": "上传文件", + "paths": ["uploads"], + "enabled": True + }, + "logs": { + "name": "日志文件", + "paths": ["logs"], + "enabled": False # 默认不备份日志 + } + } + + def create_backup(self, backup_name: Optional[str] = None) -> str: + """创建备份""" + if not backup_name: + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + backup_name = f"backup_{timestamp}" + + backup_path = self.backup_dir / backup_name + backup_path.mkdir(exist_ok=True) + + logger.info(f"开始创建备份: {backup_name}") + + backup_info = { + "name": backup_name, + "created_at": datetime.now().isoformat(), + "items": {} + } + + # 备份每个项目 + for item_id, item_config in self.backup_items.items(): + if not item_config["enabled"]: + continue + + item_backup_path = backup_path / item_id + item_backup_path.mkdir(exist_ok=True) + + item_info = self._backup_item(item_id, item_config, item_backup_path) + backup_info["items"][item_id] = item_info + + if item_info["status"] == "success": + logger.info(f"✅ {item_config['name']}: {item_info['file_count']} 个文件") + else: + logger.warning(f"⚠️ {item_config['name']}: {item_info['error']}") + + # 保存备份信息 + info_file = backup_path / "backup_info.json" + with open(info_file, "w", encoding="utf-8") as f: + json.dump(backup_info, f, ensure_ascii=False, indent=2) + + # 创建压缩包 + tar_path = self._create_tar_archive(backup_path) + + # 清理临时目录 + shutil.rmtree(backup_path) + + logger.info(f"✅ 备份创建完成: {tar_path}") + return str(tar_path) + + def _backup_item(self, item_id: str, item_config: Dict, backup_path: Path) -> Dict: + """备份单个项目""" + item_info = { + "name": item_config["name"], + "paths": item_config["paths"], + "status": "pending", + "file_count": 0, + "total_size": 0 + } + + try: + file_count = 0 + total_size = 0 + + for path_str in item_config["paths"]: + source_path = Path(path_str) + + if not source_path.exists(): + logger.warning(f"路径不存在: {source_path}") + continue + + if source_path.is_file(): + # 备份单个文件 + shutil.copy2(source_path, backup_path / source_path.name) + file_count += 1 + total_size += source_path.stat().st_size + else: + # 备份目录 + for root, dirs, files in os.walk(source_path): + for file in files: + source_file = Path(root) / file + rel_path = source_file.relative_to(source_path) + target_file = backup_path / rel_path + + target_file.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(source_file, target_file) + + file_count += 1 + total_size += source_file.stat().st_size + + item_info.update({ + "status": "success", + "file_count": file_count, + "total_size": total_size + }) + + except Exception as e: + item_info.update({ + "status": "error", + "error": str(e) + }) + + return item_info + + def _create_tar_archive(self, backup_path: Path) -> Path: + """创建tar.gz压缩包""" + tar_filename = f"{backup_path.name}.tar.gz" + tar_path = self.backup_dir / tar_filename + + with tarfile.open(tar_path, "w:gz") as tar: + # 添加备份信息文件 + info_file = backup_path / "backup_info.json" + if info_file.exists(): + tar.add(info_file, arcname="backup_info.json") + + # 添加其他文件 + for item_dir in backup_path.iterdir(): + if item_dir.is_dir(): + tar.add(item_dir, arcname=item_dir.name) + + return tar_path + + def list_backups(self) -> List[Dict]: + """列出所有备份""" + backups = [] + + for item in self.backup_dir.iterdir(): + if item.is_file() and item.suffix == ".gz": + backup_info = self._get_backup_info(item) + if backup_info: + backups.append(backup_info) + + # 按创建时间排序 + backups.sort(key=lambda x: x.get("created_at", ""), reverse=True) + return backups + + def _get_backup_info(self, backup_file: Path) -> Optional[Dict]: + """从备份文件中获取信息""" + try: + with tarfile.open(backup_file, "r:gz") as tar: + # 查找备份信息文件 + info_member = None + for member in tar.getmembers(): + if member.name == "backup_info.json": + info_member = member + break + + if info_member: + # 提取并读取信息文件 + info_data = tar.extractfile(info_member) + if info_data: + info = json.load(info_data) + info["filename"] = backup_file.name + info["size"] = backup_file.stat().st_size + return info + + except Exception as e: + logger.error(f"读取备份信息失败 {backup_file}: {e}") + + return None + + def restore_backup(self, backup_filename: str, restore_dir: str = ".") -> bool: + """恢复备份""" + backup_file = self.backup_dir / backup_filename + + if not backup_file.exists(): + logger.error(f"备份文件不存在: {backup_filename}") + return False + + restore_path = Path(restore_dir) + restore_path.mkdir(parents=True, exist_ok=True) + + logger.info(f"开始恢复备份: {backup_filename}") + + try: + with tarfile.open(backup_file, "r:gz") as tar: + # 提取所有文件 + tar.extractall(restore_path) + logger.info(f"✅ 备份恢复完成到: {restore_path}") + return True + + except Exception as e: + logger.error(f"恢复备份失败: {e}") + return False + + def cleanup_old_backups(self, keep_days: int = 30) -> int: + """清理旧备份""" + cutoff_date = datetime.now() - timedelta(days=keep_days) + deleted_count = 0 + + for backup_info in self.list_backups(): + created_at_str = backup_info.get("created_at") + if not created_at_str: + continue + + try: + created_at = datetime.fromisoformat(created_at_str.replace("Z", "+00:00")) + if created_at < cutoff_date: + backup_file = self.backup_dir / backup_info["filename"] + backup_file.unlink() + logger.info(f"删除旧备份: {backup_info['filename']}") + deleted_count += 1 + except Exception as e: + logger.error(f"解析备份日期失败: {e}") + + return deleted_count + +def main(): + """主函数""" + import argparse + + parser = argparse.ArgumentParser(description="数据备份工具") + parser.add_argument("action", choices=["create", "list", "restore", "cleanup"], + help="执行的操作") + parser.add_argument("--name", help="备份名称(用于create和restore)") + parser.add_argument("--backup-dir", default="./backups", help="备份目录") + parser.add_argument("--restore-dir", default=".", help="恢复目录") + parser.add_argument("--keep-days", type=int, default=30, help="保留备份的天数") + + args = parser.parse_args() + + backup = DataBackup(args.backup_dir) + + if args.action == "create": + backup_path = backup.create_backup(args.name) + print(f"备份创建完成: {backup_path}") + + elif args.action == "list": + backups = backup.list_backups() + print(f"\n找到 {len(backups)} 个备份:\n") + for b in backups: + print(f"名称: {b['name']}") + print(f"文件: {b['filename']}") + print(f"大小: {b['size'] / 1024 / 1024:.2f} MB") + print(f"时间: {b['created_at']}") + print(f"项目: {', '.join(b['items'].keys())}") + print("-" * 40) + + elif args.action == "restore": + if not args.name: + print("错误: 恢复备份需要指定备份文件名") + sys.exit(1) + + success = backup.restore_backup(args.name, args.restore_dir) + if success: + print("✅ 备份恢复成功") + else: + print("❌ 备份恢复失败") + sys.exit(1) + + elif args.action == "cleanup": + deleted = backup.cleanup_old_backups(args.keep_days) + print(f"清理了 {deleted} 个旧备份") + +if __name__ == "__main__": + main() diff --git a/backend/scripts/docker_init.py b/backend/scripts/docker_init.py new file mode 100644 index 0000000..3306097 --- /dev/null +++ b/backend/scripts/docker_init.py @@ -0,0 +1,304 @@ +#!/usr/bin/env python3 +""" +Docker环境初始化脚本 +""" + +import os +import sys +import time +import logging +from pathlib import Path +from datetime import datetime + +# 添加src目录到Python路径 +sys.path.append(str(Path(__file__).parent.parent)) + +from src.core.database import SessionLocal, create_tables, check_database_connection, get_database_info +from src.core.config import get_settings, is_postgresql_database +from src.models.user import User +from src.models.knowledge_base import KnowledgeBase +from src.models.forum import ForumCategory +from src.services.auth_service import AuthService + +# 配置日志 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +class DockerInitializer: + """Docker环境初始化""" + + def __init__(self): + self.settings = get_settings() + self.session = SessionLocal() + self.auth_service = AuthService(self.session) + + def initialize(self): + """执行初始化""" + logger.info("=" * 60) + logger.info("Docker环境初始化") + logger.info("=" * 60) + + # 1. 检查数据库连接 + if not self._check_database(): + return False + + # 2. 创建数据库表 + self._create_tables() + + # 3. 创建默认管理员用户 + self._create_admin_user() + + # 4. 创建系统知识库 + self._create_system_knowledge_bases() + + # 5. 创建论坛分类 + self._create_forum_categories() + + # 6. 检查数据目录 + self._check_data_directories() + + logger.info("✅ Docker环境初始化完成") + return True + + def _check_database(self): + """检查数据库连接""" + logger.info("检查数据库连接...") + + max_retries = 10 + retry_delay = 5 + + for i in range(max_retries): + try: + if check_database_connection(): + db_info = get_database_info() + logger.info(f"✅ 数据库连接成功: {db_info.get('type', 'Unknown')}") + + if is_postgresql_database(): + logger.info(f" 数据库: {db_info.get('database', 'Unknown')}") + logger.info(f" 版本: {db_info.get('version', 'Unknown')}") + + return True + else: + logger.warning(f"数据库连接失败,重试 {i+1}/{max_retries}...") + except Exception as e: + logger.warning(f"数据库连接异常: {e}") + + if i < max_retries - 1: + time.sleep(retry_delay) + + logger.error("❌ 数据库连接失败,请检查数据库服务") + return False + + def _create_tables(self): + """创建数据库表""" + logger.info("创建数据库表...") + + try: + create_tables() + logger.info("✅ 数据库表创建完成") + except Exception as e: + logger.error(f"❌ 创建数据库表失败: {e}") + raise + + def _create_admin_user(self): + """创建默认管理员用户""" + logger.info("创建默认管理员用户...") + + try: + # 检查是否已存在管理员用户 + admin_user = self.session.query(User).filter( + User.username == "admin" + ).first() + + if admin_user: + logger.info("管理员用户已存在") + return + + # 创建管理员用户 + admin_data = { + "username": "admin", + "email": "admin@course-agent.local", + "password": "admin123", # 默认密码,首次登录后应修改 + "full_name": "系统管理员", + "is_superuser": True + } + + admin_user = self.auth_service.create_user(**admin_data) + + if admin_user: + logger.info("✅ 管理员用户创建成功") + logger.info(f" 用户名: {admin_user.username}") + logger.info(f" 邮箱: {admin_user.email}") + logger.info("⚠️ 请尽快修改默认密码") + else: + logger.warning("管理员用户创建失败") + + except Exception as e: + logger.error(f"创建管理员用户失败: {e}") + + def _create_system_knowledge_bases(self): + """创建系统知识库""" + logger.info("创建系统知识库...") + + system_kbs = [ + { + "name": "国土空间法律法规集", + "description": "国土空间规划相关法律法规、政策文件", + "is_system": True, + "is_active": True + }, + { + "name": "国土空间规划原理集", + "description": "国土空间规划理论、原理、方法", + "is_system": True, + "is_active": True + }, + { + "name": "国土空间规划案例集", + "description": "各级国土空间规划案例", + "is_system": True, + "is_active": True + } + ] + + created_count = 0 + for kb_data in system_kbs: + try: + # 检查是否已存在 + existing = self.session.query(KnowledgeBase).filter( + KnowledgeBase.name == kb_data["name"], + KnowledgeBase.is_system == True + ).first() + + if existing: + continue + + # 创建知识库 + kb = KnowledgeBase( + user_id=1, # 管理员用户ID + **kb_data + ) + + self.session.add(kb) + created_count += 1 + + except Exception as e: + logger.error(f"创建知识库失败 {kb_data['name']}: {e}") + + if created_count > 0: + self.session.commit() + logger.info(f"✅ 创建了 {created_count} 个系统知识库") + else: + logger.info("系统知识库已存在") + + def _create_forum_categories(self): + """创建论坛分类""" + logger.info("创建论坛分类...") + + categories = [ + { + "name": "系统使用优化建议", + "description": "分享系统使用经验,提出改进建议" + }, + { + "name": "课程学习反馈", + "description": "交流学习心得,讨论课程内容" + } + ] + + created_count = 0 + for cat_data in categories: + try: + # 检查是否已存在 + existing = self.session.query(ForumCategory).filter( + ForumCategory.name == cat_data["name"] + ).first() + + if existing: + continue + + # 创建分类 + category = ForumCategory(**cat_data) + self.session.add(category) + created_count += 1 + + except Exception as e: + logger.error(f"创建论坛分类失败 {cat_data['name']}: {e}") + + if created_count > 0: + self.session.commit() + logger.info(f"✅ 创建了 {created_count} 个论坛分类") + else: + logger.info("论坛分类已存在") + + def _check_data_directories(self): + """检查数据目录""" + logger.info("检查数据目录...") + + directories = [ + self.settings.vector_store_path, + self.settings.upload_dir, + self.settings.knowledge_base_dir, + self.settings.generated_images_dir, + os.path.dirname(self.settings.log_file), + ] + + for dir_path in directories: + try: + path = Path(dir_path) + path.mkdir(parents=True, exist_ok=True) + + # 检查权限 + test_file = path / ".test_write" + test_file.touch() + test_file.unlink() + + logger.info(f"✅ 目录可访问: {dir_path}") + except Exception as e: + logger.error(f"❌ 目录访问失败 {dir_path}: {e}") + + def close(self): + """关闭资源""" + if self.session: + self.session.close() + +def main(): + """主函数""" + initializer = None + + try: + initializer = DockerInitializer() + success = initializer.initialize() + + if success: + print("\n" + "=" * 60) + print("初始化完成!") + print("=" * 60) + print("\n访问信息:") + print(f" 前端: http://localhost:8001") + print(f" 后端API: http://localhost:8000") + print(f" API文档: http://localhost:8000/docs") + print("\n默认管理员账号:") + print(" 用户名: admin") + print(" 密码: admin123") + print(" ⚠️ 请尽快修改默认密码") + print("\n" + "=" * 60) + else: + print("❌ 初始化失败") + sys.exit(1) + + except Exception as e: + print(f"❌ 初始化过程中发生错误: {e}") + import traceback + traceback.print_exc() + sys.exit(1) + + finally: + if initializer: + initializer.close() + +if __name__ == "__main__": + main() diff --git a/backend/scripts/import_book_structure.py b/backend/scripts/import_book_structure.py new file mode 100644 index 0000000..9fa6a5b --- /dev/null +++ b/backend/scripts/import_book_structure.py @@ -0,0 +1,162 @@ +""" +导入书籍结构到数据库 +解析LaTeX文件并导入书籍、章节、节、小节(知识点) +层级结构:书籍 -> Chapter -> Section -> Subsection(知识点) +""" +import sys +import re +from pathlib import Path + +# 添加项目根目录到路径 +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from sqlalchemy.orm import Session +from src.core.database import SessionLocal, create_tables +from src.core.config import get_settings +from src.models.book_structure import Book, Chapter, Section, Subsection +from src.services.latex_parser import LaTeXParser + + +def import_book_structure(): + """导入书籍结构""" + settings = get_settings() + book_dir = Path(settings.book_dir) + + # 如果相对路径不存在,尝试从项目根目录查找 + if not book_dir.exists(): + # 脚本位置: dofile/backend/scripts/import_book_structure.py + # 项目根目录: 向上3级 + script_dir = Path(__file__).parent.parent.parent.parent # 项目根目录 + book_dir = script_dir / "data" / "book" + if not book_dir.exists(): + print(f"错误: 书籍目录不存在") + print(f"尝试的路径1: {settings.book_dir}") + print(f"尝试的路径2: {book_dir}") + return + print(f"使用书籍目录: {book_dir}") + + # 创建数据库表 + print("创建数据库表...") + create_tables() + + # 创建数据库会话 + db: Session = SessionLocal() + try: + # 清空旧数据(如果存在) + db.query(Subsection).delete() + db.query(Section).delete() + db.query(Chapter).delete() + db.query(Book).delete() + db.commit() + print("已清空旧的书籍结构数据。") + + # 创建书籍 + book_title = "国土空间规划:概念、原理、方法" + book_description = "基于LaTeX书籍内容构建的知识图谱系统" + book = Book(title=book_title, description=book_description) + db.add(book) + db.commit() + db.refresh(book) + print(f"已创建书籍: {book.title}") + + parser = LaTeXParser(book_dir) + + # 解析主文件获取章节顺序 + main_tex_path = book_dir / "main.tex" + if not main_tex_path.exists(): + print(f"错误: main.tex 文件不存在于 {book_dir}") + return + + main_content = main_tex_path.read_text(encoding='utf-8') + chapter_input_re = re.compile(r'^\\input{(chapter\d+)}', re.MULTILINE) + + chapter_files_in_order = [] + for match in chapter_input_re.finditer(main_content): + chapter_files_in_order.append(f"{match.group(1)}.tex") + + if not chapter_files_in_order: + print("未在 main.tex 中找到章节文件引用。") + return + + total_chapters = 0 + total_sections = 0 + total_subsections = 0 + + # 遍历章节文件并导入 + for chapter_idx, chapter_filename in enumerate(chapter_files_in_order): + chapter_file_path = book_dir / chapter_filename + if not chapter_file_path.exists(): + print(f"警告: 章节文件 {chapter_file_path} 不存在,跳过。") + continue + + print(f"解析LaTeX文件: {chapter_file_path.name}...") + chapter_structure = parser.parse_chapter_file(chapter_file_path) + + if not chapter_structure: + print(f"警告: 文件 {chapter_file_path.name} 未解析出任何结构。") + continue + + # 每个文件只包含一个 \chapter + parsed_chapter_data = chapter_structure[0] + + chapter_obj = Chapter( + book_id=book.id, + chapter_number=parsed_chapter_data["chapter_number"], + title=parsed_chapter_data["title"], + file_path=chapter_file_path.name, + start_line=parsed_chapter_data["start_line"], + end_line=parsed_chapter_data["end_line"], + display_order=parsed_chapter_data["chapter_number"] + ) + db.add(chapter_obj) + db.flush() # Flush to get chapter_obj.id + total_chapters += 1 + + # 导入节(Section) + for section_data in parsed_chapter_data.get("sections", []): + section_obj = Section( + chapter_id=chapter_obj.id, + section_number=section_data["section_number"], + title=section_data["title"], + file_path=chapter_file_path.name, + start_line=section_data["start_line"], + end_line=section_data["end_line"], + display_order=section_data["section_number"] + ) + db.add(section_obj) + db.flush() # Flush to get section_obj.id + total_sections += 1 + + # 导入小节(Subsection,作为知识点) + for subsection_data in section_data.get("subsections", []): + subsection_obj = Subsection( + section_id=section_obj.id, + subsection_number=subsection_data["subsection_number"], + title=subsection_data["title"], + file_path=chapter_file_path.name, + start_line=subsection_data["start_line"], + end_line=subsection_data["end_line"], + display_order=subsection_data["subsection_number"] + ) + db.add(subsection_obj) + total_subsections += 1 + + db.commit() + print(f"\n[SUCCESS] 书籍结构导入成功!") + print(f" - 书籍: {book.title}") + print(f" - 章节: {total_chapters} 个") + print(f" - 节: {total_sections} 个") + print(f" - 小节(知识点): {total_subsections} 个") + + except Exception as e: + db.rollback() + print(f"[ERROR] 导入失败: {e}") + import traceback + traceback.print_exc() + raise + finally: + db.close() + + +if __name__ == "__main__": + import_book_structure() diff --git a/backend/scripts/service_monitor.py b/backend/scripts/service_monitor.py new file mode 100644 index 0000000..34f36c1 --- /dev/null +++ b/backend/scripts/service_monitor.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python3 +""" +服务监控脚本 - 监控多服务架构的健康状态 +""" + +import os +import sys +import time +import json +import logging +import requests +from datetime import datetime, timedelta +from typing import Dict, List, Optional +from pathlib import Path + +# 配置日志 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('service_monitor.log'), + logging.StreamHandler() + ] +) +logger = logging.getLogger(__name__) + +class ServiceMonitor: + """服务监控器""" + + def __init__(self): + self.services = { + "backend": { + "name": "FastAPI后端服务", + "url": "http://localhost:8000/health", + "timeout": 5, + "required": True + }, + "frontend": { + "name": "Next.js前端服务", + "url": "http://localhost:8001", + "timeout": 5, + "required": True + }, + "database": { + "name": "PostgreSQL数据库", + "type": "internal", # 内部服务,通过后端检查 + "required": True + }, + "vectorizer": { + "name": "向量化服务", + "type": "process", # 进程检查 + "process_name": "vectorizer_service.py", + "required": False + } + } + + self.check_interval = 30 # 检查间隔(秒) + self.alert_threshold = 3 # 报警阈值(连续失败次数) + self.status_history = [] + self.max_history = 100 + + def check_service(self, service_id: str, service_config: Dict) -> Dict: + """检查单个服务""" + service_status = { + "service_id": service_id, + "name": service_config["name"], + "timestamp": datetime.now().isoformat(), + "status": "unknown", + "response_time": None, + "error": None + } + + try: + start_time = time.time() + + if service_config.get("type") == "internal": + # 内部服务,通过后端检查 + backend_status = self._check_backend_service(service_id) + service_status.update(backend_status) + + elif service_config.get("type") == "process": + # 进程检查 + process_status = self._check_process_service(service_config) + service_status.update(process_status) + + else: + # HTTP服务检查 + response = requests.get( + service_config["url"], + timeout=service_config.get("timeout", 5) + ) + + response_time = (time.time() - start_time) * 1000 # 毫秒 + + if response.status_code == 200: + service_status["status"] = "healthy" + service_status["response_time"] = response_time + + # 解析响应内容 + try: + data = response.json() + service_status["details"] = data + except: + pass + else: + service_status["status"] = "unhealthy" + service_status["error"] = f"HTTP {response.status_code}" + + except requests.exceptions.Timeout: + service_status["status"] = "timeout" + service_status["error"] = "请求超时" + + except requests.exceptions.ConnectionError: + service_status["status"] = "unreachable" + service_status["error"] = "连接失败" + + except Exception as e: + service_status["status"] = "error" + service_status["error"] = str(e) + + return service_status + + def _check_backend_service(self, service_id: str) -> Dict: + """检查后端内部服务""" + try: + # 通过后端API检查数据库状态 + response = requests.get( + "http://localhost:8000/system/status", + timeout=5 + ) + + if response.status_code == 200: + data = response.json() + + if service_id == "database": + db_status = data.get("database", {}) + db_type = db_status.get("type", "unknown") + + return { + "status": "healthy" if db_type != "unknown" else "unhealthy", + "details": db_status + } + + return {"status": "unhealthy", "error": "后端检查失败"} + + except Exception as e: + return {"status": "error", "error": str(e)} + + def _check_process_service(self, service_config: Dict) -> Dict: + """检查进程服务""" + process_name = service_config.get("process_name") + + if not process_name: + return {"status": "unknown", "error": "未配置进程名"} + + try: + # 检查进程是否存在(Linux/Mac) + if sys.platform != "win32": + import subprocess + result = subprocess.run( + ["pgrep", "-f", process_name], + capture_output=True, + text=True + ) + + if result.returncode == 0: + return {"status": "healthy", "details": {"processes": result.stdout.strip().split()}} + else: + return {"status": "stopped", "error": "进程未运行"} + + else: + # Windows平台检查 + import psutil + process_count = 0 + + for proc in psutil.process_iter(['pid', 'name', 'cmdline']): + try: + cmdline = proc.info.get('cmdline') + if cmdline and process_name in ' '.join(cmdline): + process_count += 1 + except (psutil.NoSuchProcess, psutil.AccessDenied): + pass + + if process_count > 0: + return {"status": "healthy", "details": {"process_count": process_count}} + else: + return {"status": "stopped", "error": "进程未运行"} + + except Exception as e: + return {"status": "error", "error": str(e)} + + def check_all_services(self) -> Dict: + """检查所有服务""" + logger.info("开始检查所有服务...") + + results = {} + overall_status = "healthy" + failed_services = [] + + for service_id, service_config in self.services.items(): + status = self.check_service(service_id, service_config) + results[service_id] = status + + if status["status"] != "healthy": + if service_config.get("required", False): + overall_status = "unhealthy" + failed_services.append(service_id) + + logger.warning(f"❌ {service_config['name']}: {status['status']} - {status.get('error', '')}") + else: + logger.info(f"✅ {service_config['name']}: 健康") + + # 保存到历史记录 + check_result = { + "timestamp": datetime.now().isoformat(), + "overall_status": overall_status, + "services": results, + "failed_services": failed_services + } + + self.status_history.append(check_result) + if len(self.status_history) > self.max_history: + self.status_history = self.status_history[-self.max_history:] + + # 保存到文件 + self._save_status_history() + + logger.info(f"检查完成: 总体状态 - {overall_status}") + + return check_result + + def _save_status_history(self): + """保存状态历史""" + try: + history_file = Path("service_status_history.json") + + # 只保存最近24小时的数据 + cutoff_time = datetime.now() - timedelta(hours=24) + recent_history = [ + h for h in self.status_history + if datetime.fromisoformat(h["timestamp"].replace("Z", "+00:00")) > cutoff_time + ] + + with open(history_file, "w", encoding="utf-8") as f: + json.dump(recent_history, f, ensure_ascii=False, indent=2) + + except Exception as e: + logger.error(f"保存状态历史失败: {e}") + + def load_status_history(self) -> List[Dict]: + """加载状态历史""" + try: + history_file = Path("service_status_history.json") + if history_file.exists(): + with open(history_file, "r", encoding="utf-8") as f: + return json.load(f) + except Exception as e: + logger.error(f"加载状态历史失败: {e}") + + return [] + + def get_service_stats(self, hours: int = 24) -> Dict: + """获取服务统计信息""" + cutoff_time = datetime.now() - timedelta(hours=hours) + + relevant_history = [ + h for h in self.status_history + if datetime.fromisoformat(h["timestamp"].replace("Z", "+00:00")) > cutoff_time + ] + + if not relevant_history: + return {} + + stats = { + "total_checks": len(relevant_history), + "healthy_checks": sum(1 for h in relevant_history if h["overall_status"] == "healthy"), + "uptime_percentage": 0, + "service_stats": {} + } + + if stats["total_checks"] > 0: + stats["uptime_percentage"] = (stats["healthy_checks"] / stats["total_checks"]) * 100 + + # 计算每个服务的统计 + for service_id in self.services.keys(): + service_checks = [] + for check in relevant_history: + if service_id in check["services"]: + service_checks.append(check["services"][service_id]) + + if service_checks: + healthy_count = sum(1 for s in service_checks if s["status"] == "healthy") + total_count = len(service_checks) + + stats["service_stats"][service_id] = { + "name": self.services[service_id]["name"], + "total_checks": total_count, + "healthy_checks": healthy_count, + "availability": (healthy_count / total_count * 100) if total_count > 0 else 0, + "last_status": service_checks[-1]["status"] if service_checks else "unknown" + } + + return stats + + def run_monitor(self, duration_minutes: Optional[int] = None): + """运行监控器""" + logger.info("=" * 60) + logger.info("服务监控器启动") + logger.info("=" * 60) + + start_time = time.time() + + try: + while True: + # 检查是否达到运行时长限制 + if duration_minutes: + elapsed_minutes = (time.time() - start_time) / 60 + if elapsed_minutes >= duration_minutes: + logger.info(f"达到运行时长限制 ({duration_minutes} 分钟),停止监控") + break + + # 执行检查 + self.check_all_services() + + # 显示统计信息 + stats = self.get_service_stats(hours=1) + if stats: + logger.info(f"最近1小时可用性: {stats.get('uptime_percentage', 0):.1f}%") + + # 等待下一次检查 + logger.info(f"等待 {self.check_interval} 秒...") + time.sleep(self.check_interval) + + except KeyboardInterrupt: + logger.info("收到中断信号,停止监控") + except Exception as e: + logger.error(f"监控器运行异常: {e}") + finally: + logger.info("服务监控器停止") + +def main(): + """主函数""" + import argparse + + parser = argparse.ArgumentParser(description="服务监控工具") + parser.add_argument("action", choices=["check", "monitor", "stats"], + help="执行的操作") + parser.add_argument("--duration", type=int, default=60, + help="监控持续时间(分钟),仅用于monitor模式") + parser.add_argument("--hours", type=int, default=24, + help="统计小时数,用于stats模式") + + args = parser.parse_args() + + monitor = ServiceMonitor() + + if args.action == "check": + # 单次检查 + result = monitor.check_all_services() + print(json.dumps(result, ensure_ascii=False, indent=2)) + + elif args.action == "monitor": + # 持续监控 + monitor.run_monitor(args.duration) + + elif args.action == "stats": + # 显示统计信息 + stats = monitor.get_service_stats(args.hours) + print(json.dumps(stats, ensure_ascii=False, indent=2)) + +if __name__ == "__main__": + main() diff --git a/backend/scripts/vectorizer_service.py b/backend/scripts/vectorizer_service.py new file mode 100644 index 0000000..8d16cd9 --- /dev/null +++ b/backend/scripts/vectorizer_service.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 +""" +向量化服务 - 独立处理文档向量化 +""" + +import os +import sys +import time +import logging +from pathlib import Path +from datetime import datetime, timedelta + +# 添加src目录到Python路径 +sys.path.append(str(Path(__file__).parent.parent)) + +from src.core.database import SessionLocal, get_database_info +from src.models.document import Document +from src.services.document_service import DocumentService +from src.core.config import get_settings + +# 配置日志 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('vectorizer_service.log'), + logging.StreamHandler() + ] +) +logger = logging.getLogger(__name__) + +# 减少不必要的日志 +logging.getLogger("pypdf").setLevel(logging.ERROR) +logging.getLogger("PIL").setLevel(logging.ERROR) +logging.getLogger("chromadb").setLevel(logging.WARNING) + +class VectorizerService: + """向量化服务""" + + def __init__(self): + self.settings = get_settings() + self.batch_size = 5 # 每次处理的文档数量 + self.check_interval = 60 # 检查间隔(秒) + self.max_retries = 3 # 最大重试次数 + self.retry_delay = 30 # 重试延迟(秒) + + def get_unprocessed_documents(self, session): + """获取未处理的文档""" + try: + # 查找未处理的文档 + documents = session.query(Document).filter( + Document.is_processed == False, + Document.source_type == "knowledge_base" + ).order_by(Document.id).limit(self.batch_size).all() + + # 过滤掉文件不存在的文档 + valid_documents = [] + for doc in documents: + if Path(doc.file_path).exists(): + valid_documents.append(doc) + else: + logger.warning(f"文档文件不存在: {doc.file_path}") + # 标记为已处理以避免重复检查 + doc.is_processed = True + session.commit() + + return valid_documents + except Exception as e: + logger.error(f"获取未处理文档失败: {e}") + return [] + + def process_document(self, session, document_service, document): + """处理单个文档""" + logger.info(f"开始处理文档: {document.file_path} (ID: {document.id})") + + for retry in range(self.max_retries): + try: + # 使用异步处理 + import asyncio + + # 创建新的事件循环 + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + # 处理文档 + success = loop.run_until_complete( + document_service.process_document(document.id) + ) + + loop.close() + + if success: + logger.info(f"✅ 文档处理成功: {document.file_path}") + return True + else: + logger.warning(f"❌ 文档处理失败: {document.file_path}") + if retry < self.max_retries - 1: + logger.info(f"等待 {self.retry_delay} 秒后重试...") + time.sleep(self.retry_delay) + + except Exception as e: + logger.error(f"文档处理异常 (尝试 {retry + 1}/{self.max_retries}): {e}") + if retry < self.max_retries - 1: + logger.info(f"等待 {self.retry_delay} 秒后重试...") + time.sleep(self.retry_delay) + + logger.error(f"文档处理最终失败: {document.file_path}") + return False + + def run(self): + """运行向量化服务""" + logger.info("=" * 60) + logger.info("向量化服务启动") + logger.info("=" * 60) + + # 显示数据库信息 + db_info = get_database_info() + logger.info(f"数据库: {db_info.get('type', 'Unknown')}") + logger.info(f"批量大小: {self.batch_size}") + logger.info(f"检查间隔: {self.check_interval}秒") + + session = SessionLocal() + document_service = DocumentService(session) + + try: + while True: + try: + # 获取未处理的文档 + documents = self.get_unprocessed_documents(session) + + if documents: + logger.info(f"找到 {len(documents)} 个待处理文档") + + success_count = 0 + for doc in documents: + if self.process_document(session, document_service, doc): + success_count += 1 + + logger.info(f"批量处理完成: {success_count}/{len(documents)} 成功") + else: + logger.info("没有待处理的文档,等待中...") + + # 等待下一次检查 + time.sleep(self.check_interval) + + except KeyboardInterrupt: + logger.info("收到中断信号,停止服务") + break + except Exception as e: + logger.error(f"服务运行异常: {e}") + logger.info(f"等待 {self.check_interval} 秒后继续...") + time.sleep(self.check_interval) + + finally: + session.close() + logger.info("向量化服务停止") + +def main(): + """主函数""" + # 检查环境 + if not os.path.exists("vectorizer_service.log"): + with open("vectorizer_service.log", "w") as f: + f.write(f"向量化服务日志 - 启动时间: {datetime.now()}\n") + + # 运行服务 + service = VectorizerService() + service.run() + +if __name__ == "__main__": + main() diff --git a/backend/src/__init__.py b/backend/src/__init__.py new file mode 100644 index 0000000..bfab5c2 --- /dev/null +++ b/backend/src/__init__.py @@ -0,0 +1,7 @@ +# 国土空间规划课程智能体后端服务 + + + + + + diff --git a/backend/src/api/__init__.py b/backend/src/api/__init__.py new file mode 100644 index 0000000..14cccf2 --- /dev/null +++ b/backend/src/api/__init__.py @@ -0,0 +1,7 @@ +# API路由模块 + + + + + + diff --git a/backend/src/api/analytics.py b/backend/src/api/analytics.py new file mode 100644 index 0000000..2b9563f --- /dev/null +++ b/backend/src/api/analytics.py @@ -0,0 +1,284 @@ +""" +学习分析API +""" +from typing import List, Dict, Any, Optional +from pathlib import Path +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session +from sqlalchemy import func +from pydantic import BaseModel + +from ..core.database import get_db +from ..core.config import get_settings +from ..core.security import get_current_user +from ..models.user import User +from ..models.chat import ChatSession, ChatMessage +from ..models.document import Document +from ..services.analytics_service import AnalyticsService + +router = APIRouter(prefix="/analytics", tags=["学习分析"]) +settings = get_settings() + + +class StatisticsResponse(BaseModel): + """统计响应模型""" + total_sessions: int + total_messages: int + total_documents: int + active_days: int + user_since: Optional[str] + last_login: Optional[str] + + +class LearningReportResponse(BaseModel): + """学习报告响应模型""" + user_id: int + total_questions: int + topics_covered: List[str] + learning_progress: float + recommendations: List[str] + study_time: int + knowledge_gaps: List[str] + + +class PlatformStatsResponse(BaseModel): + """平台统计数据响应模型""" + active_users: int + knowledge_documents: int + qa_dialogues: int + generated_images: int + + +@router.get("/statistics", response_model=StatisticsResponse) +async def get_statistics( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取学习统计信息""" + try: + # 获取用户对象 + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + analytics_service = AnalyticsService(db) + statistics = analytics_service.get_user_statistics(user.id) + + return StatisticsResponse(**statistics) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取统计信息失败: {str(e)}" + ) + + +@router.get("/learning-report", response_model=LearningReportResponse) +async def get_learning_report( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取个人学习报告""" + try: + # 获取用户对象 + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + analytics_service = AnalyticsService(db) + report = analytics_service.get_learning_report(user.id) + + return LearningReportResponse(**report) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取学习报告失败: {str(e)}" + ) + + +@router.get("/trends") +async def get_learning_trends( + days: int = 30, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取学习趋势数据""" + try: + # 获取用户对象 + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + analytics_service = AnalyticsService(db) + trends = analytics_service.get_user_learning_trends(user.id, days) + + return {"success": True, "data": trends} + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取学习趋势失败: {str(e)}" + ) + + +@router.get("/popular-questions") +async def get_popular_questions( + limit: int = 10, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取热门问题""" + try: + # 获取用户对象 + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + analytics_service = AnalyticsService(db) + questions = analytics_service.get_popular_questions(user.id, limit) + + return {"success": True, "data": questions} + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取热门问题失败: {str(e)}" + ) + + +@router.get("/knowledge-coverage") +async def get_knowledge_coverage( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取知识覆盖度""" + try: + # 获取用户对象 + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + analytics_service = AnalyticsService(db) + coverage = analytics_service.get_knowledge_coverage(user.id) + + return {"success": True, "data": coverage} + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取知识覆盖度失败: {str(e)}" + ) + + +@router.get("/full-analytics") +async def get_full_analytics( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取完整的学习分析数据""" + try: + # 获取用户对象 + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + analytics_service = AnalyticsService(db) + + # 获取所有统计数据 + statistics = analytics_service.get_user_statistics(user.id) + trends = analytics_service.get_user_learning_trends(user.id, 30) + popular_questions = analytics_service.get_popular_questions(user.id, 5) + knowledge_coverage = analytics_service.get_knowledge_coverage(user.id) + learning_report = analytics_service.get_learning_report(user.id) + + return { + "success": True, + "data": { + "statistics": statistics, + "learning_trends": trends, + "popular_questions": popular_questions, + "knowledge_coverage": knowledge_coverage, + "learning_report": learning_report + } + } + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取完整分析数据失败: {str(e)}" + ) + + +@router.get("/platform-stats", response_model=PlatformStatsResponse) +async def get_platform_stats( + db: Session = Depends(get_db) +): + """获取平台统计数据(公开接口,无需登录)""" + try: + # 活跃用户数(有聊天会话或文档的用户) + users_with_sessions = db.query(func.count(func.distinct(ChatSession.user_id))).scalar() or 0 + users_with_documents = db.query(func.count(func.distinct(Document.user_id))).filter( + Document.source_type == "knowledge_base" + ).scalar() or 0 + # 取两者中的较大值,或者使用总用户数 + total_users = db.query(func.count(User.id)).scalar() or 0 + active_users = max(users_with_sessions, users_with_documents, total_users) + + # 知识文档数(知识库中的文档) + knowledge_documents = db.query(func.count(Document.id)).filter( + Document.source_type == "knowledge_base" + ).scalar() or 0 + + # 问答对话数(所有用户消息) + qa_dialogues = db.query(func.count(ChatMessage.id)).filter( + ChatMessage.role == "user" + ).scalar() or 0 + + # 生成图像数(统计generated_images目录中的图像文件) + generated_images_dir = Path(settings.generated_images_dir) + generated_images = 0 + if generated_images_dir.exists(): + # 统计目录中的所有图像文件(.png, .jpg, .jpeg等) + image_extensions = {'.png', '.jpg', '.jpeg', '.webp', '.gif'} + generated_images = sum( + 1 for file in generated_images_dir.iterdir() + if file.is_file() and file.suffix.lower() in image_extensions + ) + + return PlatformStatsResponse( + active_users=active_users, + knowledge_documents=knowledge_documents, + qa_dialogues=qa_dialogues, + generated_images=generated_images + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取平台统计数据失败: {str(e)}" + ) + + + + + + diff --git a/backend/src/api/auth.py b/backend/src/api/auth.py new file mode 100644 index 0000000..2876440 --- /dev/null +++ b/backend/src/api/auth.py @@ -0,0 +1,221 @@ +""" +用户认证API +""" +from fastapi import APIRouter, Depends, HTTPException, status +from fastapi.security import HTTPBearer +from sqlalchemy.orm import Session +from pydantic import BaseModel, EmailStr +from typing import Optional + +from ..core.database import get_db +from ..core.security import get_current_user +from ..services.auth_service import AuthService + +router = APIRouter(prefix="/auth", tags=["认证"]) + + +class UserCreate(BaseModel): + """用户创建模型""" + username: str + email: EmailStr + password: str + full_name: Optional[str] = None + + +class UserLogin(BaseModel): + """用户登录模型""" + username: str + password: str + + +class PasswordChange(BaseModel): + """密码修改模型""" + old_password: str + new_password: str + + +class UserUpdate(BaseModel): + """用户信息更新模型""" + full_name: Optional[str] = None + email: Optional[EmailStr] = None + + +class Token(BaseModel): + """Token响应模型""" + access_token: str + token_type: str + + +class UserResponse(BaseModel): + """用户响应模型""" + id: int + username: str + email: str + full_name: Optional[str] + is_active: bool + created_at: str + + +@router.post("/register", response_model=UserResponse) +async def register(user_data: UserCreate, db: Session = Depends(get_db)): + """用户注册""" + auth_service = AuthService(db) + + # 创建用户 + user = auth_service.create_user( + username=user_data.username, + email=user_data.email, + password=user_data.password, + full_name=user_data.full_name + ) + + if not user: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="用户名或邮箱已存在" + ) + + return UserResponse( + id=user.id, + username=user.username, + email=user.email, + full_name=user.full_name, + is_active=user.is_active, + created_at=user.created_at.isoformat() + ) + + +@router.post("/login", response_model=Token) +async def login(login_data: UserLogin, db: Session = Depends(get_db)): + """用户登录""" + auth_service = AuthService(db) + + # 验证用户 + user = auth_service.authenticate_user(login_data.username, login_data.password) + + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="用户名或密码错误", + headers={"WWW-Authenticate": "Bearer"}, + ) + + # 创建访问令牌 + token_data = auth_service.create_access_token_for_user(user) + + return Token( + access_token=token_data["access_token"], + token_type=token_data["token_type"] + ) + + +@router.get("/me", response_model=UserResponse) +async def get_current_user_info(current_user: str = Depends(get_current_user), db: Session = Depends(get_db)): + """获取当前用户信息""" + auth_service = AuthService(db) + user = auth_service.get_user_by_username(current_user) + + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + return UserResponse( + id=user.id, + username=user.username, + email=user.email, + full_name=user.full_name, + is_active=user.is_active, + created_at=user.created_at.isoformat() + ) + + +@router.put("/me", response_model=UserResponse) +async def update_user_info( + user_data: UserUpdate, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """更新用户信息""" + auth_service = AuthService(db) + + # 准备更新数据 + update_data = {} + if user_data.full_name is not None: + update_data["full_name"] = user_data.full_name + if user_data.email is not None: + # 检查邮箱是否已被其他用户使用 + existing_user = auth_service.get_user_by_email(user_data.email) + if existing_user and existing_user.username != current_user: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="邮箱已被其他用户使用" + ) + update_data["email"] = user_data.email + + # 更新用户信息 + user = auth_service.update_user( + auth_service.get_user_by_username(current_user).id, + **update_data + ) + + if not user: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="更新用户信息失败" + ) + + return UserResponse( + id=user.id, + username=user.username, + email=user.email, + full_name=user.full_name, + is_active=user.is_active, + created_at=user.created_at.isoformat() + ) + + +@router.post("/change-password") +async def change_password( + password_data: PasswordChange, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """修改密码""" + auth_service = AuthService(db) + user = auth_service.get_user_by_username(current_user) + + success = auth_service.change_password( + user.id, + password_data.old_password, + password_data.new_password + ) + + if not success: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="原密码错误或修改失败" + ) + + return {"message": "密码修改成功"} + + +@router.get("/stats") +async def get_user_stats( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取用户统计信息(管理员功能)""" + auth_service = AuthService(db) + user = auth_service.get_user_by_username(current_user) + + # 检查是否为管理员(这里简化处理,实际应该有更复杂的权限系统) + if not user.is_superuser: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="权限不足" + ) + + stats = auth_service.get_user_statistics() + return stats \ No newline at end of file diff --git a/backend/src/api/chat.py b/backend/src/api/chat.py new file mode 100644 index 0000000..5476f37 --- /dev/null +++ b/backend/src/api/chat.py @@ -0,0 +1,714 @@ +""" +聊天对话API +""" +from fastapi import APIRouter, Depends, HTTPException, status +from fastapi.responses import StreamingResponse +from sqlalchemy.orm import Session +from pydantic import BaseModel +from typing import List, Optional, Dict, Any +import json +import asyncio + +from ..core.database import get_db, SessionLocal +from ..core.security import get_current_user +from ..models.chat import ChatSession, ChatMessage +from ..models.user import User +from ..rag.chains import create_rag_chain +from ..rag.conversation_chains import create_conversation_chain +from ..llm.siliconflow import get_llm_client + +router = APIRouter(prefix="/chat", tags=["聊天"]) + + +def get_user_id_by_username(db: Session, username: str) -> int: + """根据用户名获取用户ID""" + user = db.query(User).filter(User.username == username).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + return user.id + + +class ChatRequest(BaseModel): + """聊天请求模型""" + message: str + session_id: Optional[int] = None + mode: str = "normal" # normal, rag + knowledge_base_ids: Optional[List[int]] = None + model: Optional[str] = None # 模型ID,如 deepseek-ai/DeepSeek-V3, Qwen/QwQ-32B + + +class ChatResponse(BaseModel): + """聊天响应模型""" + answer: str + sources: List[Dict[str, Any]] + session_id: int + message_id: int + + +class ChatSessionResponse(BaseModel): + """聊天会话响应模型""" + id: int + title: str + created_at: str + message_count: int + + +@router.post("/send", response_model=ChatResponse) +async def send_message( + request: ChatRequest, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """发送消息""" + try: + # 获取或创建会话 + if request.session_id: + session = db.query(ChatSession).filter( + ChatSession.id == request.session_id, + ChatSession.user_id == db.query(User).filter(User.username == current_user).first().id + ).first() + if not session: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="会话不存在" + ) + else: + # 创建新会话 + user = db.query(User).filter(User.username == current_user).first() + session = ChatSession( + user_id=user.id, + title=request.message[:50] + "..." if len(request.message) > 50 else request.message + ) + db.add(session) + db.commit() + db.refresh(session) + + # 保存用户消息 + user_message = ChatMessage( + session_id=session.id, + role="user", + content=request.message + ) + db.add(user_message) + db.commit() + db.refresh(user_message) + + # 自动更新会话标题(如果是第一条消息且标题为"新对话") + message_count = db.query(ChatMessage).filter( + ChatMessage.session_id == session.id + ).count() + if message_count == 1 and session.title == "新对话": + # 生成标题:取消息前30个字符 + new_title = request.message.strip()[:30] + "..." if len(request.message.strip()) > 30 else request.message.strip() + session.title = new_title + db.commit() + print(f"[DEBUG-AUTO-TITLE] 自动更新会话标题: {new_title}") + + # 根据模式运行不同的问答工作流 + if request.mode == "rag": + print(f"[DEBUG-RAG] 非流式RAG模式") + print(f"[DEBUG-RAG] 接收到的knowledge_base_ids: {request.knowledge_base_ids}") + print(f"[DEBUG-RAG] knowledge_base_ids类型: {type(request.knowledge_base_ids)}") + if request.knowledge_base_ids: + print(f"[DEBUG-RAG] 第一个ID: {request.knowledge_base_ids[0]}, 类型: {type(request.knowledge_base_ids[0])}") + + # 使用LangChain 1.0 RAG链 + print(f"[DEBUG-RAG] 模型: {request.model}") + rag_chain = create_rag_chain(knowledge_base_ids=request.knowledge_base_ids, model=request.model) + result = rag_chain.invoke(request.message) + else: + # 普通模式:使用LangChain 1.0对话链 + print(f"[DEBUG-CHAT] 普通模式 - 使用LangChain对话链") + print(f"[DEBUG-CHAT] 模型: {request.model}") + conversation_chain = create_conversation_chain(model=request.model) + + # 获取聊天历史 + history_messages = db.query(ChatMessage).filter( + ChatMessage.session_id == session.id + ).order_by(ChatMessage.created_at).limit(10).all() + + chat_history = [] + for msg in history_messages: + chat_history.append({ + "role": msg.role, + "content": msg.content + }) + + result = conversation_chain.invoke(request.message, chat_history=chat_history) + + # 保存助手回复 + assistant_message = ChatMessage( + session_id=session.id, + role="assistant", + content=result["answer"], + message_metadata=json.dumps(result["sources"], ensure_ascii=False) + ) + db.add(assistant_message) + db.commit() + db.refresh(assistant_message) + + return ChatResponse( + answer=result["answer"], + sources=result["sources"], + session_id=session.id, + message_id=assistant_message.id + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"处理消息失败: {str(e)}" + ) + + +@router.post("/stream") +async def stream_message( + request: ChatRequest, + current_user: str = Depends(get_current_user) +): + """流式发送消息""" + async def generate_response(): + # 在生成器内部创建新的数据库会话 + db = SessionLocal() + try: + # 打印请求参数调试信息 + print(f"[DEBUG-CHAT] 接收流式请求 - mode: {request.mode}, knowledge_base_ids: {request.knowledge_base_ids}, model: {request.model}, message: {request.message[:50]}...") + + # 获取或创建会话 + if request.session_id: + session = db.query(ChatSession).filter( + ChatSession.id == request.session_id, + ChatSession.user_id == db.query(User).filter(User.username == current_user).first().id + ).first() + if not session: + yield f"data: {json.dumps({'error': '会话不存在'})}\n\n" + return + else: + # 创建新会话 + user = db.query(User).filter(User.username == current_user).first() + session = ChatSession( + user_id=user.id, + title=request.message[:50] + "..." if len(request.message) > 50 else request.message + ) + db.add(session) + db.commit() + db.refresh(session) + + # 保存用户消息 + user_message = ChatMessage( + session_id=session.id, + role="user", + content=request.message + ) + db.add(user_message) + db.commit() + + # 自动更新会话标题(如果是第一条消息且标题为"新对话") + message_count = db.query(ChatMessage).filter( + ChatMessage.session_id == session.id + ).count() + if message_count == 1 and session.title == "新对话": + # 生成标题:取消息前30个字符 + new_title = request.message.strip()[:30] + "..." if len(request.message.strip()) > 30 else request.message.strip() + session.title = new_title + db.commit() + print(f"[DEBUG-AUTO-TITLE] 自动更新会话标题: {new_title}") + + # 获取聊天历史 + chat_history = [] + previous_messages = db.query(ChatMessage).filter( + ChatMessage.session_id == session.id + ).order_by(ChatMessage.created_at).limit(10).all() + + for msg in previous_messages: + chat_history.append({ + "role": msg.role, + "content": msg.content + }) + + # 根据模式选择不同的处理方式 + if request.mode == "rag": + print(f"[DEBUG-RAG] 使用LangChain 1.0 RAG链") + print(f"[DEBUG-RAG] 接收到的knowledge_base_ids: {request.knowledge_base_ids}") + print(f"[DEBUG-RAG] knowledge_base_ids类型: {type(request.knowledge_base_ids)}") + print(f"[DEBUG-RAG] 模型: {request.model}") + if request.knowledge_base_ids: + print(f"[DEBUG-RAG] 第一个ID: {request.knowledge_base_ids[0]}, 类型: {type(request.knowledge_base_ids[0])}") + + # 创建RAG链 + rag_chain = create_rag_chain( + knowledge_base_ids=request.knowledge_base_ids, + search_type="similarity", + k=5, + model=request.model + ) + + # 使用带思考过程的流式输出 + full_answer = "" + sources = [] + thinking_steps = [] + async for result in rag_chain.astream_with_sources(request.message): + if result["type"] == "thinking": + # 收集思考过程 + thinking_steps.append({ + "stage": result["stage"], + "message": result["message"], + "doc_count": result.get("doc_count"), + "time": result.get("time") + }) + # 发送思考过程 + yield f"data: {json.dumps(result, ensure_ascii=False)}\n\n" + elif result["type"] == "chunk": + full_answer += result["content"] + yield f"data: {json.dumps(result, ensure_ascii=False)}\n\n" + elif result["type"] == "sources": + sources = result["sources"] + if sources: + yield f"data: {json.dumps({'type': 'sources', 'sources': sources}, ensure_ascii=False)}\n\n" + + # 保存到数据库 + assistant_message = ChatMessage( + session_id=session.id, + role="assistant", + content=full_answer, + message_metadata=json.dumps({ + "sources": sources, + "thinking": thinking_steps, + "mode": "rag" + }, ensure_ascii=False) + ) + db.add(assistant_message) + db.commit() + + yield f"data: {json.dumps({'type': 'done', 'session_id': session.id}, ensure_ascii=False)}\n\n" + + else: + # 普通模式:使用LangChain 1.0对话链 + print(f"[DEBUG-CHAT] 普通模式 - 使用LangChain流式对话链") + print(f"[DEBUG-CHAT] 模型: {request.model}") + conversation_chain = create_conversation_chain(model=request.model) + + # 使用带思考过程的流式输出 + full_answer = "" + thinking_steps = [] + async for result in conversation_chain.astream_with_thinking(request.message, chat_history=chat_history): + if result["type"] == "thinking": + # 收集思考过程 + thinking_steps.append({ + "stage": result["stage"], + "message": result["message"], + "time": result.get("time") + }) + yield f"data: {json.dumps(result, ensure_ascii=False)}\n\n" + elif result["type"] == "chunk": + full_answer += result["content"] + yield f"data: {json.dumps({'type': 'chunk', 'content': result['content']}, ensure_ascii=False)}\n\n" + elif result["type"] == "complete": + pass # 完成标记 + + # 保存到数据库 + assistant_message = ChatMessage( + session_id=session.id, + role="assistant", + content=full_answer, + message_metadata=json.dumps({ + "thinking": thinking_steps, + "mode": "normal" + }, ensure_ascii=False) + ) + db.add(assistant_message) + db.commit() + + yield f"data: {json.dumps({'type': 'done', 'session_id': session.id}, ensure_ascii=False)}\n\n" + + except Exception as e: + yield f"data: {json.dumps({'error': str(e)})}\n\n" + finally: + # 确保会话在生成器结束时关闭 + db.close() + + return StreamingResponse( + generate_response(), + media_type="text/plain", + headers={"Cache-Control": "no-cache", "Connection": "keep-alive"} + ) + + +@router.post("/sessions", response_model=ChatSessionResponse) +async def create_session( + title: str = "新对话", + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """创建新会话""" + user = db.query(User).filter(User.username == current_user).first() + + # 创建新会话 + session = ChatSession( + user_id=user.id, + title=title, + is_active=True + ) + + db.add(session) + db.commit() + db.refresh(session) + + return ChatSessionResponse( + id=session.id, + title=session.title, + created_at=session.created_at.isoformat(), + message_count=0 + ) + + +@router.get("/sessions", response_model=List[ChatSessionResponse]) +async def get_sessions( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取聊天会话列表""" + user = db.query(User).filter(User.username == current_user).first() + sessions = db.query(ChatSession).filter( + ChatSession.user_id == user.id, + ChatSession.is_active == True + ).order_by(ChatSession.created_at.desc()).all() + + result = [] + for session in sessions: + message_count = db.query(ChatMessage).filter( + ChatMessage.session_id == session.id + ).count() + + result.append(ChatSessionResponse( + id=session.id, + title=session.title, + created_at=session.created_at.isoformat(), + message_count=message_count + )) + + return result + + +@router.get("/sessions/{session_id}/messages") +async def get_session_messages( + session_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取会话消息""" + user = db.query(User).filter(User.username == current_user).first() + session = db.query(ChatSession).filter( + ChatSession.id == session_id, + ChatSession.user_id == user.id + ).first() + + if not session: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="会话不存在" + ) + + messages = db.query(ChatMessage).filter( + ChatMessage.session_id == session_id + ).order_by(ChatMessage.created_at).all() + + return [ + { + "id": msg.id, + "role": msg.role, + "content": msg.content, + "created_at": msg.created_at.isoformat(), + "thinking": metadata.get("thinking") if metadata else None, + "metadata": metadata + } + for msg in messages + for metadata in [json.loads(msg.message_metadata) if msg.message_metadata else None] + ] + + +# 会话管理 API +class SessionUpdateRequest(BaseModel): + """会话更新请求模型""" + title: str + + +class SessionExportResponse(BaseModel): + """会话导出响应模型""" + session_id: int + title: str + messages: List[Dict[str, Any]] + export_format: str + created_at: str + + +@router.put("/sessions/{session_id}") +async def update_session( + session_id: int, + request: SessionUpdateRequest, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """重命名会话""" + # 获取会话 + session = db.query(ChatSession).filter( + ChatSession.id == session_id, + ChatSession.user_id == get_user_id_by_username(db, current_user) + ).first() + + if not session: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="会话不存在" + ) + + # 更新标题 + session.title = request.title + db.commit() + + return {"message": "会话重命名成功", "title": session.title} + + +@router.delete("/sessions/{session_id}") +async def delete_session( + session_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """删除会话""" + # 获取会话 + session = db.query(ChatSession).filter( + ChatSession.id == session_id, + ChatSession.user_id == get_user_id_by_username(db, current_user) + ).first() + + if not session: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="会话不存在" + ) + + # 删除会话(级联删除消息) + db.delete(session) + db.commit() + + return {"message": "会话删除成功"} + + +@router.post("/sessions/{session_id}/export", response_model=SessionExportResponse) +async def export_session( + session_id: int, + format: str = "json", + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """导出会话""" + # 获取会话 + session = db.query(ChatSession).filter( + ChatSession.id == session_id, + ChatSession.user_id == get_user_id_by_username(db, current_user) + ).first() + + if not session: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="会话不存在" + ) + + # 获取消息 + messages = db.query(ChatMessage).filter( + ChatMessage.session_id == session_id + ).order_by(ChatMessage.created_at).all() + + # 格式化消息 + formatted_messages = [] + for msg in messages: + formatted_messages.append({ + "id": msg.id, + "role": msg.role, + "content": msg.content, + "created_at": msg.created_at.isoformat(), + "feedback": msg.feedback, + "edited": msg.edited + }) + + return SessionExportResponse( + session_id=session.id, + title=session.title or f"会话 {session.id}", + messages=formatted_messages, + export_format=format, + created_at=session.created_at.isoformat() + ) + + +# 消息操作 API +class MessageEditRequest(BaseModel): + """消息编辑请求模型""" + content: str + + +class MessageFeedbackRequest(BaseModel): + """消息反馈请求模型""" + feedback: str # like, dislike + + +@router.put("/messages/{message_id}") +async def edit_message( + message_id: int, + request: MessageEditRequest, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """编辑用户消息""" + # 获取消息 + message = db.query(ChatMessage).join(ChatSession).filter( + ChatMessage.id == message_id, + ChatMessage.role == "user", + ChatSession.user_id == get_user_id_by_username(db, current_user) + ).first() + + if not message: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="消息不存在或无权编辑" + ) + + # 更新消息内容 + message.content = request.content + message.edited = True + db.commit() + + return {"message": "消息编辑成功"} + + +@router.post("/messages/{message_id}/regenerate") +async def regenerate_message( + message_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """重新生成AI回复""" + # 获取原始消息 + original_message = db.query(ChatMessage).join(ChatSession).filter( + ChatMessage.id == message_id, + ChatMessage.role == "user", + ChatSession.user_id == get_user_id_by_username(db, current_user) + ).first() + + if not original_message: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="消息不存在" + ) + + # 删除该消息之后的所有消息 + later_messages = db.query(ChatMessage).filter( + ChatMessage.session_id == original_message.session_id, + ChatMessage.created_at > original_message.created_at + ).all() + + for msg in later_messages: + db.delete(msg) + + # 重新生成回复 + try: + # 使用RAG工作流重新生成 + response_data = await run_rag_workflow_with_context( + original_message.content, + original_message.session_id, + db, + None # No knowledge base filtering for regeneration + ) + + # 创建新的AI回复 + new_message = ChatMessage( + session_id=original_message.session_id, + role="assistant", + content=response_data["answer"], + message_metadata=json.dumps({ + "sources": response_data["sources"], + "metadata": response_data.get("metadata", {}) + }), + regenerated_from=message_id + ) + + db.add(new_message) + db.commit() + + return { + "message": "消息重新生成成功", + "new_message_id": new_message.id, + "content": new_message.content + } + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"重新生成失败: {str(e)}" + ) + + +@router.post("/messages/{message_id}/feedback") +async def feedback_message( + message_id: int, + request: MessageFeedbackRequest, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """给消息点赞/踩""" + # 获取消息 + message = db.query(ChatMessage).join(ChatSession).filter( + ChatMessage.id == message_id, + ChatMessage.role == "assistant", + ChatSession.user_id == get_user_id_by_username(db, current_user) + ).first() + + if not message: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="消息不存在或无权操作" + ) + + # 更新反馈 + message.feedback = request.feedback + db.commit() + + return {"message": "反馈提交成功", "feedback": request.feedback} + + +async def run_rag_workflow_with_context(question: str, session_id: int, db: Session, knowledge_base_ids: Optional[List[int]] = None) -> Dict[str, Any]: + """运行带上下文的RAG工作流""" + try: + # 获取会话历史消息作为上下文 + session_messages = db.query(ChatMessage).filter( + ChatMessage.session_id == session_id + ).order_by(ChatMessage.created_at.desc()).limit(10).all() + + # 构建上下文 + context_messages = [] + for msg in reversed(session_messages): + if msg.role == "user": + context_messages.append({"role": "user", "content": msg.content}) + elif msg.role == "assistant": + context_messages.append({"role": "assistant", "content": msg.content}) + + # 运行RAG工作流 + rag_chain = create_rag_chain(knowledge_base_ids=knowledge_base_ids) + result = rag_chain.invoke(question) + + # 如果有上下文,增强回答 + if context_messages: + # 这里可以添加基于上下文的增强逻辑 + # 例如:检查是否与之前的问题相关,提供更个性化的回答 + pass + + return result + + except Exception as e: + print(f"RAG工作流执行失败: {str(e)}") + # 降级到基础问答 + rag_chain = create_rag_chain() + return rag_chain.invoke(question) diff --git a/backend/src/api/course_content.py b/backend/src/api/course_content.py new file mode 100644 index 0000000..0a9dc4b --- /dev/null +++ b/backend/src/api/course_content.py @@ -0,0 +1,232 @@ +""" +课程内容API +层级结构:书籍 -> Chapter -> Section -> Subsection(知识点) +""" +from typing import List, Optional +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session +from pydantic import BaseModel + +from ..core.database import get_db +from ..core.security import get_current_user +from ..core.config import get_settings +from ..models.course_content import CourseModule +from ..models.book_structure import Book, Chapter, Section, Subsection +from ..services.book_content_service import BookContentService + +router = APIRouter(prefix="/course-content", tags=["课程内容"]) + +# 初始化书籍内容服务 +settings = get_settings() +book_content_service = BookContentService(settings.book_dir) + + +# 旧的响应模型(向后兼容) +class CourseModuleResponse(BaseModel): + """课程模块响应模型""" + id: int + module_name: str + core_knowledge_points: str + digitalization_necessity: str + expanded_knowledge_points: List[str] + display_order: int + + class Config: + from_attributes = True + + +# 新的书籍结构响应模型 +class SubsectionResponse(BaseModel): + """小节响应模型(知识点)""" + id: int + subsection_number: int + title: str + display_order: int + + class Config: + from_attributes = True + + +class SectionResponse(BaseModel): + """节响应模型""" + id: int + section_number: int + title: str + display_order: int + subsections: List[SubsectionResponse] # 小节(知识点)列表 + + class Config: + from_attributes = True + + +class ChapterResponse(BaseModel): + """章节响应模型""" + id: int + chapter_number: int + title: str + display_order: int + sections: List[SectionResponse] # 节列表 + + class Config: + from_attributes = True + + +class BookStructureResponse(BaseModel): + """书籍结构响应模型""" + book: dict + chapters: List[ChapterResponse] + + +class ContentResponse(BaseModel): + """内容响应模型""" + content: str + + +@router.get("", response_model=BookStructureResponse) +async def get_course_content( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取书籍层级结构(章节、节、小节/知识点)""" + try: + # 获取书籍(假设只有一个书籍) + book = db.query(Book).first() + if not book: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="未找到书籍数据,请先运行导入脚本" + ) + + # 获取所有章节及其子节点 + chapters = db.query(Chapter).filter( + Chapter.book_id == book.id + ).order_by(Chapter.display_order.asc()).all() + + chapter_responses = [] + for chapter in chapters: + # 获取章节下的节(Section) + sections = db.query(Section).filter( + Section.chapter_id == chapter.id + ).order_by(Section.display_order.asc()).all() + + section_responses = [] + for section in sections: + # 获取节下的小节(Subsection,作为知识点) + subsections = db.query(Subsection).filter( + Subsection.section_id == section.id + ).order_by(Subsection.display_order.asc()).all() + + subsection_responses = [ + SubsectionResponse( + id=sub.id, + subsection_number=sub.subsection_number, + title=sub.title, + display_order=sub.display_order + ) + for sub in subsections + ] + + section_responses.append(SectionResponse( + id=section.id, + section_number=section.section_number, + title=section.title, + display_order=section.display_order, + subsections=subsection_responses + )) + + chapter_responses.append(ChapterResponse( + id=chapter.id, + chapter_number=chapter.chapter_number, + title=chapter.title, + display_order=chapter.display_order, + sections=section_responses + )) + + return BookStructureResponse( + book={ + "id": book.id, + "title": book.title, + "description": book.description + }, + chapters=chapter_responses + ) + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取课程内容失败: {str(e)}" + ) + + +@router.get("/chapters/{chapter_id}/content", response_model=ContentResponse) +async def get_chapter_content( + chapter_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取章节完整内容""" + try: + content = book_content_service.get_chapter_content(db, chapter_id) + if content is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="章节不存在或内容读取失败" + ) + return ContentResponse(content=content) + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取章节内容失败: {str(e)}" + ) + + +@router.get("/sections/{section_id}/content", response_model=ContentResponse) +async def get_section_content( + section_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取节完整内容""" + try: + content = book_content_service.get_section_content(db, section_id) + if content is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="节不存在或内容读取失败" + ) + return ContentResponse(content=content) + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取节内容失败: {str(e)}" + ) + + +@router.get("/subsections/{subsection_id}/content", response_model=ContentResponse) +async def get_subsection_content( + subsection_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取小节完整内容(知识点,包含其下所有subsubsection内容)""" + try: + content = book_content_service.get_subsection_content(db, subsection_id) + if content is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="小节不存在或内容读取失败" + ) + return ContentResponse(content=content) + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取小节内容失败: {str(e)}" + ) diff --git a/backend/src/api/document.py b/backend/src/api/document.py new file mode 100644 index 0000000..7f790a4 --- /dev/null +++ b/backend/src/api/document.py @@ -0,0 +1,332 @@ +""" +文档管理API +""" +import asyncio +import os +import uuid +from pathlib import Path +from typing import List, Optional +from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File +from sqlalchemy.orm import Session +from pydantic import BaseModel + +from ..core.database import get_db +from ..core.security import get_current_user +from ..models.document import Document, DocumentChunk +from ..services.document_service import DocumentService + +router = APIRouter(prefix="/documents", tags=["文档管理"]) + + +class DocumentResponse(BaseModel): + """文档响应模型""" + id: int + filename: str + title: str + file_size: int + file_type: str + is_processed: bool + is_public: bool + created_at: str + + +class DocumentUploadResponse(BaseModel): + """文档上传响应模型""" + id: int + filename: str + message: str + + +class DocumentStats(BaseModel): + """文档统计模型""" + total_documents: int + processed_documents: int + total_size: int + file_types: dict + + +@router.post("/upload", response_model=DocumentUploadResponse, deprecated=True) +async def upload_document( + file: UploadFile = File(...), + title: Optional[str] = None, + description: Optional[str] = None, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """上传文档(已废弃,请使用知识库上传接口)""" + raise HTTPException( + status_code=status.HTTP_410_GONE, + detail="此接口已废弃,请使用知识库上传接口:POST /knowledge-bases/{knowledge_base_id}/documents" + ) + + +@router.get("/", response_model=List[DocumentResponse]) +async def get_documents( + skip: int = 0, + limit: int = 100, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取文档列表""" + try: + # 获取用户ID + from ..models.user import User + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 获取用户的文档 + documents = db.query(Document).filter( + Document.user_id == user.id + ).offset(skip).limit(limit).all() + + return [ + DocumentResponse( + id=doc.id, + filename=doc.filename, + title=doc.title, + file_size=doc.file_size, + file_type=doc.file_type, + is_processed=doc.is_processed, + is_public=doc.is_public, + created_at=doc.created_at.isoformat() + ) + for doc in documents + ] + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取文档列表失败: {str(e)}" + ) + + +@router.get("/{document_id}", response_model=DocumentResponse) +async def get_document( + document_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取单个文档信息""" + try: + # 获取用户ID + from ..models.user import User + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 获取文档 + document = db.query(Document).filter( + Document.id == document_id, + Document.user_id == user.id + ).first() + + if not document: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="文档不存在" + ) + + return DocumentResponse( + id=document.id, + filename=document.filename, + title=document.title, + file_size=document.file_size, + file_type=document.file_type, + is_processed=document.is_processed, + is_public=document.is_public, + created_at=document.created_at.isoformat() + ) + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取文档信息失败: {str(e)}" + ) + + +@router.delete("/{document_id}") +async def delete_document( + document_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """删除文档""" + try: + # 获取用户ID + from ..models.user import User + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 获取文档 + document = db.query(Document).filter( + Document.id == document_id, + Document.user_id == user.id + ).first() + + if not document: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="文档不存在" + ) + + # 1. 先删除向量数据和文档块 + try: + print(f"开始删除文档向量数据: {document.filename} (ID: {document.id})") + document_service = DocumentService(db) + vector_deleted = document_service.delete_document_chunks(document.id) + if vector_deleted: + print(f"成功删除文档向量数据: {document.filename}") + else: + print(f"警告:删除文档向量数据失败: {document.filename}") + except Exception as e: + print(f"删除向量数据时发生错误: {str(e)}") + import traceback + print(f"详细错误信息: {traceback.format_exc()}") + + # 2. 删除物理文件 + try: + if os.path.exists(document.file_path): + os.remove(document.file_path) + print(f"成功删除物理文件: {document.file_path}") + else: + print(f"物理文件不存在: {document.file_path}") + except Exception as e: + print(f"删除物理文件时发生错误: {str(e)}") + + # 3. 删除数据库记录 + db.delete(document) + db.commit() + print(f"成功删除文档数据库记录: {document.filename}") + + return {"message": "文档删除成功"} + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"删除文档失败: {str(e)}" + ) + + +@router.post("/{document_id}/process") +async def process_document( + document_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """处理文档(向量化)""" + try: + # 获取用户ID + from ..models.user import User + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 获取文档 + document = db.query(Document).filter( + Document.id == document_id, + Document.user_id == user.id + ).first() + + if not document: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="文档不存在" + ) + + if document.is_processed: + return {"message": "文档已经处理过了"} + + # 处理文档 + document_service = DocumentService(db) + success = await asyncio.to_thread(document_service.process_document, document.id) + + if success: + return {"message": "文档处理成功"} + else: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="文档处理失败" + ) + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"处理文档失败: {str(e)}" + ) + + +@router.get("/stats/overview", response_model=DocumentStats) +async def get_document_stats( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取文档统计信息""" + try: + # 获取用户ID + from ..models.user import User + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 统计信息 + total_documents = db.query(Document).filter(Document.user_id == user.id).count() + processed_documents = db.query(Document).filter( + Document.user_id == user.id, + Document.is_processed == True + ).count() + + # 计算总大小 + documents = db.query(Document).filter(Document.user_id == user.id).all() + total_size = sum(doc.file_size for doc in documents) + + # 文件类型统计 + file_types = {} + for doc in documents: + file_type = doc.file_type + file_types[file_type] = file_types.get(file_type, 0) + 1 + + return DocumentStats( + total_documents=total_documents, + processed_documents=processed_documents, + total_size=total_size, + file_types=file_types + ) + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取统计信息失败: {str(e)}" + ) + + + + + + diff --git a/backend/src/api/forum.py b/backend/src/api/forum.py new file mode 100644 index 0000000..055d897 --- /dev/null +++ b/backend/src/api/forum.py @@ -0,0 +1,225 @@ +""" +论坛功能相关 API +""" +from typing import List, Optional + +from fastapi import APIRouter, Depends, HTTPException, status +from pydantic import BaseModel +from sqlalchemy.orm import Session + +from ..core.database import get_db +from ..core.security import get_current_user +from ..models.forum import ForumCategory, ForumPost, ForumReply +from ..models.user import User + +router = APIRouter(prefix="/forum", tags=["论坛"]) + + +class ForumCategoryResponse(BaseModel): + id: int + slug: str + name: str + description: Optional[str] + post_count: int + + class Config: + from_attributes = True + + +class ForumPostSummary(BaseModel): + id: int + title: str + author_name: str + created_at: str + reply_count: int + + class Config: + from_attributes = True + + +class ForumReplyResponse(BaseModel): + id: int + content: str + author_name: str + created_at: str + + class Config: + from_attributes = True + + +class ForumPostDetail(BaseModel): + id: int + title: str + content: str + author_name: str + created_at: str + replies: List[ForumReplyResponse] + + class Config: + from_attributes = True + + +ForumPostDetail.model_rebuild() + + +class CreatePostRequest(BaseModel): + title: str + content: str + + +class CreateReplyRequest(BaseModel): + content: str + + +@router.get("/categories", response_model=List[ForumCategoryResponse]) +def list_categories(db: Session = Depends(get_db)): + categories = db.query(ForumCategory).all() + results: List[ForumCategoryResponse] = [] + for category in categories: + post_count = db.query(ForumPost).filter(ForumPost.category_id == category.id).count() + results.append( + ForumCategoryResponse( + id=category.id, + slug=category.slug, + name=category.name, + description=category.description, + post_count=post_count, + ) + ) + return results + + +@router.get("/categories/{category_id}/posts", response_model=List[ForumPostSummary]) +def list_posts(category_id: int, db: Session = Depends(get_db), limit: int = 20): + posts = ( + db.query(ForumPost) + .filter(ForumPost.category_id == category_id) + .order_by(ForumPost.created_at.desc()) + .limit(limit) + .all() + ) + results: List[ForumPostSummary] = [] + for post in posts: + reply_count = db.query(ForumReply).filter(ForumReply.post_id == post.id).count() + author_name = post.author.full_name or post.author.username if post.author else "匿名" + results.append( + ForumPostSummary( + id=post.id, + title=post.title, + author_name=author_name, + created_at=post.created_at.isoformat() if post.created_at else "", + reply_count=reply_count, + ) + ) + return results + + +@router.post( + "/categories/{category_id}/posts", + status_code=status.HTTP_201_CREATED, + response_model=ForumPostDetail, +) +def create_post( + category_id: int, + payload: CreatePostRequest, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + category = db.query(ForumCategory).filter(ForumCategory.id == category_id).first() + if not category: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="分类不存在") + + author = db.query(User).filter(User.username == current_user).first() + if not author: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在") + + post = ForumPost( + category_id=category.id, + user_id=author.id, + title=payload.title.strip(), + content=payload.content.strip(), + ) + db.add(post) + db.commit() + db.refresh(post) + + return ForumPostDetail( + id=post.id, + title=post.title, + content=post.content, + author_name=author.full_name or author.username, + created_at=post.created_at.isoformat() if post.created_at else "", + replies=[], + ) + + +@router.get("/posts/{post_id}", response_model=ForumPostDetail) +def get_post_detail(post_id: int, db: Session = Depends(get_db)): + post = ( + db.query(ForumPost) + .filter(ForumPost.id == post_id) + .first() + ) + if not post: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="帖子不存在") + + replies = ( + db.query(ForumReply) + .filter(ForumReply.post_id == post.id) + .order_by(ForumReply.created_at.asc()) + .all() + ) + + return ForumPostDetail( + id=post.id, + title=post.title, + content=post.content, + author_name=post.author.full_name or post.author.username if post.author else "匿名", + created_at=post.created_at.isoformat() if post.created_at else "", + replies=[ + ForumReplyResponse( + id=reply.id, + content=reply.content, + author_name=reply.author.full_name or reply.author.username if reply.author else "匿名", + created_at=reply.created_at.isoformat() if reply.created_at else "", + ) + for reply in replies + ], + ) + + +@router.post( + "/posts/{post_id}/replies", + status_code=status.HTTP_201_CREATED, + response_model=ForumReplyResponse, +) +def create_reply( + post_id: int, + payload: CreateReplyRequest, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + post = db.query(ForumPost).filter(ForumPost.id == post_id).first() + if not post: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="帖子不存在") + + author = db.query(User).filter(User.username == current_user).first() + if not author: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在") + + reply = ForumReply( + post_id=post.id, + user_id=author.id, + content=payload.content.strip(), + ) + db.add(reply) + db.commit() + db.refresh(reply) + + return ForumReplyResponse( + id=reply.id, + content=reply.content, + author_name=author.full_name or author.username, + created_at=reply.created_at.isoformat() if reply.created_at else "", + ) + diff --git a/backend/src/api/image.py b/backend/src/api/image.py new file mode 100644 index 0000000..492451a --- /dev/null +++ b/backend/src/api/image.py @@ -0,0 +1,411 @@ +""" +图像生成和分析API +支持文生图和图生图功能 +""" + +import json +from typing import List, Optional +from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form +from sqlalchemy.orm import Session + +from ..core.database import get_db +from ..core.security import get_current_user +from ..models.user import User +from ..models.generated_image import GeneratedImageRecord +from ..models.image_models import ( + TextToImageRequest, TextToImageResponse, GeneratedImage, + ImageEditRequest, ImageEditResponse, ImageEditResult, + ImageVariationRequest, ImageVariationResponse, ImageVariationResult, + ModelInfo, TemplateInfo, StyleInfo, SizeInfo, EditModeInfo +) +from ..services.text_to_image_service import TextToImageService +from ..services.image_to_image_service import ImageToImageService + +router = APIRouter(prefix="/image", tags=["图像生成"]) + +# 服务实例 +text_to_image_service = TextToImageService() +image_to_image_service = ImageToImageService() + + +def _save_record(db: Session, user_id: int, image_id: str, image_type: str, + image_url: str, prompt: str = None, model: str = None, + style: str = None, size: str = None, template: str = None, + original_filename: str = None, mode: str = None, + strength: float = None, metadata: dict = None): + """保存图像生成记录到数据库""" + record = GeneratedImageRecord( + user_id=user_id, + image_id=image_id, + image_type=image_type, + prompt=prompt, + model=model, + style=style, + size=size, + template=template, + image_url=image_url, + original_filename=original_filename, + mode=mode, + strength=str(strength) if strength else None, + generation_meta=json.dumps(metadata or {}, ensure_ascii=False), + ) + db.add(record) + db.commit() + + +@router.post("/text-to-image", response_model=TextToImageResponse) +async def text_to_image( + request: TextToImageRequest, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """文生图 - 从文字描述生成图像""" + try: + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + images_data = await text_to_image_service.generate( + prompt=request.prompt, model=request.model, template=request.template, + style=request.style, size=request.size, num_images=request.num_images + ) + + images = [ + GeneratedImage(id=img["id"], url=img["url"], prompt=img["prompt"], + model=img["model"], metadata=img["metadata"]) + for img in images_data + ] + + for img in images_data: + _save_record(db, user.id, img["id"], "text_to_image", img["url"], + prompt=request.prompt, model=request.model, + style=request.style, size=request.size, + template=request.template, metadata=img.get("metadata")) + + return TextToImageResponse(images=images, total=len(images)) + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"文生图失败: {str(e)}") + + +@router.post("/image-to-image/edit", response_model=ImageEditResponse) +async def image_edit( + image: UploadFile = File(...), + prompt: str = Form(...), + mode: str = Form("optimize"), + mask: Optional[UploadFile] = File(None), + strength: float = Form(0.8), + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """图生图 - 图像编辑""" + try: + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + result_data = await image_to_image_service.edit_image( + image_file=image, prompt=prompt, mode=mode, mask_file=mask, strength=strength + ) + + result = ImageEditResult( + id=result_data["id"], url=result_data["url"], + original_filename=result_data["original_filename"], + edit_prompt=result_data["edit_prompt"], mode=result_data["mode"], + metadata=result_data["metadata"] + ) + + _save_record(db, user.id, result_data["id"], "image_edit", result_data["url"], + prompt=prompt, model="Qwen-Image-Edit", + original_filename=result_data.get("original_filename"), + mode=mode, strength=strength, metadata=result_data.get("metadata")) + + return ImageEditResponse(result=result) + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"图像编辑失败: {str(e)}") + + +@router.post("/image-to-image/variations", response_model=ImageVariationResponse) +async def image_variations( + image: UploadFile = File(...), + num_variations: int = Form(3), + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """图生图 - 生成图像变体""" + try: + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + variations_data = await image_to_image_service.create_variation( + image_file=image, num_variations=num_variations + ) + + variations = [ + ImageVariationResult(id=var["id"], url=var["url"], type=var["type"], metadata=var["metadata"]) + for var in variations_data + ] + + for var in variations_data: + _save_record(db, user.id, var["id"], "variation", var["url"], + model="Qwen-Image-Edit", metadata=var.get("metadata")) + + return ImageVariationResponse(variations=variations, total=len(variations)) + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"生成图像变体失败: {str(e)}") + + +@router.post("/image-to-image/style-transfer", response_model=ImageEditResponse) +async def style_transfer( + image: UploadFile = File(...), + style_prompt: str = Form(...), + strength: float = Form(0.8), + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """图生图 - 风格转换""" + try: + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + result_data = await image_to_image_service.style_transfer( + image_file=image, style_prompt=style_prompt, strength=strength + ) + + result = ImageEditResult( + id=result_data["id"], url=result_data["url"], + original_filename=result_data["original_filename"], + edit_prompt=result_data["edit_prompt"], mode=result_data["mode"], + metadata=result_data["metadata"] + ) + + _save_record(db, user.id, result_data["id"], "style_transfer", result_data["url"], + prompt=style_prompt, model="Qwen-Image-Edit", + original_filename=result_data.get("original_filename"), + mode="style_transfer", strength=strength, metadata=result_data.get("metadata")) + + return ImageEditResponse(result=result) + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"风格转换失败: {str(e)}") + + +@router.post("/image-to-image/optimize", response_model=ImageEditResponse) +async def optimize_image( + image: UploadFile = File(...), + optimization_prompt: str = Form("优化图像质量,增强细节,提高清晰度"), + strength: float = Form(0.6), + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """图生图 - 图像优化""" + try: + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + result_data = await image_to_image_service.optimize_image( + image_file=image, optimization_prompt=optimization_prompt, strength=strength + ) + + result = ImageEditResult( + id=result_data["id"], url=result_data["url"], + original_filename=result_data["original_filename"], + edit_prompt=result_data["edit_prompt"], mode=result_data["mode"], + metadata=result_data["metadata"] + ) + + _save_record(db, user.id, result_data["id"], "optimize", result_data["url"], + prompt=optimization_prompt, model="Qwen-Image-Edit", + original_filename=result_data.get("original_filename"), + mode="optimize", strength=strength, metadata=result_data.get("metadata")) + + return ImageEditResponse(result=result) + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"图像优化失败: {str(e)}") + + +@router.post("/image-to-image/outpaint", response_model=ImageEditResponse) +async def outpaint_image( + image: UploadFile = File(...), + expansion_prompt: str = Form(...), + strength: float = Form(0.7), + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """图生图 - 图像智能扩展""" + try: + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + result_data = await image_to_image_service.outpaint_image( + image_file=image, expansion_prompt=expansion_prompt, strength=strength + ) + + result = ImageEditResult( + id=result_data["id"], url=result_data["url"], + original_filename=result_data["original_filename"], + edit_prompt=result_data["edit_prompt"], mode=result_data["mode"], + metadata=result_data["metadata"] + ) + + _save_record(db, user.id, result_data["id"], "outpaint", result_data["url"], + prompt=expansion_prompt, model="Qwen-Image-Edit", + original_filename=result_data.get("original_filename"), + mode="outpaint", strength=strength, metadata=result_data.get("metadata")) + + return ImageEditResponse(result=result) + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"图像扩展失败: {str(e)}") + + +# 配置信息端点 +@router.get("/models") +async def get_available_models(): + """获取可用的模型列表""" + models_data = text_to_image_service.get_available_models() + return { + "models": [ + ModelInfo(id=model["id"], name=model["name"], description=model["description"]) + for model in models_data + ] + } + + +@router.get("/templates") +async def get_available_templates(): + """获取可用的提示词模板""" + templates_data = text_to_image_service.get_available_templates() + return { + "templates": [ + TemplateInfo(id=template["id"], name=template["name"], description=template["description"]) + for template in templates_data + ] + } + + +@router.get("/styles") +async def get_available_styles(): + """获取可用的风格选项""" + styles_data = text_to_image_service.get_available_styles() + return { + "styles": [ + StyleInfo(id=style["id"], name=style["name"], description=style["description"]) + for style in styles_data + ] + } + + +@router.get("/sizes") +async def get_available_sizes(): + """获取可用的尺寸选项""" + sizes_data = text_to_image_service.get_available_sizes() + return { + "sizes": [ + SizeInfo(id=size["id"], name=size["name"], description=size["description"]) + for size in sizes_data + ] + } + + +@router.get("/edit-modes") +async def get_edit_modes(): + """获取可用的编辑模式""" + modes_data = image_to_image_service.get_available_modes() + return { + "modes": [ + EditModeInfo(id=mode["id"], name=mode["name"], description=mode["description"]) + for mode in modes_data + ] + } + + +@router.get("/style-presets") +async def get_style_presets(): + """获取预设风格选项""" + presets_data = image_to_image_service.get_style_presets() + return { + "presets": [ + StyleInfo(id=preset["id"], name=preset["name"], description=preset["description"]) + for preset in presets_data + ] + } + + +@router.get("/history") +async def get_image_history( + page: int = 1, + page_size: int = 20, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取用户的图像生成历史""" + try: + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + total = db.query(GeneratedImageRecord).filter(GeneratedImageRecord.user_id == user.id).count() + records = ( + db.query(GeneratedImageRecord) + .filter(GeneratedImageRecord.user_id == user.id) + .order_by(GeneratedImageRecord.created_at.desc()) + .offset((page - 1) * page_size) + .limit(page_size) + .all() + ) + + images = [] + for r in records: + img = { + "id": r.image_id, + "url": r.image_url, + "image_type": r.image_type, + "prompt": r.prompt, + "model": r.model, + "created_at": r.created_at.isoformat() if r.created_at else None, + } + if r.style: + img["style"] = r.style + if r.size: + img["size"] = r.size + if r.template: + img["template"] = r.template + if r.mode: + img["mode"] = r.mode + if r.original_filename: + img["original_filename"] = r.original_filename + images.append(img) + + return { + "images": images, + "total": total, + "page": page, + "page_size": page_size, + "has_next": page * page_size < total, + "has_prev": page > 1 + } + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"获取图像历史失败: {str(e)}") diff --git a/backend/src/api/knowledge_base.py b/backend/src/api/knowledge_base.py new file mode 100644 index 0000000..86eef1f --- /dev/null +++ b/backend/src/api/knowledge_base.py @@ -0,0 +1,809 @@ +""" +知识库CRUD API +""" +import os +import uuid +from pathlib import Path +from typing import List, Optional, Dict, Any +from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File +from sqlalchemy.orm import Session +from sqlalchemy import or_ +from pydantic import BaseModel + +from ..core.database import get_db +from ..core.security import get_current_user +from ..core.config import settings +from ..models.knowledge_base import KnowledgeBase +from ..models.document import Document +from ..models.user import User +from ..services.document_service import DocumentService + +router = APIRouter(prefix="/knowledge-bases", tags=["知识库管理"]) + + +class KnowledgeBaseResponse(BaseModel): + """知识库响应模型""" + id: int + name: str + description: Optional[str] + user_id: int + document_count: int + created_at: str + updated_at: str + is_system: bool + + +class KnowledgeBaseCreate(BaseModel): + """创建知识库请求模型""" + name: str + description: Optional[str] = None + + +class KnowledgeBaseUpdate(BaseModel): + """更新知识库请求模型""" + name: Optional[str] = None + description: Optional[str] = None + + +class KnowledgeBaseDetailResponse(KnowledgeBaseResponse): + """知识库详情响应模型""" + documents: List[dict] + + +class DocumentUploadResponse(BaseModel): + """文档上传响应模型""" + id: int + filename: str + title: str + message: str + + +@router.get("", response_model=List[KnowledgeBaseResponse]) +async def get_knowledge_bases( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取用户的所有知识库""" + print(f"DEBUG: get_knowledge_bases called for user: {current_user}") + try: + # 获取用户ID + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 获取用户的知识库:包括用户自己的知识库 + 所有系统知识库 + knowledge_bases = db.query(KnowledgeBase).filter( + or_( + KnowledgeBase.user_id == user.id, # 用户自己的知识库 + KnowledgeBase.is_system == True # 所有系统知识库(所有用户可见) + ) + ).all() + + result = [] + for kb in knowledge_bases: + # 计算文档数量 + document_count = db.query(Document).filter( + Document.knowledge_base_id == kb.id + ).count() + + result.append(KnowledgeBaseResponse( + id=kb.id, + name=kb.name, + description=kb.description, + user_id=kb.user_id, + document_count=document_count, + created_at=kb.created_at.isoformat(), + updated_at=kb.updated_at.isoformat() if kb.updated_at else kb.created_at.isoformat(), + is_system=kb.is_system + )) + + return result + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取知识库列表失败: {str(e)}" + ) + + +@router.post("", response_model=KnowledgeBaseResponse) +async def create_knowledge_base( + data: KnowledgeBaseCreate, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """创建新知识库""" + print(f"DEBUG: create_knowledge_base called for user: {current_user}, data: {data}") + try: + # 获取用户ID + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 检查知识库名称是否已存在 + existing_kb = db.query(KnowledgeBase).filter( + KnowledgeBase.name == data.name, + KnowledgeBase.user_id == user.id + ).first() + + if existing_kb: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="知识库名称已存在" + ) + + # 创建知识库 + knowledge_base = KnowledgeBase( + name=data.name, + description=data.description, + user_id=user.id + ) + + db.add(knowledge_base) + db.commit() + db.refresh(knowledge_base) + + return KnowledgeBaseResponse( + id=knowledge_base.id, + name=knowledge_base.name, + description=knowledge_base.description, + user_id=knowledge_base.user_id, + document_count=0, + created_at=knowledge_base.created_at.isoformat(), + updated_at=knowledge_base.updated_at.isoformat() if knowledge_base.updated_at else knowledge_base.created_at.isoformat(), + is_system=knowledge_base.is_system + ) + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"创建知识库失败: {str(e)}" + ) + + +@router.get("/{knowledge_base_id}", response_model=KnowledgeBaseDetailResponse) +async def get_knowledge_base( + knowledge_base_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取知识库详情""" + try: + # 获取用户ID + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 获取知识库:用户自己的知识库或系统知识库(所有用户可查看) + knowledge_base = db.query(KnowledgeBase).filter( + KnowledgeBase.id == knowledge_base_id, + or_( + KnowledgeBase.user_id == user.id, # 用户自己的知识库 + KnowledgeBase.is_system == True # 系统知识库(所有用户可见) + ) + ).first() + + if not knowledge_base: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="知识库不存在" + ) + + # 获取知识库的文档 + documents = db.query(Document).filter( + Document.knowledge_base_id == knowledge_base_id + ).all() + + document_list = [] + for doc in documents: + document_list.append({ + "id": doc.id, + "filename": doc.filename, + "title": doc.title, + "file_size": doc.file_size, + "file_type": doc.file_type, + "is_processed": doc.is_processed, + "is_public": doc.is_public, + "knowledge_base_id": doc.knowledge_base_id, + "created_at": doc.created_at.isoformat(), + "updated_at": doc.updated_at.isoformat() if doc.updated_at else doc.created_at.isoformat() + }) + + return KnowledgeBaseDetailResponse( + id=knowledge_base.id, + name=knowledge_base.name, + description=knowledge_base.description, + user_id=knowledge_base.user_id, + document_count=len(documents), + created_at=knowledge_base.created_at.isoformat(), + updated_at=knowledge_base.updated_at.isoformat() if knowledge_base.updated_at else knowledge_base.created_at.isoformat(), + is_system=knowledge_base.is_system, + documents=document_list + ) + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取知识库详情失败: {str(e)}" + ) + + +@router.put("/{knowledge_base_id}", response_model=KnowledgeBaseResponse) +async def update_knowledge_base( + knowledge_base_id: int, + data: KnowledgeBaseUpdate, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """更新知识库""" + try: + # 获取用户ID + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 获取知识库 + knowledge_base = db.query(KnowledgeBase).filter( + KnowledgeBase.id == knowledge_base_id, + KnowledgeBase.user_id == user.id + ).first() + + if not knowledge_base: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="知识库不存在" + ) + + # 更新字段 + if data.name is not None: + # 检查新名称是否已存在 + existing_kb = db.query(KnowledgeBase).filter( + KnowledgeBase.name == data.name, + KnowledgeBase.user_id == user.id, + KnowledgeBase.id != knowledge_base_id + ).first() + + if existing_kb: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="知识库名称已存在" + ) + knowledge_base.name = data.name + + if data.description is not None: + knowledge_base.description = data.description + + db.commit() + db.refresh(knowledge_base) + + # 计算文档数量 + document_count = db.query(Document).filter( + Document.knowledge_base_id == knowledge_base_id + ).count() + + return KnowledgeBaseResponse( + id=knowledge_base.id, + name=knowledge_base.name, + description=knowledge_base.description, + user_id=knowledge_base.user_id, + document_count=document_count, + created_at=knowledge_base.created_at.isoformat(), + updated_at=knowledge_base.updated_at.isoformat() if knowledge_base.updated_at else knowledge_base.created_at.isoformat(), + is_system=knowledge_base.is_system + ) + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"更新知识库失败: {str(e)}" + ) + + +@router.delete("/{knowledge_base_id}") +async def delete_knowledge_base( + knowledge_base_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """删除知识库""" + try: + # 获取用户ID + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 获取知识库 + knowledge_base = db.query(KnowledgeBase).filter( + KnowledgeBase.id == knowledge_base_id, + KnowledgeBase.user_id == user.id + ).first() + + if not knowledge_base: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="知识库不存在" + ) + + # 1. 获取知识库下的所有文档 + documents = db.query(Document).filter( + Document.knowledge_base_id == knowledge_base_id + ).all() + + print(f"开始删除知识库 '{knowledge_base.name}',包含 {len(documents)} 个文档") + + # 2. 逐个删除文档的向量数据和物理文件 + document_service = DocumentService(db) + success_count = 0 + error_count = 0 + + for document in documents: + try: + # 删除向量数据 + vector_deleted = document_service.delete_document_chunks(document.id) + if vector_deleted: + print(f"成功删除文档向量数据: {document.filename}") + else: + print(f"警告:删除文档向量数据失败: {document.filename}") + error_count += 1 + + # 删除物理文件 + if os.path.exists(document.file_path): + os.remove(document.file_path) + print(f"成功删除物理文件: {document.file_path}") + else: + print(f"物理文件不存在: {document.file_path}") + + success_count += 1 + + except Exception as e: + print(f"删除文档 {document.filename} 的资源时出错: {str(e)}") + import traceback + print(f"详细错误信息: {traceback.format_exc()}") + error_count += 1 + # 继续处理其他文档 + + print(f"文档清理完成: 成功 {success_count} 个,失败 {error_count} 个") + + # 3. 删除知识库(级联删除文档记录) + db.delete(knowledge_base) + db.commit() + print(f"成功删除知识库数据库记录: {knowledge_base.name}") + + return {"message": "知识库删除成功"} + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"删除知识库失败: {str(e)}" + ) + + +@router.post("/{knowledge_base_id}/documents", response_model=DocumentUploadResponse) +async def upload_document_to_knowledge_base( + knowledge_base_id: int, + file: UploadFile = File(...), + title: Optional[str] = None, + description: Optional[str] = None, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """上传文档到知识库""" + try: + # 检查文件类型 + allowed_extensions = [".pdf", ".docx", ".txt", ".md"] + file_extension = Path(file.filename).suffix.lower() + + if file_extension not in allowed_extensions: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"不支持的文件类型。支持的类型: {', '.join(allowed_extensions)}" + ) + + # 检查文件大小 + file_size = 0 + content = await file.read() + file_size = len(content) + + max_size = 10 * 1024 * 1024 # 10MB + if file_size > max_size: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="文件大小超过限制(10MB)" + ) + + # 获取用户ID + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 验证知识库存在 + knowledge_base = db.query(KnowledgeBase).filter( + KnowledgeBase.id == knowledge_base_id + ).first() + + if not knowledge_base: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="知识库不存在" + ) + + # 检查是否为系统知识库,系统知识库不允许任何用户上传文档 + if knowledge_base.is_system: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="系统知识库不允许上传文档,请使用您自己的知识库" + ) + + # 验证知识库属于当前用户(非系统知识库必须属于用户) + if knowledge_base.user_id != user.id: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="您没有权限向此知识库上传文档" + ) + + # 生成唯一文件名 + file_id = str(uuid.uuid4()) + filename = f"{file_id}{file_extension}" + + # 保存文件 + upload_dir = Path(settings.upload_dir) + upload_dir.mkdir(parents=True, exist_ok=True) + file_path = upload_dir / filename + + with open(file_path, "wb") as f: + f.write(content) + + # 创建文档记录 + document = Document( + user_id=user.id, + knowledge_base_id=knowledge_base_id, + filename=filename, + original_filename=file.filename, + file_path=str(file_path), + file_size=file_size, + file_type=file_extension, + title=title or Path(file.filename).stem, + description=description, + is_processed=False + ) + + db.add(document) + db.commit() + db.refresh(document) + + # 自动处理文档向量化 + try: + print(f"开始处理文档向量化: {document.filename} (ID: {document.id})") + document_service = DocumentService(db) + success = await document_service.process_document(document.id) + + if success: + print(f"文档向量化处理成功: {document.filename}") + message = "文档上传并处理成功" + else: + print(f"文档向量化处理失败: {document.filename}") + message = "文档上传成功,但向量化处理失败" + except Exception as e: + print(f"文档向量化处理异常: {document.filename}, 错误: {str(e)}") + import traceback + print(f"详细错误信息: {traceback.format_exc()}") + message = "文档上传成功,但向量化处理失败" + + return DocumentUploadResponse( + id=document.id, + filename=document.filename, + title=document.title, + message=message + ) + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"文档上传失败: {str(e)}" + ) + + +@router.get("/{knowledge_base_id}/documents", response_model=List[dict]) +async def get_knowledge_base_documents( + knowledge_base_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取知识库的文档列表""" + try: + # 获取用户ID + user = db.query(User).filter(User.username == current_user).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在" + ) + + # 验证知识库存在且属于用户 + knowledge_base = db.query(KnowledgeBase).filter( + KnowledgeBase.id == knowledge_base_id, + KnowledgeBase.user_id == user.id + ).first() + + if not knowledge_base: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="知识库不存在" + ) + + # 获取知识库的文档 + documents = db.query(Document).filter( + Document.knowledge_base_id == knowledge_base_id + ).all() + + result = [] + for doc in documents: + result.append({ + "id": doc.id, + "filename": doc.filename, + "title": doc.title, + "file_size": doc.file_size, + "file_type": doc.file_type, + "is_processed": doc.is_processed, + "is_public": doc.is_public, + "knowledge_base_id": doc.knowledge_base_id, + "created_at": doc.created_at.isoformat(), + "updated_at": doc.updated_at.isoformat() if doc.updated_at else doc.created_at.isoformat() + }) + + return result + + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取文档列表失败: {str(e)}" + ) + + +# ========== 知识库管理操作API(从knowledge.py合并) ========== + +from ..services.knowledge_base_service import KnowledgeBaseService +from ..services.file_watcher_service import get_file_watcher_service + + +class ScanResponse(BaseModel): + """扫描响应模型""" + success: bool + message: str + results: Optional[Dict[str, Any]] = None + + +class StatusResponse(BaseModel): + """状态响应模型""" + success: bool + status: Dict[str, Any] + + +class ReindexResponse(BaseModel): + """重新索引响应模型""" + success: bool + message: str + + +@router.post("/scan", response_model=ScanResponse) +async def scan_knowledge_base( + directory: Optional[str] = None, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """手动触发知识库扫描和入库""" + try: + kb_service = KnowledgeBaseService(db) + results = kb_service.scan_directory(directory) + + if results["success"]: + return ScanResponse( + success=True, + message="知识库扫描完成", + results=results + ) + else: + return ScanResponse( + success=False, + message="知识库扫描失败", + results=results + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"扫描知识库失败: {str(e)}" + ) + + +@router.get("/status", response_model=StatusResponse) +async def get_knowledge_base_status( + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """获取知识库状态""" + try: + kb_service = KnowledgeBaseService(db) + watcher_service = get_file_watcher_service() + + # 获取知识库状态 + kb_status = kb_service.get_knowledge_base_status() + + # 获取文件监控状态 + watcher_status = watcher_service.get_status() + + # 合并状态信息 + status_info = { + "knowledge_base": kb_status, + "file_watcher": watcher_status + } + + return StatusResponse( + success=True, + status=status_info + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取知识库状态失败: {str(e)}" + ) + + +@router.post("/documents/{document_id}/reindex", response_model=ReindexResponse) +async def reindex_document( + document_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """重新索引指定文档""" + try: + kb_service = KnowledgeBaseService(db) + result = kb_service.reindex_document(document_id) + + if result["success"]: + return ReindexResponse( + success=True, + message=result["message"] + ) + else: + return ReindexResponse( + success=False, + message=result["message"] + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"重新索引文档失败: {str(e)}" + ) + + +@router.delete("/documents/{document_id}", response_model=ReindexResponse) +async def delete_knowledge_base_document( + document_id: int, + current_user: str = Depends(get_current_user), + db: Session = Depends(get_db) +): + """删除知识库文档""" + try: + kb_service = KnowledgeBaseService(db) + result = kb_service.delete_document(document_id) + + if result["success"]: + return ReindexResponse( + success=True, + message=result["message"] + ) + else: + return ReindexResponse( + success=False, + message=result["message"] + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"删除文档失败: {str(e)}" + ) + + +@router.post("/watcher/start", response_model=ReindexResponse) +async def start_file_watcher( + current_user: str = Depends(get_current_user) +): + """启动文件监控服务""" + try: + watcher_service = get_file_watcher_service() + watcher_service.start() + + if watcher_service.is_active(): + return ReindexResponse( + success=True, + message="文件监控服务启动成功" + ) + else: + return ReindexResponse( + success=False, + message="文件监控服务启动失败" + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"启动文件监控服务失败: {str(e)}" + ) + + +@router.post("/watcher/stop", response_model=ReindexResponse) +async def stop_file_watcher( + current_user: str = Depends(get_current_user) +): + """停止文件监控服务""" + try: + watcher_service = get_file_watcher_service() + watcher_service.stop() + + return ReindexResponse( + success=True, + message="文件监控服务停止成功" + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"停止文件监控服务失败: {str(e)}" + ) + + +@router.get("/watcher/status", response_model=StatusResponse) +async def get_watcher_status( + current_user: str = Depends(get_current_user) +): + """获取文件监控服务状态""" + try: + watcher_service = get_file_watcher_service() + status_info = watcher_service.get_status() + + return StatusResponse( + success=True, + status=status_info + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取文件监控状态失败: {str(e)}" + ) \ No newline at end of file diff --git a/backend/src/core/__init__.py b/backend/src/core/__init__.py new file mode 100644 index 0000000..f1ddcff --- /dev/null +++ b/backend/src/core/__init__.py @@ -0,0 +1,7 @@ +# 核心配置模块 + + + + + + diff --git a/backend/src/core/config.py b/backend/src/core/config.py new file mode 100644 index 0000000..482dbea --- /dev/null +++ b/backend/src/core/config.py @@ -0,0 +1,161 @@ +""" +应用配置管理 +""" +import os +from typing import List, Optional +from pydantic import validator, field_validator, Field +from pydantic_settings import BaseSettings +from pathlib import Path + + +class Settings(BaseSettings): + """应用配置""" + + # 应用基础配置 + app_name: str = "国土空间规划课程智能体" + app_version: str = "0.1.0" + debug: bool = True + host: str = "127.0.0.1" + port: int = 8000 + + # 硅基流动API配置 + siliconflow_api_key: str + siliconflow_base_url: str = "https://api.siliconflow.cn/v1" + siliconflow_model: str = "deepseek-ai/DeepSeek-R1-0528-Qwen3-8B" + + # 数据库配置 + database_url: str = "sqlite:///../data/database/course_agent.db" + + # JWT配置 + secret_key: str + algorithm: str = "HS256" + access_token_expire_minutes: int = 30 + + # 向量数据库配置 + vector_store_path: str = os.getenv("VECTOR_STORE_PATH", "./vector_store") + embedding_model: str = "shibing624/text2vec-base-chinese" + + # CORS配置 + allowed_origins: List[str] = [ + "http://localhost:8001", + "http://127.0.0.1:8001" + ] + + # 文件上传配置 + upload_dir: str = os.getenv("UPLOAD_DIR", "./uploads") + max_file_size: int = 10485760 # 10MB + allowed_extensions: List[str] = [".pdf", ".docx", ".txt", ".md"] + + # 知识库配置 + knowledge_base_dir: str = os.getenv("KNOWLEDGE_BASE_DIR", "./data/knowledge_base") + enable_file_watcher: bool = True + + # 书籍配置 + book_dir: str = os.getenv("BOOK_DIR", "./data/book") # LaTeX书籍目录 + + # 图像生成配置 + generated_images_dir: str = os.getenv("GENERATED_IMAGES_DIR", "./generated_images") + image_generation_timeout: int = 120 # 图像生成超时时间(秒) + max_image_size: int = 10485760 # 最大图像文件大小(10MB) + + # 日志配置 + log_level: str = os.getenv("LOG_LEVEL", "INFO") + log_file: str = os.getenv("LOG_FILE", "./logs/app.log") + + # Hugging Face镜像配置 + hf_endpoint: Optional[str] = "https://hf-mirror.com" + + @field_validator("allowed_origins", mode="before") + @classmethod + def parse_cors_origins(cls, v): + if v is None: + return [] + if isinstance(v, str): + # 移除可能的引号和空格 + v = v.strip().strip('"').strip("'") + if not v: + return [] + # 按逗号分割并清理 + origins = [origin.strip().strip('"').strip("'") for origin in v.split(",") if origin.strip()] + return origins + if isinstance(v, list): + return v + return [] + + @field_validator("allowed_extensions", mode="before") + @classmethod + def parse_extensions(cls, v): + if isinstance(v, str): + # 尝试解析 JSON 格式 + try: + import json + parsed = json.loads(v) + if isinstance(parsed, list): + return parsed + except (json.JSONDecodeError, ValueError): + pass + # 如果不是 JSON,按逗号分割 + return [ext.strip() for ext in v.split(",")] + return v + + @field_validator("database_url", mode="before") + @classmethod + def validate_database_url(cls, v): + """验证数据库URL,支持SQLite和PostgreSQL""" + if not v: + # 默认使用SQLite + return "sqlite:///./course_agent.db" + + # 如果是PostgreSQL URL,确保包含必要的组件 + if v.startswith("postgresql://") or v.startswith("postgresql+psycopg://"): + # 检查是否包含必要的认证信息 + if "@" not in v: + raise ValueError("PostgreSQL URL必须包含认证信息") + + return v + + class Config: + env_file = os.path.join(os.path.dirname(__file__), "..", "..", "..", ".env") + env_file_encoding = "utf-8" + case_sensitive = False + extra = "ignore" + + +# 全局配置实例 +settings = Settings() + + +def get_settings() -> Settings: + """获取配置实例""" + return settings + + +def ensure_directories(): + """确保必要的目录存在""" + directories = [ + settings.vector_store_path, + settings.upload_dir, + settings.knowledge_base_dir, + settings.generated_images_dir, + os.path.dirname(settings.log_file), + ] + + for directory in directories: + Path(directory).mkdir(parents=True, exist_ok=True) + + +def is_postgresql_database() -> bool: + """检查是否使用PostgreSQL数据库""" + db_url = get_settings().database_url + return db_url.startswith("postgresql://") or db_url.startswith("postgresql+psycopg://") + + +def get_database_type() -> str: + """获取数据库类型""" + db_url = get_settings().database_url + if "sqlite" in db_url: + return "sqlite" + elif "postgresql" in db_url: + return "postgresql" + else: + return "unknown" \ No newline at end of file diff --git a/backend/src/core/database.py b/backend/src/core/database.py new file mode 100644 index 0000000..93e3aa8 --- /dev/null +++ b/backend/src/core/database.py @@ -0,0 +1,209 @@ +""" +数据库连接和会话管理 +""" +from sqlalchemy import create_engine, MetaData, text +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker, Session +from typing import Generator +import logging + +from .config import get_settings, is_postgresql_database + +logger = logging.getLogger(__name__) +settings = get_settings() + +# 创建数据库引擎 +def create_database_engine(): + """创建数据库引擎,根据数据库类型配置不同的参数(带重试机制)""" + import time + + db_url = settings.database_url + + # 重试机制:等待 DNS 解析就绪 + max_retries = 10 + retry_delay = 2 + + for attempt in range(max_retries): + try: + if is_postgresql_database(): + # PostgreSQL配置 + engine = create_engine( + db_url, + pool_size=20, + max_overflow=30, + pool_pre_ping=True, + pool_recycle=3600, + echo=settings.debug, + echo_pool=settings.debug, + connect_args={"connect_timeout": 10} # 连接超时 + ) + # 测试连接 + with engine.connect() as conn: + conn.execute(text("SELECT 1")) + logger.info("使用PostgreSQL数据库引擎") + else: + # SQLite配置 + engine = create_engine( + db_url, + connect_args={"check_same_thread": False}, + echo=settings.debug + ) + logger.info("使用SQLite数据库引擎") + + return engine + except Exception as e: + if attempt < max_retries - 1: + logger.warning(f"数据库引擎创建失败(尝试 {attempt + 1}/{max_retries}): {e}") + logger.info(f"等待 {retry_delay} 秒后重试...") + time.sleep(retry_delay) + else: + logger.error(f"数据库引擎创建失败,已达到最大重试次数: {e}") + raise + +# 延迟创建引擎(避免在导入时就连接数据库,等待 DNS 解析就绪) +_engine = None +_SessionLocal = None + +def get_engine(): + """获取数据库引擎(懒加载)""" + global _engine + if _engine is None: + _engine = create_database_engine() + return _engine + +def get_session_local(): + """获取会话工厂(懒加载)""" + global _SessionLocal + if _SessionLocal is None: + _SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=get_engine()) + return _SessionLocal + +# 为了向后兼容,提供这些变量(延迟初始化) +# 注意:这些变量在首次访问时会触发数据库连接 +# 使用类来模拟属性访问,延迟到实际使用时才连接 +class _LazyEngine: + def __getattr__(self, name): + return getattr(get_engine(), name) + def connect(self, *args, **kwargs): + return get_engine().connect(*args, **kwargs) + def execute(self, *args, **kwargs): + return get_engine().execute(*args, **kwargs) + +class _LazySessionLocal: + def __call__(self, *args, **kwargs): + return get_session_local()(*args, **kwargs) + +# 为了向后兼容,提供这些变量(延迟初始化) +engine = _LazyEngine() +SessionLocal = _LazySessionLocal() + +# 创建基础模型类 +Base = declarative_base() + +# 元数据 +metadata = MetaData() + + +def get_db() -> Generator[Session, None, None]: + """获取数据库会话""" + db = get_session_local()() + try: + yield db + finally: + db.close() + + +def create_tables(): + """创建数据库表(带重试机制,处理 DNS 解析延迟)""" + import time + + # 导入所有模型以确保它们被注册到 Base.metadata + from ..models import User, ChatSession, ChatMessage, Document, DocumentChunk, KnowledgeBase, CourseModule + from ..models.book_structure import Book, Chapter, Section, Subsection + from ..models.forum import ForumCategory, ForumPost, ForumReply + + # 重试机制:等待 DNS 解析和数据库就绪 + max_retries = 10 + retry_delay = 2 + + for attempt in range(max_retries): + try: + # 创建所有表 + engine = get_engine() + Base.metadata.create_all(bind=engine) + logger.info("数据库表创建完成") + return + except Exception as e: + if attempt < max_retries - 1: + logger.warning(f"数据库连接失败(尝试 {attempt + 1}/{max_retries}): {e}") + logger.info(f"等待 {retry_delay} 秒后重试...") + time.sleep(retry_delay) + else: + logger.error(f"数据库连接失败,已达到最大重试次数: {e}") + raise + + +def check_database_connection(): + """检查数据库连接""" + try: + with get_engine().connect() as conn: + if is_postgresql_database(): + conn.execute(text("SELECT 1")) + logger.info("PostgreSQL数据库连接正常") + else: + conn.execute(text("SELECT 1")) + logger.info("SQLite数据库连接正常") + return True + except Exception as e: + logger.error(f"数据库连接失败: {e}") + return False + + +def get_database_info(): + """获取数据库信息""" + db_type = "PostgreSQL" if is_postgresql_database() else "SQLite" + + try: + with get_engine().connect() as conn: + if is_postgresql_database(): + # PostgreSQL信息 + result = conn.execute(text("SELECT version()")) + version = result.scalar() + result = conn.execute(text("SELECT current_database()")) + db_name = result.scalar() + return { + "type": db_type, + "version": version, + "database": db_name, + "url": settings.database_url.split("@")[-1] if "@" in settings.database_url else settings.database_url + } + else: + # SQLite信息 + return { + "type": db_type, + "version": "SQLite", + "database": settings.database_url.split("/")[-1], + "url": settings.database_url + } + except Exception as e: + logger.error(f"获取数据库信息失败: {e}") + return { + "type": db_type, + "error": str(e) + } + + +def vacuum_database(): + """清理数据库(仅SQLite)""" + if not is_postgresql_database(): + try: + with get_engine().connect() as conn: + conn.execute(text("VACUUM")) + logger.info("SQLite数据库清理完成") + return True + except Exception as e: + logger.error(f"数据库清理失败: {e}") + return False + else: + logger.info("PostgreSQL不需要VACUUM操作") + return True \ No newline at end of file diff --git a/backend/src/core/security.py b/backend/src/core/security.py new file mode 100644 index 0000000..a13eed8 --- /dev/null +++ b/backend/src/core/security.py @@ -0,0 +1,84 @@ +""" +安全相关功能 +""" +from datetime import datetime, timedelta +from typing import Optional, Union +from jose import JWTError, jwt +from passlib.context import CryptContext +from fastapi import HTTPException, status, Depends +from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials +from pydantic import BaseModel + +from .config import get_settings + +settings = get_settings() + +# 密码加密上下文 +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + +# JWT Bearer认证 +security = HTTPBearer() + + +class Token(BaseModel): + """Token响应模型""" + access_token: str + token_type: str + + +class TokenData(BaseModel): + """Token数据模型""" + username: Optional[str] = None + + +def verify_password(plain_password: str, hashed_password: str) -> bool: + """验证密码""" + return pwd_context.verify(plain_password, hashed_password) + + +def get_password_hash(password: str) -> str: + """生成密码哈希""" + return pwd_context.hash(password) + + +def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: + """创建访问令牌""" + to_encode = data.copy() + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(minutes=settings.access_token_expire_minutes) + + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode(to_encode, settings.secret_key, algorithm=settings.algorithm) + return encoded_jwt + + +def verify_token(token: str) -> Optional[str]: + """验证令牌并返回用户名""" + try: + payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm]) + username: str = payload.get("sub") + if username is None: + return None + return username + except JWTError: + return None + + +async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)): + """获取当前用户""" + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": "Bearer"}, + ) + + try: + token = credentials.credentials + username = verify_token(token) + if username is None: + raise credentials_exception + return username + except JWTError: + raise credentials_exception diff --git a/backend/src/graph/__init__.py b/backend/src/graph/__init__.py new file mode 100644 index 0000000..129b987 --- /dev/null +++ b/backend/src/graph/__init__.py @@ -0,0 +1,7 @@ +# LangGraph工作流模块 + + + + + + diff --git a/backend/src/graph/nodes.py b/backend/src/graph/nodes.py new file mode 100644 index 0000000..0d03c26 --- /dev/null +++ b/backend/src/graph/nodes.py @@ -0,0 +1,212 @@ +""" +LangGraph节点定义 +""" +import json +import re +from typing import Dict, Any, List, TypedDict +from langchain.schema import HumanMessage, AIMessage, SystemMessage +from ..llm.siliconflow import get_llm_client +from ..rag.retrievers import KnowledgeBaseRetriever +from ..rag.vector_store import get_vector_store + + +def _parse_json_from_response(text: str) -> dict: + """从LLM响应中提取JSON,兼容markdown代码块包裹的情况""" + # 尝试提取 ```json ... ``` 中的内容 + match = re.search(r"```(?:json)?\s*([\s\S]*?)```", text) + if match: + text = match.group(1).strip() + return json.loads(text) + + +class GraphState(TypedDict): + """图状态定义""" + messages: List[Dict[str, str]] + current_question: str + retrieved_docs: List[Dict[str, Any]] + answer: str + sources: List[Dict[str, Any]] + metadata: Dict[str, Any] + + +def analyze_question_node(state: GraphState) -> GraphState: + """问题分析节点""" + try: + llm = get_llm_client() + + # 构建分析提示 + system_prompt = """你是一个专业的国土空间规划知识问答助手。请分析用户的问题,确定问题的类型和需要检索的知识领域。 + +问题类型包括: +1. 概念解释类:询问基本概念、定义 +2. 方法技术类:询问规划方法、技术手段 +3. 案例分析类:询问具体案例、实践应用 +4. 政策法规类:询问相关政策、法规条文 +5. 技术标准类:询问技术标准、规范要求 + +请以JSON格式返回分析结果: +{ + "question_type": "问题类型", + "keywords": ["关键词1", "关键词2"], + "domain": "知识领域", + "intent": "用户意图" +}""" + + messages = [ + SystemMessage(content=system_prompt), + HumanMessage(content=f"请分析这个问题:{state['current_question']}") + ] + + response = llm.chat(messages) + + # 解析LLM返回的JSON + analysis = _parse_json_from_response(response) + + new_state = state.copy() + new_state["metadata"] = {**state["metadata"], "analysis": { + "question_type": analysis.get("question_type", "通用"), + "keywords": analysis.get("keywords", []), + "domain": analysis.get("domain", "国土空间规划"), + "intent": analysis.get("intent", "获取知识") + }} + + return new_state + + except Exception as e: + print(f"问题分析失败: {str(e)}") + new_state = state.copy() + new_state["metadata"] = {**state["metadata"], "analysis": { + "question_type": "通用", + "keywords": [], + "domain": "国土空间规划", + "intent": "获取知识" + }} + + return new_state + + +def retrieve_knowledge_node(state: GraphState) -> GraphState: + """知识检索节点""" + try: + # 获取知识库过滤条件 + knowledge_base_ids = state.get("metadata", {}).get("knowledge_base_ids") + + # 使用LangChain兼容的检索器 + vector_store = get_vector_store() + retriever = KnowledgeBaseRetriever( + vectorstore=vector_store.vectorstore, + knowledge_base_ids=knowledge_base_ids, + search_type="similarity", + search_kwargs={"k": 5}, + score_threshold=0.4 # 转换为相似度阈值 + ) + + # 执行检索(LangChain格式) + from langchain_core.callbacks.manager import CallbackManagerForRetrieverRun + from langchain_core.callbacks import CallbackManager + + class DummyRunManager: + pass + + run_manager = DummyRunManager() + langchain_docs = retriever._get_relevant_documents( + state["current_question"], + run_manager=run_manager + ) + + # 转换为旧格式 + retrieved_docs = [] + sources = [] + for doc in langchain_docs: + retrieved_docs.append({ + "content": doc.page_content, + "metadata": doc.metadata, + "distance": 0.0 # LangChain不直接提供distance + }) + sources.append({ + "title": doc.metadata.get("title", "未知标题"), + "filename": doc.metadata.get("filename", "未知文件"), + "page": doc.metadata.get("page", 0), + "score": 0.8, # 默认分数 + "preview": doc.page_content[:200] + "..." if len(doc.page_content) > 200 else doc.page_content + }) + + new_state = state.copy() + new_state["retrieved_docs"] = retrieved_docs + new_state["sources"] = sources + + return new_state + + except Exception as e: + print(f"知识检索失败: {str(e)}") + import traceback + print(traceback.format_exc()) + new_state = state.copy() + new_state["retrieved_docs"] = [] + new_state["sources"] = [] + return new_state + + +def generate_answer_node(state: GraphState) -> GraphState: + """答案生成节点""" + try: + llm = get_llm_client() + + # 构建上下文 + context = "" + if state["retrieved_docs"]: + context_parts = [doc.get("content", "") for doc in state["retrieved_docs"]] + context = "\n\n".join(context_parts) + + # 构建系统提示 + system_prompt = """你是一个专业的国土空间规划知识问答助手。请基于提供的上下文信息回答用户的问题。 + +要求: +1. 回答要准确、专业、详细 +2. 如果上下文中没有相关信息,请诚实说明 +3. 回答要结构清晰,逻辑性强 +4. 适当引用相关概念和术语 +5. 回答长度控制在500-1000字之间 + +上下文信息: +{context}""" + + # 构建消息 + messages = [ + SystemMessage(content=system_prompt.format(context=context)), + HumanMessage(content=f"问题:{state['current_question']}") + ] + + # 生成回答 + answer = llm.chat(messages) + + new_state = state.copy() + new_state["answer"] = answer + + return new_state + + except Exception as e: + print(f"答案生成失败: {str(e)}") + new_state = state.copy() + new_state["answer"] = "抱歉,我无法生成合适的回答。请稍后重试。" + return new_state + + +def format_response_node(state: GraphState) -> GraphState: + """响应格式化节点""" + try: + # 格式化最终响应 + response = { + "answer": state["answer"], + "sources": state["sources"], + "metadata": state["metadata"] + } + + new_state = state.copy() + new_state["metadata"] = {**state["metadata"], "formatted_response": response} + + return new_state + + except Exception as e: + print(f"响应格式化失败: {str(e)}") + return state diff --git a/backend/src/graph/qa_graph.py b/backend/src/graph/qa_graph.py new file mode 100644 index 0000000..7a8d285 --- /dev/null +++ b/backend/src/graph/qa_graph.py @@ -0,0 +1,74 @@ +""" +问答LangGraph工作流 +""" +from typing import Dict, Any, Optional, List +from langgraph.graph import StateGraph, END +from .nodes import GraphState, analyze_question_node, retrieve_knowledge_node, generate_answer_node, format_response_node + + +def create_qa_graph() -> StateGraph: + """创建问答图""" + # 创建状态图 + builder = StateGraph(GraphState) + + # 添加节点 + builder.add_node("analyze", analyze_question_node) + builder.add_node("retrieve", retrieve_knowledge_node) + builder.add_node("generate", generate_answer_node) + builder.add_node("format", format_response_node) + + # 添加边 + builder.add_edge("analyze", "retrieve") + builder.add_edge("retrieve", "generate") + builder.add_edge("generate", "format") + builder.add_edge("format", END) + + # 设置入口点 + builder.set_entry_point("analyze") + + return builder + + +def run_qa_workflow(question: str, knowledge_base_ids: Optional[List[int]] = None) -> Dict[str, Any]: + """运行问答工作流""" + try: + # 创建图 + graph_builder = create_qa_graph() + graph = graph_builder.compile() + + # 初始化状态 + initial_state: GraphState = { + "messages": [], + "current_question": question, + "retrieved_docs": [], + "answer": "", + "sources": [], + "metadata": {"knowledge_base_ids": knowledge_base_ids} + } + + # 运行图 + result = graph.invoke(initial_state) + + # 返回结果 + return { + "answer": result["answer"], + "sources": result["sources"], + "metadata": result["metadata"] + } + + except Exception as e: + print(f"问答工作流执行失败: {str(e)}") + return { + "answer": "抱歉,处理您的问题时出现了错误。请稍后重试。", + "sources": [], + "metadata": {"error": str(e)} + } + + +# 全局图实例 +qa_graph = create_qa_graph().compile() + + +def get_qa_graph(): + """获取问答图实例""" + return qa_graph diff --git a/backend/src/llm/__init__.py b/backend/src/llm/__init__.py new file mode 100644 index 0000000..cf4b67b --- /dev/null +++ b/backend/src/llm/__init__.py @@ -0,0 +1,7 @@ +# 大模型集成模块 + + + + + + diff --git a/backend/src/llm/siliconflow.py b/backend/src/llm/siliconflow.py new file mode 100644 index 0000000..764fede --- /dev/null +++ b/backend/src/llm/siliconflow.py @@ -0,0 +1,108 @@ +""" +硅基流动大模型API集成 +""" +import os +from typing import List, Dict, Any, Optional, AsyncGenerator +from langchain_openai import ChatOpenAI +from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, SystemMessage +from langchain_core.callbacks.base import BaseCallbackHandler +from langchain_core.callbacks.streaming_stdout import StreamingStdOutCallbackHandler + +from ..core.config import get_settings + +settings = get_settings() + + +class SiliconFlowLLM: + """硅基流动大模型客户端""" + + def __init__(self, model: Optional[str] = None): + """初始化LLM客户端""" + # 设置环境变量 + os.environ["OPENAI_API_KEY"] = settings.siliconflow_api_key + os.environ["OPENAI_API_BASE"] = settings.siliconflow_base_url + + # 使用传入的模型或默认模型 + self.model_name = model or settings.siliconflow_model + print(f"[DEBUG-LLM] 初始化LLM客户端,使用模型: {self.model_name} (传入参数: {model}, 默认配置: {settings.siliconflow_model})") + + # 创建LLM实例 + self.llm = ChatOpenAI( + model=self.model_name, + api_key=settings.siliconflow_api_key, + base_url=settings.siliconflow_base_url, + temperature=0.7, + max_tokens=2000, + streaming=True + ) + # 检查实际使用的模型名称 + actual_model = getattr(self.llm, 'model_name', None) or getattr(self.llm, 'model', None) or str(self.llm) + print(f"[DEBUG-LLM] ChatOpenAI实例创建完成,实际模型: {actual_model}") + + def chat(self, messages: List[BaseMessage], **kwargs) -> str: + """同步聊天""" + try: + response = self.llm.invoke(messages, **kwargs) + return response.content + except Exception as e: + raise Exception(f"LLM调用失败: {str(e)}") + + async def achat(self, messages: List[BaseMessage], **kwargs) -> str: + """异步聊天""" + try: + response = await self.llm.ainvoke(messages, **kwargs) + return response.content + except Exception as e: + raise Exception(f"LLM异步调用失败: {str(e)}") + + async def stream_chat(self, messages: List[BaseMessage], **kwargs) -> AsyncGenerator[str, None]: + """流式聊天""" + try: + async for chunk in self.llm.astream(messages, **kwargs): + if hasattr(chunk, 'content') and chunk.content: + yield chunk.content + except Exception as e: + raise Exception(f"LLM流式调用失败: {str(e)}") + + def create_messages( + self, + user_message: str, + system_prompt: Optional[str] = None, + chat_history: Optional[List[Dict[str, str]]] = None + ) -> List[BaseMessage]: + """创建消息列表""" + messages = [] + + # 添加系统提示 + if system_prompt: + messages.append(SystemMessage(content=system_prompt)) + + # 添加聊天历史 + if chat_history: + for msg in chat_history: + if msg["role"] == "user": + messages.append(HumanMessage(content=msg["content"])) + elif msg["role"] == "assistant": + messages.append(AIMessage(content=msg["content"])) + + # 添加当前用户消息 + messages.append(HumanMessage(content=user_message)) + + return messages + + +# 全局LLM实例(使用默认模型) +llm_client = SiliconFlowLLM() + + +def get_llm_client(model: Optional[str] = None) -> SiliconFlowLLM: + """获取LLM客户端实例 + + Args: + model: 可选的模型名称,如果提供则创建新的实例,否则返回默认实例 + """ + if model is None: + return llm_client + else: + # 为指定模型创建新实例 + return SiliconFlowLLM(model=model) diff --git a/backend/src/migrations/migrate_orphaned_documents.py b/backend/src/migrations/migrate_orphaned_documents.py new file mode 100644 index 0000000..9c83d52 --- /dev/null +++ b/backend/src/migrations/migrate_orphaned_documents.py @@ -0,0 +1,55 @@ +""" +迁移孤立文档到默认知识库 +""" +from sqlalchemy.orm import Session +from ..core.database import get_db +from ..models.user import User +from ..models.knowledge_base import KnowledgeBase +from ..models.document import Document + + +def migrate_orphaned_documents(): + """将没有知识库的文档迁移到用户的默认知识库""" + db = next(get_db()) + + try: + # 获取所有用户 + users = db.query(User).all() + + for user in users: + # 检查用户是否有孤立文档 + orphaned_docs = db.query(Document).filter( + Document.user_id == user.id, + Document.knowledge_base_id.is_(None) + ).all() + + if orphaned_docs: + # 创建默认知识库 + default_kb = KnowledgeBase( + name="默认知识库", + description="系统自动创建的默认知识库,包含之前上传的文档", + user_id=user.id, + is_system=True + ) + db.add(default_kb) + db.commit() + db.refresh(default_kb) + + # 将孤立文档迁移到默认知识库 + for doc in orphaned_docs: + doc.knowledge_base_id = default_kb.id + + db.commit() + print(f"用户 {user.username} 的 {len(orphaned_docs)} 个文档已迁移到默认知识库") + + print("孤立文档迁移完成") + + except Exception as e: + print(f"迁移失败: {str(e)}") + db.rollback() + finally: + db.close() + + +if __name__ == "__main__": + migrate_orphaned_documents() diff --git a/backend/src/models/__init__.py b/backend/src/models/__init__.py new file mode 100644 index 0000000..b8701a7 --- /dev/null +++ b/backend/src/models/__init__.py @@ -0,0 +1,29 @@ +# 数据模型模块 +# 导入所有模型以确保它们被注册到 Base.metadata +from .user import User +from .chat import ChatSession, ChatMessage +from .document import Document, DocumentChunk +from .knowledge_base import KnowledgeBase +from .course_content import CourseModule +from .book_structure import Book, Chapter, Section, Subsection +from .forum import ForumCategory, ForumPost, ForumReply +from .generated_image import GeneratedImageRecord + +# 确保所有模型都被导入 +__all__ = [ + "User", + "ChatSession", + "ChatMessage", + "Document", + "DocumentChunk", + "KnowledgeBase", + "CourseModule", + "Book", + "Chapter", + "Section", + "Subsection", + "ForumCategory", + "ForumPost", + "ForumReply", + "GeneratedImageRecord", +] diff --git a/backend/src/models/book_structure.py b/backend/src/models/book_structure.py new file mode 100644 index 0000000..c904575 --- /dev/null +++ b/backend/src/models/book_structure.py @@ -0,0 +1,104 @@ +""" +书籍结构数据模型 +""" +from sqlalchemy import Column, Integer, String, DateTime, Text, ForeignKey +from sqlalchemy.sql import func +from sqlalchemy.orm import relationship + +from ..core.database import Base + + +class Book(Base): + """书籍模型""" + __tablename__ = "books" + + id = Column(Integer, primary_key=True, index=True) + title = Column(String(200), nullable=False) + description = Column(Text, nullable=True) + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + # 关联关系 + chapters = relationship("Chapter", back_populates="book", cascade="all, delete-orphan", order_by="Chapter.display_order") + + def __repr__(self): + return f"" + + +class Chapter(Base): + """章节模型""" + __tablename__ = "chapters" + + id = Column(Integer, primary_key=True, index=True) + book_id = Column(Integer, ForeignKey("books.id", ondelete="CASCADE"), nullable=False) + chapter_number = Column(Integer, nullable=False) # 章节编号(1, 2, 3...) + title = Column(String(500), nullable=False) + display_order = Column(Integer, nullable=False, default=0) + + # LaTeX文件信息(用于动态读取内容) + file_path = Column(String(500), nullable=False) # 章节文件路径 + start_line = Column(Integer, nullable=False) # 起始行号 + end_line = Column(Integer, nullable=False) # 结束行号 + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + # 关联关系 + book = relationship("Book", back_populates="chapters") + sections = relationship("Section", back_populates="chapter", cascade="all, delete-orphan", order_by="Section.display_order") + + def __repr__(self): + return f"" + + +class Section(Base): + """节模型(对应LaTeX的\section)""" + __tablename__ = "sections" + + id = Column(Integer, primary_key=True, index=True) + chapter_id = Column(Integer, ForeignKey("chapters.id", ondelete="CASCADE"), nullable=False) + section_number = Column(Integer, nullable=False) # 节编号 + title = Column(String(500), nullable=False) + display_order = Column(Integer, nullable=False, default=0) + + # LaTeX文件信息(用于动态读取内容) + file_path = Column(String(500), nullable=False) # 章节文件路径 + start_line = Column(Integer, nullable=False) # 起始行号 + end_line = Column(Integer, nullable=False) # 结束行号 + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + # 关联关系 + chapter = relationship("Chapter", back_populates="sections") + subsections = relationship("Subsection", back_populates="section", cascade="all, delete-orphan", order_by="Subsection.display_order") + + def __repr__(self): + return f"" + + +class Subsection(Base): + """小节模型(对应LaTeX的\subsection,作为知识点)""" + __tablename__ = "subsections" + + id = Column(Integer, primary_key=True, index=True) + section_id = Column(Integer, ForeignKey("sections.id", ondelete="CASCADE"), nullable=False) + subsection_number = Column(Integer, nullable=False) # 小节编号 + title = Column(String(500), nullable=False) + display_order = Column(Integer, nullable=False, default=0) + + # LaTeX文件信息(用于动态读取内容,包含subsubsection的内容) + file_path = Column(String(500), nullable=False) # 章节文件路径 + start_line = Column(Integer, nullable=False) # 起始行号(包含subsection及其下所有subsubsection) + end_line = Column(Integer, nullable=False) # 结束行号 + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + # 关联关系 + section = relationship("Section", back_populates="subsections") + + def __repr__(self): + return f"" + diff --git a/backend/src/models/chat.py b/backend/src/models/chat.py new file mode 100644 index 0000000..208e93b --- /dev/null +++ b/backend/src/models/chat.py @@ -0,0 +1,49 @@ +""" +聊天相关数据模型 +""" +from sqlalchemy import Column, Integer, String, DateTime, Text, ForeignKey, Boolean +from sqlalchemy.sql import func +from sqlalchemy.orm import relationship + +from ..core.database import Base + + +class ChatSession(Base): + """聊天会话模型""" + __tablename__ = "chat_sessions" + + id = Column(Integer, primary_key=True, index=True) + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) + title = Column(String(200), nullable=True) + is_active = Column(Boolean, default=True) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) + + # 关联关系 + user = relationship("User", back_populates="chat_sessions") + messages = relationship("ChatMessage", back_populates="session", cascade="all, delete-orphan") + + def __repr__(self): + return f"" + + +class ChatMessage(Base): + """聊天消息模型""" + __tablename__ = "chat_messages" + + id = Column(Integer, primary_key=True, index=True) + session_id = Column(Integer, ForeignKey("chat_sessions.id"), nullable=False) + role = Column(String(20), nullable=False) # user, assistant, system + content = Column(Text, nullable=False) + message_metadata = Column(Text, nullable=True) # JSON格式的元数据 + feedback = Column(String(20), nullable=True) # like, dislike + edited = Column(Boolean, default=False) # 是否被编辑过 + regenerated_from = Column(Integer, nullable=True) # 从哪条消息重新生成 + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + # 关联关系 + session = relationship("ChatSession", back_populates="messages") + + def __repr__(self): + return f"" diff --git a/backend/src/models/course_content.py b/backend/src/models/course_content.py new file mode 100644 index 0000000..cef64d7 --- /dev/null +++ b/backend/src/models/course_content.py @@ -0,0 +1,40 @@ +""" +课程内容数据模型 +""" +from sqlalchemy import Column, Integer, String, DateTime, Text +from sqlalchemy.sql import func +import json + +from ..core.database import Base + + +class CourseModule(Base): + """课程模块模型""" + __tablename__ = "course_modules" + + id = Column(Integer, primary_key=True, index=True) + module_name = Column(String(200), nullable=False) + core_knowledge_points = Column(Text, nullable=False) + digitalization_necessity = Column(Text, nullable=False) + expanded_knowledge_points = Column(Text, nullable=False) # JSON格式存储数组 + display_order = Column(Integer, nullable=False, default=0) + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + def get_expanded_knowledge_points(self) -> list[str]: + """获取展开知识点列表""" + if not self.expanded_knowledge_points: + return [] + try: + return json.loads(self.expanded_knowledge_points) + except (json.JSONDecodeError, TypeError): + return [] + + def set_expanded_knowledge_points(self, points: list[str]): + """设置展开知识点列表""" + self.expanded_knowledge_points = json.dumps(points, ensure_ascii=False) + + def __repr__(self): + return f"" + diff --git a/backend/src/models/document.py b/backend/src/models/document.py new file mode 100644 index 0000000..a80dceb --- /dev/null +++ b/backend/src/models/document.py @@ -0,0 +1,62 @@ +""" +文档数据模型 +""" +from sqlalchemy import Column, Integer, String, DateTime, Text, ForeignKey, Boolean, Float +from sqlalchemy.sql import func +from sqlalchemy.orm import relationship + +from ..core.database import Base + + +class Document(Base): + """文档模型""" + __tablename__ = "documents" + + id = Column(Integer, primary_key=True, index=True) + user_id = Column(Integer, ForeignKey("users.id"), nullable=True) # None表示系统文档 + knowledge_base_id = Column(Integer, ForeignKey("knowledge_bases.id"), nullable=True) # 所属知识库 + filename = Column(String(255), nullable=False) + original_filename = Column(String(255), nullable=False) + file_path = Column(String(500), nullable=False) + file_size = Column(Integer, nullable=False) + file_type = Column(String(50), nullable=False) + title = Column(String(200), nullable=True) + description = Column(Text, nullable=True) + is_processed = Column(Boolean, default=False) + is_public = Column(Boolean, default=False) + + # 新增字段:知识库管理 + source_type = Column(String(50), default="upload") # upload, knowledge_base + last_modified = Column(DateTime(timezone=True), nullable=True) # 文件最后修改时间 + file_hash = Column(String(64), nullable=True) # 文件内容哈希 + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + # 关联关系 + user = relationship("User", back_populates="documents") + knowledge_base = relationship("KnowledgeBase", back_populates="documents") + chunks = relationship("DocumentChunk", back_populates="document", cascade="all, delete-orphan") + + def __repr__(self): + return f"" + + +class DocumentChunk(Base): + """文档分块模型""" + __tablename__ = "document_chunks" + + id = Column(Integer, primary_key=True, index=True) + document_id = Column(Integer, ForeignKey("documents.id"), nullable=False) + chunk_index = Column(Integer, nullable=False) + content = Column(Text, nullable=False) + content_hash = Column(String(64), nullable=False) # 内容哈希 + embedding_vector = Column(Text, nullable=True) # 向量嵌入(JSON格式) + chunk_metadata = Column(Text, nullable=True) # 分块元数据(JSON格式) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + + # 关联关系 + document = relationship("Document", back_populates="chunks") + + def __repr__(self): + return f"" diff --git a/backend/src/models/forum.py b/backend/src/models/forum.py new file mode 100644 index 0000000..6e96799 --- /dev/null +++ b/backend/src/models/forum.py @@ -0,0 +1,50 @@ +""" +论坛相关模型 +""" +from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey +from sqlalchemy.sql import func +from sqlalchemy.orm import relationship + +from ..core.database import Base + + +class ForumCategory(Base): + __tablename__ = "forum_categories" + + id = Column(Integer, primary_key=True, index=True) + slug = Column(String(50), unique=True, nullable=False, index=True) + name = Column(String(100), nullable=False) + description = Column(String(255), nullable=True) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + + posts = relationship("ForumPost", back_populates="category", cascade="all, delete-orphan") + + +class ForumPost(Base): + __tablename__ = "forum_posts" + + id = Column(Integer, primary_key=True, index=True) + category_id = Column(Integer, ForeignKey("forum_categories.id"), nullable=False) + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) + title = Column(String(200), nullable=False) + content = Column(Text, nullable=False) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + category = relationship("ForumCategory", back_populates="posts") + replies = relationship("ForumReply", back_populates="post", cascade="all, delete-orphan") + author = relationship("User", back_populates="forum_posts") + + +class ForumReply(Base): + __tablename__ = "forum_replies" + + id = Column(Integer, primary_key=True, index=True) + post_id = Column(Integer, ForeignKey("forum_posts.id"), nullable=False) + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) + content = Column(Text, nullable=False) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + + post = relationship("ForumPost", back_populates="replies") + author = relationship("User", back_populates="forum_replies") + diff --git a/backend/src/models/generated_image.py b/backend/src/models/generated_image.py new file mode 100644 index 0000000..cc0ae74 --- /dev/null +++ b/backend/src/models/generated_image.py @@ -0,0 +1,34 @@ +""" +图像生成记录数据模型 +""" +from sqlalchemy import Column, Integer, String, DateTime, Text, ForeignKey +from sqlalchemy.sql import func +from sqlalchemy.orm import relationship + +from ..core.database import Base + + +class GeneratedImageRecord(Base): + """图像生成记录""" + __tablename__ = "generated_images" + + id = Column(Integer, primary_key=True, index=True) + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) + image_id = Column(String(36), nullable=False, unique=True) # UUID + image_type = Column(String(30), nullable=False) # text_to_image, image_edit, variation, style_transfer, optimize, outpaint + prompt = Column(Text, nullable=True) + model = Column(String(50), nullable=True) + style = Column(String(50), nullable=True) + size = Column(String(20), nullable=True) + template = Column(String(50), nullable=True) + image_url = Column(String(500), nullable=False) + original_filename = Column(String(255), nullable=True) # 图生图的原始文件名 + mode = Column(String(50), nullable=True) # 编辑模式 + strength = Column(String(10), nullable=True) + generation_meta = Column(Text, nullable=True) # JSON格式的额外元数据 + created_at = Column(DateTime(timezone=True), server_default=func.now()) + + user = relationship("User", back_populates="generated_images") + + def __repr__(self): + return f"" diff --git a/backend/src/models/image_models.py b/backend/src/models/image_models.py new file mode 100644 index 0000000..9afac84 --- /dev/null +++ b/backend/src/models/image_models.py @@ -0,0 +1,107 @@ +""" +图像生成相关的 Pydantic 模型 +""" + +from typing import List, Optional, Dict, Any +from pydantic import BaseModel, Field + + +class TextToImageRequest(BaseModel): + """文生图请求模型""" + prompt: str = Field(..., description="图像描述提示词", min_length=1, max_length=1000) + model: str = Field(default="kolors", description="使用的模型", pattern="^(kolors|qwen)$") + template: str = Field(default="custom", description="提示词模板") + style: str = Field(default="realistic", description="图像风格") + size: str = Field(default="1024x1024", description="图像尺寸") + num_images: int = Field(default=1, description="生成图像数量", ge=1, le=4) + + +class ImageEditRequest(BaseModel): + """图像编辑请求模型""" + prompt: str = Field(..., description="编辑描述", min_length=1, max_length=500) + mode: str = Field(default="optimize", description="编辑模式") + strength: float = Field(default=0.8, description="编辑强度", ge=0.0, le=1.0) + + +class ImageVariationRequest(BaseModel): + """图像变体生成请求模型""" + num_variations: int = Field(default=3, description="变体数量", ge=1, le=6) + + +class GeneratedImage(BaseModel): + """生成的图像模型""" + id: str = Field(..., description="图像唯一ID") + url: str = Field(..., description="图像访问URL") + prompt: str = Field(..., description="使用的提示词") + model: str = Field(..., description="使用的模型") + metadata: Dict[str, Any] = Field(default_factory=dict, description="元数据") + + +class ImageEditResult(BaseModel): + """图像编辑结果模型""" + id: str = Field(..., description="编辑后图像ID") + url: str = Field(..., description="图像访问URL") + original_filename: Optional[str] = Field(None, description="原始文件名") + edit_prompt: str = Field(..., description="编辑提示词") + mode: str = Field(..., description="编辑模式") + metadata: Dict[str, Any] = Field(default_factory=dict, description="元数据") + + +class ImageVariationResult(BaseModel): + """图像变体结果模型""" + id: str = Field(..., description="变体图像ID") + url: str = Field(..., description="图像访问URL") + type: str = Field(default="variation", description="图像类型") + metadata: Dict[str, Any] = Field(default_factory=dict, description="元数据") + + +class TextToImageResponse(BaseModel): + """文生图响应模型""" + images: List[GeneratedImage] = Field(..., description="生成的图像列表") + total: int = Field(..., description="图像总数") + + +class ImageEditResponse(BaseModel): + """图像编辑响应模型""" + result: ImageEditResult = Field(..., description="编辑结果") + + +class ImageVariationResponse(BaseModel): + """图像变体响应模型""" + variations: List[ImageVariationResult] = Field(..., description="变体图像列表") + total: int = Field(..., description="变体总数") + + +class ModelInfo(BaseModel): + """模型信息""" + id: str = Field(..., description="模型ID") + name: str = Field(..., description="模型名称") + description: str = Field(..., description="模型描述") + + +class TemplateInfo(BaseModel): + """模板信息""" + id: str = Field(..., description="模板ID") + name: str = Field(..., description="模板名称") + description: str = Field(..., description="模板描述") + + +class StyleInfo(BaseModel): + """风格信息""" + id: str = Field(..., description="风格ID") + name: str = Field(..., description="风格名称") + description: str = Field(..., description="风格描述") + + +class SizeInfo(BaseModel): + """尺寸信息""" + id: str = Field(..., description="尺寸ID") + name: str = Field(..., description="尺寸名称") + description: str = Field(..., description="尺寸描述") + + +class EditModeInfo(BaseModel): + """编辑模式信息""" + id: str = Field(..., description="模式ID") + name: str = Field(..., description="模式名称") + description: str = Field(..., description="模式描述") diff --git a/backend/src/models/knowledge_base.py b/backend/src/models/knowledge_base.py new file mode 100644 index 0000000..17c011a --- /dev/null +++ b/backend/src/models/knowledge_base.py @@ -0,0 +1,29 @@ +""" +知识库数据模型 +""" +from sqlalchemy import Column, Integer, String, DateTime, Text, ForeignKey, Boolean +from sqlalchemy.sql import func +from sqlalchemy.orm import relationship + +from ..core.database import Base + + +class KnowledgeBase(Base): + """知识库模型""" + __tablename__ = "knowledge_bases" + + id = Column(Integer, primary_key=True, index=True) + name = Column(String(200), nullable=False) + description = Column(Text, nullable=True) + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) + is_system = Column(Boolean, default=False) # 是否为系统知识库 + + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + + # 关联关系 + user = relationship("User", back_populates="knowledge_bases") + documents = relationship("Document", back_populates="knowledge_base", cascade="all, delete-orphan") + + def __repr__(self): + return f"" diff --git a/backend/src/models/user.py b/backend/src/models/user.py new file mode 100644 index 0000000..9b98e7c --- /dev/null +++ b/backend/src/models/user.py @@ -0,0 +1,41 @@ +""" +用户数据模型 +""" +from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text +from sqlalchemy.sql import func +from sqlalchemy.orm import relationship + +from ..core.database import Base + + +class User(Base): + """用户模型""" + __tablename__ = "users" + + id = Column(Integer, primary_key=True, index=True) + username = Column(String(50), unique=True, index=True, nullable=False) + email = Column(String(100), unique=True, index=True, nullable=False) + hashed_password = Column(String(255), nullable=False) + full_name = Column(String(100), nullable=True) + is_active = Column(Boolean, default=True) + is_superuser = Column(Boolean, default=False) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + last_login = Column(DateTime(timezone=True), nullable=True) + + # 关联关系 + chat_sessions = relationship("ChatSession", back_populates="user") + documents = relationship("Document", back_populates="user") + knowledge_bases = relationship("KnowledgeBase", back_populates="user") + forum_posts = relationship("ForumPost", back_populates="author") + forum_replies = relationship("ForumReply", back_populates="author") + generated_images = relationship("GeneratedImageRecord", back_populates="user") + + def __repr__(self): + return f"" + + + + + + diff --git a/backend/src/rag/__init__.py b/backend/src/rag/__init__.py new file mode 100644 index 0000000..9420649 --- /dev/null +++ b/backend/src/rag/__init__.py @@ -0,0 +1,7 @@ +# RAG系统模块 + + + + + + diff --git a/backend/src/rag/chains.py b/backend/src/rag/chains.py new file mode 100644 index 0000000..a889027 --- /dev/null +++ b/backend/src/rag/chains.py @@ -0,0 +1,209 @@ +""" +RAG检索链(LangChain 1.0) +""" +from typing import List, Optional, Dict, Any +from langchain_core.runnables import RunnablePassthrough, RunnableLambda +from langchain_core.prompts import ChatPromptTemplate +from langchain_core.output_parsers import StrOutputParser + +from .prompts import create_rag_prompt +from .retrievers import KnowledgeBaseRetriever +from .vector_store import get_vector_store +from ..llm.siliconflow import get_llm_client + +class RAGChain: + """RAG问答链(LangChain 1.0标准API)""" + + def __init__( + self, + knowledge_base_ids: Optional[List[int]] = None, + search_type: str = "similarity", + k: int = 5, + score_threshold: float = 0.1, + model: Optional[str] = None + ): + """初始化RAG链 + + Args: + knowledge_base_ids: 知识库ID列表 + search_type: 搜索类型 + k: 返回文档数量 + score_threshold: 相似度阈值 + model: 可选的模型名称,如 deepseek-ai/DeepSeek-V3, Qwen/QwQ-32B + """ + print(f"[DEBUG-RAGChain] 初始化,knowledge_base_ids: {knowledge_base_ids}, model: {model}") + self.llm = get_llm_client(model=model).llm + self.vector_store = get_vector_store() + self.knowledge_base_ids = knowledge_base_ids + + # 创建自定义检索器 + self.retriever = KnowledgeBaseRetriever( + vectorstore=self.vector_store.vectorstore, + knowledge_base_ids=knowledge_base_ids, + search_type=search_type, + search_kwargs={"k": k}, + score_threshold=score_threshold + ) + print(f"[DEBUG-RAGChain] 检索器创建完成,knowledge_base_ids: {self.retriever.knowledge_base_ids}") + + # 创建Prompt + self.prompt = create_rag_prompt() + + # 创建RAG链 + self.chain = self._create_chain() + + def _create_chain(self): + """创建检索链(LangChain 1.0 Runnable API)""" + # 使用LangChain 1.0的runnable API构建RAG链 + def format_docs(docs): + """格式化文档""" + return "\n\n".join(doc.page_content for doc in docs) + + # 构建RAG链 - 只检索一次,返回完整结果 + def rag_with_sources(input_data): + """RAG处理函数,只检索一次""" + question = input_data + # 只检索一次 + docs = self.retriever.invoke(question) + context = format_docs(docs) + + # 生成答案 + messages = self.prompt.invoke({"context": context, "question": question}) + answer = self.llm.invoke(messages).content + + return { + "answer": answer, + "source_documents": docs, + "context": context, + "question": question + } + + rag_chain = RunnableLambda(rag_with_sources) + return rag_chain + + def invoke(self, question: str) -> Dict[str, Any]: + """同步调用""" + # 只调用一次,获取完整结果 + result = self.chain.invoke(question) + + return { + "answer": result["answer"], + "sources": self._format_sources(result["source_documents"]), + "metadata": { + "has_context": bool(result["source_documents"]), + "source_count": len(result["source_documents"]) + } + } + + async def ainvoke(self, question: str) -> Dict[str, Any]: + """异步调用""" + # 只调用一次,获取完整结果 + result = await self.chain.ainvoke(question) + + return { + "answer": result["answer"], + "sources": self._format_sources(result["source_documents"]), + "metadata": { + "has_context": bool(result["source_documents"]), + "source_count": len(result["source_documents"]) + } + } + + async def astream(self, question: str): + """流式调用(只流式输出答案)""" + # 先获取文档(这是唯一一次检索) + docs = await self.retriever.ainvoke(question) + context = "\n\n".join(doc.page_content for doc in docs) + + # 构建prompt + messages = await self.prompt.ainvoke({"context": context, "question": question}) + + # 流式生成答案 + async for chunk in self.llm.astream(messages): + if isinstance(chunk, str): + yield chunk + else: + # 处理AIMessageChunk + yield chunk.content if hasattr(chunk, 'content') else str(chunk) + + async def astream_with_sources(self, question: str): + """流式调用(返回答案流和文档,包含思考过程)""" + import time + + # 0. 思考阶段开始 + start_time = time.time() + yield {"type": "thinking", "stage": "understanding", "message": "正在理解问题..."} + + # 1. 检索文档 + yield {"type": "thinking", "stage": "retrieving", "message": "正在检索相关知识..."} + retrieval_start = time.time() + docs = await self.retriever.ainvoke(question) + retrieval_time = time.time() - retrieval_start + + # 发送检索结果 + yield { + "type": "thinking", + "stage": "retrieved", + "message": f"找到 {len(docs)} 条相关文档", + "doc_count": len(docs), + "time": round(retrieval_time, 2) + } + + context = "\n\n".join(doc.page_content for doc in docs) + + # 2. 构建prompt + yield {"type": "thinking", "stage": "generating", "message": "正在生成回答..."} + messages = await self.prompt.ainvoke({"context": context, "question": question}) + + # 3. 流式生成答案 + answer_chunks = [] + async for chunk in self.llm.astream(messages): + content = chunk.content if hasattr(chunk, 'content') else str(chunk) + answer_chunks.append(content) + yield {"type": "chunk", "content": content} + + # 4. 完成,返回sources + total_time = time.time() - start_time + yield { + "type": "sources", + "sources": self._format_sources(docs), + "answer": "".join(answer_chunks), + "metadata": { + "total_time": round(total_time, 2), + "retrieval_time": round(retrieval_time, 2) + } + } + + def _format_sources(self, documents: List) -> List[Dict]: + """格式化来源信息""" + sources = [] + for doc in documents: + metadata = doc.metadata if hasattr(doc, 'metadata') else {} + sources.append({ + "title": metadata.get("title", "未知标题"), + "filename": metadata.get("filename", "未知文件"), + "page": metadata.get("chunk_index", 0), + "preview": doc.page_content[:200] + "..." if len(doc.page_content) > 200 else doc.page_content + }) + return sources + +def create_rag_chain( + knowledge_base_ids: Optional[List[int]] = None, + search_type: str = "similarity", + k: int = 5, + model: Optional[str] = None +) -> RAGChain: + """创建RAG链实例 + + Args: + knowledge_base_ids: 知识库ID列表 + search_type: 搜索类型 + k: 返回文档数量 + model: 可选的模型名称,如 deepseek-ai/DeepSeek-V3, Qwen/QwQ-32B + """ + return RAGChain( + knowledge_base_ids=knowledge_base_ids, + search_type=search_type, + k=k, + model=model + ) diff --git a/backend/src/rag/conversation_chains.py b/backend/src/rag/conversation_chains.py new file mode 100644 index 0000000..43816e1 --- /dev/null +++ b/backend/src/rag/conversation_chains.py @@ -0,0 +1,129 @@ +""" +LangChain 1.0 对话链(Normal Mode) +""" +from typing import List, Dict, Any, Optional +from langchain_core.runnables import RunnablePassthrough +from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder +from langchain_core.messages import HumanMessage, AIMessage, SystemMessage +from langchain_core.output_parsers import StrOutputParser + +from ..llm.siliconflow import get_llm_client + + +class ConversationChain: + """标准对话链(LangChain 1.0)""" + + def __init__( + self, + system_prompt: Optional[str] = None, + model: Optional[str] = None + ): + """初始化对话链 + + Args: + system_prompt: 系统提示词 + model: 可选的模型名称,如 deepseek-ai/DeepSeek-V3, Qwen/QwQ-32B + """ + self.llm = get_llm_client(model=model).llm + self.system_prompt = system_prompt or "你是一个专业的国土空间规划知识问答助手。请基于你的知识回答用户的问题。" + + # 创建带历史的Prompt模板 + self.prompt = ChatPromptTemplate.from_messages([ + SystemMessage(content=self.system_prompt), + MessagesPlaceholder(variable_name="chat_history"), + ("human", "{question}") + ]) + + # 创建对话链 + self.chain = self._create_chain() + + def _create_chain(self): + """创建对话链""" + return ( + self.prompt + | self.llm + | StrOutputParser() + ) + + def invoke(self, question: str, chat_history: List[Dict] = None) -> Dict[str, Any]: + """同步调用""" + history_messages = self._format_history(chat_history or []) + answer = self.chain.invoke({ + "question": question, + "chat_history": history_messages + }) + + return { + "answer": answer, + "sources": [], + "metadata": { + "mode": "normal", + "has_history": bool(chat_history) + } + } + + async def ainvoke(self, question: str, chat_history: List[Dict] = None) -> Dict[str, Any]: + """异步调用""" + history_messages = self._format_history(chat_history or []) + answer = await self.chain.ainvoke({ + "question": question, + "chat_history": history_messages + }) + + return { + "answer": answer, + "sources": [], + "metadata": { + "mode": "normal", + "has_history": bool(chat_history) + } + } + + async def astream_with_thinking(self, question: str, chat_history: List[Dict] = None): + """流式调用(包含思考过程)""" + import time + + # 思考阶段 + start_time = time.time() + yield {"type": "thinking", "stage": "understanding", "message": "正在理解问题..."} + + # 准备历史 + history_messages = self._format_history(chat_history or []) + + yield {"type": "thinking", "stage": "generating", "message": "正在生成回答..."} + + # 流式生成 + async for chunk in self.chain.astream({ + "question": question, + "chat_history": history_messages + }): + yield {"type": "chunk", "content": chunk} + + # 完成 + total_time = time.time() - start_time + yield { + "type": "complete", + "metadata": { + "total_time": round(total_time, 2) + } + } + + def _format_history(self, chat_history: List[Dict]) -> List: + """格式化聊天历史为LangChain消息格式""" + messages = [] + for msg in chat_history: + if msg["role"] == "user": + messages.append(HumanMessage(content=msg["content"])) + elif msg["role"] == "assistant": + messages.append(AIMessage(content=msg["content"])) + return messages + + +def create_conversation_chain(system_prompt: Optional[str] = None, model: Optional[str] = None) -> ConversationChain: + """创建对话链实例 + + Args: + system_prompt: 系统提示词 + model: 可选的模型名称,如 deepseek-ai/DeepSeek-V3, Qwen/QwQ-32B + """ + return ConversationChain(system_prompt=system_prompt, model=model) diff --git a/backend/src/rag/document_loaders.py b/backend/src/rag/document_loaders.py new file mode 100644 index 0000000..c839f31 --- /dev/null +++ b/backend/src/rag/document_loaders.py @@ -0,0 +1,43 @@ +""" +LangChain 1.0 文档加载器封装 +""" +from typing import List, Optional +from pathlib import Path +from langchain_community.document_loaders import ( + PyPDFLoader, + Docx2txtLoader, + TextLoader, + UnstructuredMarkdownLoader +) +from langchain_core.documents import Document + +class DocumentLoaderFactory: + """文档加载器工厂""" + + @staticmethod + def get_loader(file_path: str, file_type: str): + """根据文件类型获取对应的加载器""" + loaders = { + ".pdf": PyPDFLoader, + ".docx": Docx2txtLoader, + ".txt": TextLoader, + ".md": UnstructuredMarkdownLoader, + } + + loader_class = loaders.get(file_type) + if not loader_class: + raise ValueError(f"Unsupported file type: {file_type}") + + return loader_class(file_path) + + @staticmethod + def load_document(file_path: str, file_type: str, metadata: Optional[dict] = None) -> List[Document]: + """加载文档并添加元数据""" + loader = DocumentLoaderFactory.get_loader(file_path, file_type) + documents = loader.load() + + if metadata: + for doc in documents: + doc.metadata.update(metadata) + + return documents diff --git a/backend/src/rag/embeddings.py b/backend/src/rag/embeddings.py new file mode 100644 index 0000000..c234a0f --- /dev/null +++ b/backend/src/rag/embeddings.py @@ -0,0 +1,69 @@ +""" +嵌入模型管理 +""" +from typing import List +from sentence_transformers import SentenceTransformer +import numpy as np + +from ..core.config import get_settings + +settings = get_settings() + + +class EmbeddingModel: + """嵌入模型管理器""" + + def __init__(self): + """初始化嵌入模型""" + self.model_name = settings.embedding_model + self.model = None + self._load_model() + + def _load_model(self): + """加载嵌入模型""" + try: + self.model = SentenceTransformer(self.model_name) + print(f"嵌入模型 {self.model_name} 加载成功") + except Exception as e: + raise Exception(f"嵌入模型加载失败: {str(e)}") + + def encode(self, texts: List[str]) -> np.ndarray: + """编码文本为向量""" + try: + embeddings = self.model.encode(texts) + return embeddings + except Exception as e: + raise Exception(f"文本编码失败: {str(e)}") + + def encode_single(self, text: str) -> np.ndarray: + """编码单个文本""" + return self.encode([text])[0] + + def embed_query(self, text: str) -> List[float]: + """LangChain兼容的查询嵌入方法""" + return self.encode_single(text).tolist() + + def embed_documents(self, texts: List[str]) -> List[List[float]]: + """LangChain兼容的文档嵌入方法""" + return self.encode(texts).tolist() + + def get_embedding_dimension(self) -> int: + """获取嵌入维度""" + if self.model is None: + return 0 + return self.model.get_sentence_embedding_dimension() + + +# 全局嵌入模型实例 +embedding_model = EmbeddingModel() + + +def get_embedding_model() -> EmbeddingModel: + """获取嵌入模型实例""" + return embedding_model + + + + + + diff --git a/backend/src/rag/prompts.py b/backend/src/rag/prompts.py new file mode 100644 index 0000000..5f57bae --- /dev/null +++ b/backend/src/rag/prompts.py @@ -0,0 +1,27 @@ +""" +RAG系统的Prompt模板(LangChain 1.0) +""" +from langchain_core.prompts import ChatPromptTemplate +from langchain_core.messages import SystemMessage, HumanMessage + +# RAG系统提示词 +RAG_SYSTEM_PROMPT = """你是一个专业的国土空间规划知识问答助手。请基于以下上下文信息回答用户的问题。 + +上下文信息: +{context} + +要求: +1. 回答要准确、专业、详细 +2. 如果上下文中没有相关信息,请诚实说明 +3. 回答要结构清晰,逻辑性强 +4. 适当引用相关概念和术语 +5. 回答长度控制在500-1000字之间 + +请基于上述上下文信息回答用户的问题。""" + +def create_rag_prompt() -> ChatPromptTemplate: + """创建RAG聊天Prompt模板""" + return ChatPromptTemplate.from_messages([ + ("system", RAG_SYSTEM_PROMPT), + ("human", "{question}") + ]) diff --git a/backend/src/rag/retriever.py b/backend/src/rag/retriever.py new file mode 100644 index 0000000..4b175e1 --- /dev/null +++ b/backend/src/rag/retriever.py @@ -0,0 +1,105 @@ +""" +文档检索器 +""" +from typing import List, Dict, Any, Optional +from .vector_store import get_vector_store +from .embeddings import get_embedding_model + + +class DocumentRetriever: + """文档检索器""" + + def __init__(self): + """初始化检索器""" + self.vector_store = get_vector_store() + self.embedding_model = get_embedding_model() + + def retrieve( + self, + query: str, + top_k: int = 5, + score_threshold: float = 0.7, + filter_metadata: Optional[Dict] = None + ) -> List[Dict[str, Any]]: + """检索相关文档""" + try: + print(f"[DEBUG-RETRIEVER] 开始检索 - query: {query[:50]}..., filter_metadata: {filter_metadata}") + + # 执行向量搜索 + results = self.vector_store.search( + query=query, + n_results=top_k, + filter_metadata=filter_metadata + ) + print(f"[DEBUG-RETRIEVER] 向量搜索返回结果数量: {len(results)}") + + # 过滤低分结果 + filtered_results = [ + result for result in results + if result.get("distance", 1.0) <= (1 - score_threshold) + ] + print(f"[DEBUG-RETRIEVER] 过滤后结果数量: {len(filtered_results)}") + + return filtered_results + + except Exception as e: + print(f"文档检索失败: {str(e)}") + return [] + + def retrieve_by_document_id(self, document_id: str) -> List[Dict[str, Any]]: + """根据文档ID检索""" + try: + results = self.vector_store.search( + query="", # 空查询 + n_results=1000, # 获取大量结果 + filter_metadata={"document_id": document_id} + ) + return results + except Exception as e: + print(f"按文档ID检索失败: {str(e)}") + return [] + + def get_relevant_context(self, query: str, max_length: int = 2000) -> str: + """获取相关上下文""" + results = self.retrieve(query, top_k=5) + + if not results: + return "" + + # 按相关性排序并拼接内容 + context_parts = [] + current_length = 0 + + for result in results: + content = result.get("content", "") + if current_length + len(content) > max_length: + break + + context_parts.append(content) + current_length += len(content) + + return "\n\n".join(context_parts) + + def get_sources_info(self, query: str, top_k: int = 5, filter_metadata: Optional[Dict] = None) -> List[Dict[str, Any]]: + """获取来源信息""" + results = self.retrieve(query, top_k=top_k, filter_metadata=filter_metadata) + + sources = [] + for result in results: + metadata = result.get("metadata", {}) + source_info = { + "title": metadata.get("title", "未知标题"), + "filename": metadata.get("filename", "未知文件"), + "page": metadata.get("page", 0), + "score": 1 - result.get("distance", 1.0), # 转换为相似度分数 + "preview": result.get("content", "")[:200] + "..." if len(result.get("content", "")) > 200 else result.get("content", "") + } + sources.append(source_info) + + return sources + + + + + + diff --git a/backend/src/rag/retrievers.py b/backend/src/rag/retrievers.py new file mode 100644 index 0000000..ec06b3b --- /dev/null +++ b/backend/src/rag/retrievers.py @@ -0,0 +1,82 @@ +""" +自定义知识库检索器(LangChain 1.0) +""" +from typing import List, Optional +import math +from langchain_core.documents import Document +from langchain_core.callbacks.manager import CallbackManagerForRetrieverRun +from langchain_core.retrievers import BaseRetriever + +class KnowledgeBaseRetriever(BaseRetriever): + """支持知识库过滤和智能分数转换的检索器""" + + vectorstore: any + knowledge_base_ids: Optional[List[int]] = None + search_type: str = "similarity" + search_kwargs: dict = {"k": 5} + score_threshold: float = 0.1 + + def _get_relevant_documents( + self, + query: str, + *, + run_manager: CallbackManagerForRetrieverRun + ) -> List[Document]: + """获取相关文档(LangChain 1.0标准接口)""" + print(f"[DEBUG-Retriever] 查询: {query}") + print(f"[DEBUG-Retriever] knowledge_base_ids: {self.knowledge_base_ids}") + + # 构建知识库过滤条件 + filter_dict = None + if self.knowledge_base_ids: + filter_dict = {"knowledge_base_id": {"$in": self.knowledge_base_ids}} + print(f"[DEBUG-Retriever] 构建的过滤条件: {filter_dict}") + else: + print(f"[DEBUG-Retriever] 没有知识库ID,不进行过滤") + + # 执行搜索 + if self.search_type == "similarity": + docs_and_scores = self.vectorstore.similarity_search_with_score( + query=query, + k=self.search_kwargs.get("k", 5), + filter=filter_dict + ) + print(f"[DEBUG-Retriever] 搜索返回文档数量: {len(docs_and_scores)}") + + # 打印每个文档的知识库ID + for i, (doc, distance) in enumerate(docs_and_scores): + kb_id = doc.metadata.get("knowledge_base_id", "未知") + print(f"[DEBUG-Retriever] 文档{i+1}: knowledge_base_id={kb_id}, distance={distance:.4f}") + + # 转换距离为分数并过滤 + filtered_docs = [] + for doc, distance in docs_and_scores: + score = self._convert_distance_to_score(distance) + if score > self.score_threshold: + filtered_docs.append(doc) + + print(f"[DEBUG-Retriever] 过滤后文档数量: {len(filtered_docs)}") + return filtered_docs + + elif self.search_type == "mmr": + return self.vectorstore.max_marginal_relevance_search( + query=query, + k=self.search_kwargs.get("k", 5), + fetch_k=self.search_kwargs.get("fetch_k", 20), + filter=filter_dict + ) + + return [] + + def _convert_distance_to_score(self, distance: float) -> float: + """将ChromaDB的distance转换为0-1范围的相似度分数""" + # 内积距离(负值) + if distance < 0: + return (1 + distance) / 2 + + # 大距离使用对数缩放 + if distance > 100: + return 1 / (1 + math.log(distance)) + + # 标准距离转换 + return 1 / (1 + distance) diff --git a/backend/src/rag/text_splitters.py b/backend/src/rag/text_splitters.py new file mode 100644 index 0000000..880824c --- /dev/null +++ b/backend/src/rag/text_splitters.py @@ -0,0 +1,41 @@ +""" +LangChain 1.0 文本分割器配置 +""" +from langchain_text_splitters import RecursiveCharacterTextSplitter +from typing import List +from langchain_core.documents import Document + +class ChineseTextSplitter: + """中文文本分割器""" + + def __init__(self, chunk_size: int = 1000, chunk_overlap: int = 200): + # 针对中文优化的分隔符顺序 + self.splitter = RecursiveCharacterTextSplitter( + chunk_size=chunk_size, + chunk_overlap=chunk_overlap, + separators=[ + "\n\n", # 段落 + "\n", # 行 + "。", # 句号 + "!", # 感叹号 + "?", # 问号 + ";", # 分号 + ",", # 逗号 + " ", # 空格 + "", # 字符 + ], + length_function=len, + is_separator_regex=False, + ) + + def split_documents(self, documents: List[Document]) -> List[Document]: + """分割文档""" + return self.splitter.split_documents(documents) + + def split_text(self, text: str) -> List[str]: + """分割文本""" + return self.splitter.split_text(text) + +def get_text_splitter(chunk_size: int = 1000, chunk_overlap: int = 200) -> ChineseTextSplitter: + """获取文本分割器实例""" + return ChineseTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap) diff --git a/backend/src/rag/vector_store.py b/backend/src/rag/vector_store.py new file mode 100644 index 0000000..be15a0f --- /dev/null +++ b/backend/src/rag/vector_store.py @@ -0,0 +1,98 @@ +""" +LangChain 1.0 向量存储封装 +""" +import os +import json +import hashlib +from typing import List, Dict, Any, Optional +from pathlib import Path +from langchain_chroma import Chroma +from langchain_core.documents import Document as LangChainDocument + +from ..core.config import get_settings +from .embeddings import get_embedding_model + +settings = get_settings() + + +class VectorStore: + """向量存储管理器(LangChain 1.0 Chroma)""" + + def __init__(self): + """初始化向量存储""" + self.vector_store_path = Path(settings.vector_store_path) + self.vector_store_path.mkdir(parents=True, exist_ok=True) + + # 获取嵌入模型(保留自定义实现) + self.embedding_model = get_embedding_model() + + # 使用LangChain Chroma wrapper + self.vectorstore = Chroma( + collection_name="course_knowledge", + embedding_function=self.embedding_model, + persist_directory=str(self.vector_store_path), + collection_metadata={"hnsw:space": "l2"} # 保持L2距离度量 + ) + + def add_documents(self, documents: List[LangChainDocument]) -> bool: + """添加LangChain文档到向量存储""" + try: + self.vectorstore.add_documents(documents) + return True + except Exception as e: + print(f"添加文档失败: {str(e)}") + return False + + def as_retriever(self, **kwargs): + """返回标准LangChain检索器""" + return self.vectorstore.as_retriever(**kwargs) + + def similarity_search_with_score( + self, + query: str, + k: int = 5, + filter: Optional[Dict] = None + ): + """相似度搜索(带分数)""" + print(f"[DEBUG-VectorStore] 查询参数 - k: {k}, filter: {filter}") + + result = self.vectorstore.similarity_search_with_score( + query=query, + k=k, + filter=filter + ) + + print(f"[DEBUG-VectorStore] 返回结果数量: {len(result)}") + return result + + def max_marginal_relevance_search( + self, + query: str, + k: int = 5, + fetch_k: int = 20, + filter: Optional[Dict] = None + ): + """MMR搜索(多样性检索)""" + return self.vectorstore.max_marginal_relevance_search( + query=query, + k=k, + fetch_k=fetch_k, + filter=filter + ) + + +# 单例模式 +_vector_store_instance = None + +def get_vector_store() -> VectorStore: + """获取向量存储实例""" + global _vector_store_instance + if _vector_store_instance is None: + _vector_store_instance = VectorStore() + return _vector_store_instance + + + + + + diff --git a/backend/src/services/__init__.py b/backend/src/services/__init__.py new file mode 100644 index 0000000..1ab9654 --- /dev/null +++ b/backend/src/services/__init__.py @@ -0,0 +1,7 @@ +# 业务逻辑服务模块 + + + + + + diff --git a/backend/src/services/analytics_service.py b/backend/src/services/analytics_service.py new file mode 100644 index 0000000..8492210 --- /dev/null +++ b/backend/src/services/analytics_service.py @@ -0,0 +1,215 @@ +""" +学习分析服务 +提供用户学习数据的统计和分析功能 +""" + +from typing import Dict, Any, List +from sqlalchemy.orm import Session +from sqlalchemy import func, distinct, and_ +from datetime import datetime, timedelta + +from ..models.user import User +from ..models.chat import ChatSession, ChatMessage +from ..models.document import Document + + +class AnalyticsService: + """学习分析服务""" + + def __init__(self, db: Session): + self.db = db + + def get_user_statistics(self, user_id: int) -> Dict[str, Any]: + """获取用户统计数据""" + try: + # 获取用户信息 + user = self.db.query(User).filter(User.id == user_id).first() + if not user: + raise ValueError(f"用户 {user_id} 不存在") + + # 总会话数 + total_sessions = self.db.query(ChatSession).filter( + ChatSession.user_id == user_id + ).count() + + # 总消息数(只统计用户发送的消息) + total_messages = self.db.query(ChatMessage).join(ChatSession).filter( + and_( + ChatSession.user_id == user_id, + ChatMessage.role == "user" + ) + ).count() + + # 总文档数 + total_documents = self.db.query(Document).filter( + Document.user_id == user_id + ).count() + + # 活跃天数(基于会话创建日期) + active_days = self.db.query( + distinct(func.date(ChatSession.created_at)) + ).filter( + ChatSession.user_id == user_id + ).count() + + # 用户注册时间 + user_since = user.created_at.isoformat() if user.created_at else None + + return { + "total_sessions": total_sessions, + "total_messages": total_messages, + "total_documents": total_documents, + "active_days": active_days, + "user_since": user_since, + "last_login": user.last_login.isoformat() if user.last_login else None + } + + except Exception as e: + print(f"[ERROR] 获取用户统计数据失败: {str(e)}") + raise Exception(f"获取统计数据失败: {str(e)}") + + def get_user_learning_trends(self, user_id: int, days: int = 30) -> List[Dict[str, Any]]: + """获取用户学习趋势数据""" + try: + # 计算开始日期 + end_date = datetime.now() + start_date = end_date - timedelta(days=days) + + # 按日期统计消息和会话数量 + trends_query = self.db.query( + func.date(ChatSession.created_at).label('date'), + func.count(distinct(ChatSession.id)).label('sessions'), + func.count(ChatMessage.id).label('messages') + ).join( + ChatMessage, ChatSession.id == ChatMessage.session_id + ).filter( + and_( + ChatSession.user_id == user_id, + ChatSession.created_at >= start_date, + ChatMessage.role == "user" # 只统计用户消息 + ) + ).group_by( + func.date(ChatSession.created_at) + ).order_by( + func.date(ChatSession.created_at) + ) + + trends = [] + for row in trends_query: + # 处理日期格式,确保返回字符串 + date_str = row.date.isoformat() if hasattr(row.date, 'isoformat') else str(row.date) + trends.append({ + "date": date_str, + "sessions": row.sessions, + "messages": row.messages + }) + + return trends + + except Exception as e: + print(f"[ERROR] 获取学习趋势数据失败: {str(e)}") + raise Exception(f"获取学习趋势失败: {str(e)}") + + def get_popular_questions(self, user_id: int, limit: int = 10) -> List[Dict[str, Any]]: + """获取用户热门问题""" + try: + # 统计用户消息中出现频率最高的问题 + # 这里简化处理,实际可能需要更复杂的文本分析 + popular_query = self.db.query( + ChatMessage.content.label('question'), + func.count(ChatMessage.id).label('count') + ).join(ChatSession).filter( + and_( + ChatSession.user_id == user_id, + ChatMessage.role == "user", + func.length(ChatMessage.content) > 10 # 过滤太短的消息 + ) + ).group_by( + ChatMessage.content + ).order_by( + func.count(ChatMessage.id).desc() + ).limit(limit) + + popular_questions = [] + for row in popular_query: + popular_questions.append({ + "question": row.question, + "count": row.count, + "category": "用户问题" # 简化分类 + }) + + return popular_questions + + except Exception as e: + print(f"[ERROR] 获取热门问题失败: {str(e)}") + raise Exception(f"获取热门问题失败: {str(e)}") + + def get_knowledge_coverage(self, user_id: int) -> List[Dict[str, Any]]: + """获取知识覆盖度(简化版本)""" + try: + # 这里是一个简化的实现 + # 实际可能需要基于文档内容和问题内容进行更复杂的分析 + coverage_data = [ + {"topic": "基础概念", "coverage": 75, "questions": 20}, + {"topic": "实践方法", "coverage": 60, "questions": 15}, + {"topic": "技术标准", "coverage": 45, "questions": 10}, + {"topic": "案例分析", "coverage": 30, "questions": 8}, + {"topic": "政策法规", "coverage": 25, "questions": 5} + ] + + return coverage_data + + except Exception as e: + print(f"[ERROR] 获取知识覆盖度失败: {str(e)}") + raise Exception(f"获取知识覆盖度失败: {str(e)}") + + def get_learning_report(self, user_id: int) -> Dict[str, Any]: + """获取学习报告""" + try: + stats = self.get_user_statistics(user_id) + + # 计算学习进度(基于活跃天数和消息数量) + days_since_registration = 1 + if stats["user_since"]: + # 处理日期字符串,确保正确解析 + user_since_str = stats["user_since"] + if isinstance(user_since_str, str): + # 移除时区信息并解析 + clean_date_str = user_since_str.replace('Z', '').replace('+00:00', '') + reg_date = datetime.fromisoformat(clean_date_str) + else: + reg_date = user_since_str + days_since_registration = max(1, (datetime.now() - reg_date).days) + + # 简化的学习进度计算 + learning_progress = min(100, (stats["active_days"] / days_since_registration) * 100) + + # 学习建议 + recommendations = [] + if stats["total_messages"] < 50: + recommendations.append("建议增加提问频率,多与AI助手互动学习") + if stats["total_documents"] < 5: + recommendations.append("建议上传更多相关文档,丰富知识库内容") + if stats["active_days"] < 7: + recommendations.append("建议保持每日学习习惯,提高学习连续性") + + # 知识缺口 + knowledge_gaps = [] + if stats["total_sessions"] < 10: + knowledge_gaps.append("基础概念理解不够深入") + if stats["total_documents"] < 3: + knowledge_gaps.append("实践应用能力有待提升") + + return { + "user_id": user_id, + "total_questions": stats["total_messages"], + "topics_covered": ["国土空间规划基础理论", "规划编制方法与技术", "土地利用规划"], + "learning_progress": round(learning_progress, 1), + "recommendations": recommendations, + "study_time": stats["total_messages"] * 2, # 估算学习时间(分钟) + "knowledge_gaps": knowledge_gaps + } + + except Exception as e: + print(f"[ERROR] 获取学习报告失败: {str(e)}") + raise Exception(f"获取学习报告失败: {str(e)}") diff --git a/backend/src/services/auth_service.py b/backend/src/services/auth_service.py new file mode 100644 index 0000000..688d74f --- /dev/null +++ b/backend/src/services/auth_service.py @@ -0,0 +1,202 @@ +""" +用户认证服务 +""" +from datetime import datetime, timedelta +from typing import Optional, Dict, Any +from sqlalchemy.orm import Session +from sqlalchemy import and_ + +from ..models.user import User +from ..core.security import get_password_hash, verify_password, create_access_token +from ..core.config import get_settings + +settings = get_settings() + + +class AuthService: + """用户认证服务""" + + def __init__(self, db: Session): + self.db = db + + def create_user( + self, + username: str, + email: str, + password: str, + full_name: Optional[str] = None + ) -> Optional[User]: + """创建用户""" + try: + # 检查用户名是否已存在 + if self.get_user_by_username(username): + return None + + # 检查邮箱是否已存在 + if self.get_user_by_email(email): + return None + + # 限制密码长度(bcrypt 最大支持72字节) + if len(password) > 72: + password = password[:72] + + # 创建新用户 + hashed_password = get_password_hash(password) + user = User( + username=username, + email=email, + hashed_password=hashed_password, + full_name=full_name, + is_active=True + ) + + self.db.add(user) + self.db.commit() + self.db.refresh(user) + + return user + + except Exception as e: + self.db.rollback() + print(f"创建用户失败: {str(e)}") + return None + + def authenticate_user(self, username: str, password: str) -> Optional[User]: + """验证用户""" + try: + user = self.get_user_by_username(username) + if not user: + return None + + # 限制密码长度(bcrypt 最大支持72字节) + if len(password) > 72: + password = password[:72] + + if not verify_password(password, user.hashed_password): + return None + + if not user.is_active: + return None + + # 更新最后登录时间 + user.last_login = datetime.utcnow() + self.db.commit() + + return user + + except Exception as e: + print(f"用户认证失败: {str(e)}") + return None + + def get_user_by_username(self, username: str) -> Optional[User]: + """根据用户名获取用户""" + return self.db.query(User).filter(User.username == username).first() + + def get_user_by_email(self, email: str) -> Optional[User]: + """根据邮箱获取用户""" + return self.db.query(User).filter(User.email == email).first() + + def get_user_by_id(self, user_id: int) -> Optional[User]: + """根据ID获取用户""" + return self.db.query(User).filter(User.id == user_id).first() + + def update_user(self, user_id: int, **kwargs) -> Optional[User]: + """更新用户信息""" + try: + user = self.get_user_by_id(user_id) + if not user: + return None + + for key, value in kwargs.items(): + if hasattr(user, key) and value is not None: + setattr(user, key, value) + + self.db.commit() + self.db.refresh(user) + return user + + except Exception as e: + self.db.rollback() + print(f"更新用户失败: {str(e)}") + return None + + def deactivate_user(self, user_id: int) -> bool: + """停用用户""" + try: + user = self.get_user_by_id(user_id) + if not user: + return False + + user.is_active = False + self.db.commit() + return True + + except Exception as e: + self.db.rollback() + print(f"停用用户失败: {str(e)}") + return False + + def change_password(self, user_id: int, old_password: str, new_password: str) -> bool: + """修改密码""" + try: + user = self.get_user_by_id(user_id) + if not user: + return False + + if not verify_password(old_password, user.hashed_password): + return False + + user.hashed_password = get_password_hash(new_password) + self.db.commit() + return True + + except Exception as e: + self.db.rollback() + print(f"修改密码失败: {str(e)}") + return False + + def create_access_token_for_user(self, user: User) -> Dict[str, Any]: + """为用户创建访问令牌""" + access_token_expires = timedelta(minutes=settings.access_token_expire_minutes) + access_token = create_access_token( + data={"sub": user.username}, + expires_delta=access_token_expires + ) + + return { + "access_token": access_token, + "token_type": "bearer", + "expires_in": settings.access_token_expire_minutes * 60, + "user": { + "id": user.id, + "username": user.username, + "email": user.email, + "full_name": user.full_name, + "is_active": user.is_active + } + } + + def get_user_statistics(self) -> Dict[str, Any]: + """获取用户统计信息""" + try: + total_users = self.db.query(User).count() + active_users = self.db.query(User).filter(User.is_active == True).count() + recent_users = self.db.query(User).filter( + User.created_at >= datetime.utcnow() - timedelta(days=30) + ).count() + + return { + "total_users": total_users, + "active_users": active_users, + "recent_users": recent_users, + "inactive_users": total_users - active_users + } + + except Exception as e: + print(f"获取用户统计失败: {str(e)}") + return { + "total_users": 0, + "active_users": 0, + "recent_users": 0, + "inactive_users": 0 + } diff --git a/backend/src/services/book_content_service.py b/backend/src/services/book_content_service.py new file mode 100644 index 0000000..4374c98 --- /dev/null +++ b/backend/src/services/book_content_service.py @@ -0,0 +1,132 @@ +""" +书籍内容读取服务 +根据数据库中的行号范围从LaTeX文件动态读取内容 +层级结构:书籍 -> Chapter -> Section -> Subsection(知识点) +""" +from pathlib import Path +from typing import Optional +from sqlalchemy.orm import Session + +from ..models.book_structure import Chapter, Section, Subsection +from .latex_parser import LaTeXParser + + +class BookContentService: + """书籍内容服务""" + + def __init__(self, book_dir: str): + """ + 初始化服务 + + Args: + book_dir: 书籍目录路径 + """ + # 处理相对路径:如果相对路径不存在,尝试从项目根目录查找 + book_path = Path(book_dir) + if not book_path.exists() or not book_path.is_absolute(): + # 脚本位置: dofile/backend/src/services/book_content_service.py + # 项目根目录: 向上3级 + project_root = Path(__file__).parent.parent.parent.parent.parent + book_path = project_root / "data" / "book" + if not book_path.exists(): + # 如果还是不存在,使用原始路径 + book_path = Path(book_dir) + + self.book_dir = book_path + self.parser = LaTeXParser(self.book_dir) + + def get_chapter_content(self, db: Session, chapter_id: int) -> Optional[str]: + """ + 获取章节完整内容 + + Args: + db: 数据库会话 + chapter_id: 章节ID + + Returns: + 章节内容文本,如果章节不存在则返回None + """ + chapter = db.query(Chapter).filter(Chapter.id == chapter_id).first() + if not chapter: + return None + + try: + file_path = self.book_dir / Path(chapter.file_path).name + content = self.parser.get_content_by_lines( + file_path, + chapter.start_line, + chapter.end_line + ) + return content + except Exception as e: + print(f"读取章节内容失败: {e}") + return None + + def get_section_content(self, db: Session, section_id: int) -> Optional[str]: + """ + 获取节完整内容 + + Args: + db: 数据库会话 + section_id: 节ID + + Returns: + 节内容文本,如果节不存在则返回None + """ + section = db.query(Section).filter(Section.id == section_id).first() + if not section: + return None + + try: + # 通过section获取chapter以获取文件路径 + chapter = db.query(Chapter).filter(Chapter.id == section.chapter_id).first() + if not chapter: + return None + + file_path = self.book_dir / Path(chapter.file_path).name + content = self.parser.get_content_by_lines( + file_path, + section.start_line, + section.end_line + ) + return content + except Exception as e: + print(f"读取节内容失败: {e}") + return None + + def get_subsection_content(self, db: Session, subsection_id: int) -> Optional[str]: + """ + 获取小节完整内容(知识点,包含其下所有subsubsection内容) + + Args: + db: 数据库会话 + subsection_id: 小节ID + + Returns: + 小节内容文本,如果小节不存在则返回None + """ + subsection = db.query(Subsection).filter(Subsection.id == subsection_id).first() + if not subsection: + return None + + try: + # 通过subsection获取section和chapter以获取文件路径 + section = db.query(Section).filter(Section.id == subsection.section_id).first() + if not section: + return None + + chapter = db.query(Chapter).filter(Chapter.id == section.chapter_id).first() + if not chapter: + return None + + file_path = self.book_dir / Path(chapter.file_path).name + content = self.parser.get_content_by_lines( + file_path, + subsection.start_line, + subsection.end_line + ) + return content + except Exception as e: + print(f"读取小节内容失败: {e}") + return None + diff --git a/backend/src/services/document_service.py b/backend/src/services/document_service.py new file mode 100644 index 0000000..7772fbd --- /dev/null +++ b/backend/src/services/document_service.py @@ -0,0 +1,127 @@ +""" +文档处理服务(LangChain 1.0) +""" +import os +import hashlib +from pathlib import Path +from typing import List, Dict, Any, Optional +from sqlalchemy.orm import Session +from langchain_core.documents import Document as LangChainDocument + +from ..models.document import Document, DocumentChunk +from ..rag.vector_store import get_vector_store +from ..rag.document_loaders import DocumentLoaderFactory +from ..rag.text_splitters import get_text_splitter + +class DocumentService: + """文档处理服务""" + + def __init__(self, db: Session): + self.db = db + self.vector_store = get_vector_store() + + async def process_document(self, document_id: int) -> bool: + """处理文档(使用LangChain 1.0)""" + try: + document = self.db.query(Document).filter(Document.id == document_id).first() + if not document: + return False + + # 1. 使用LangChain加载文档 + documents = DocumentLoaderFactory.load_document( + file_path=document.file_path, + file_type=document.file_type, + metadata={ + "document_id": document.id, + "knowledge_base_id": document.knowledge_base_id, + "title": document.title, + "filename": document.filename + } + ) + + # 2. 使用中文优化的文本分割器 + text_splitter = get_text_splitter(chunk_size=1000, chunk_overlap=200) + splits = text_splitter.split_documents(documents) + + # 3. 添加到向量存储 + success = self.vector_store.add_documents(splits) + + if success: + document.is_processed = True + self.db.commit() + return True + + return False + + except Exception as e: + print(f"处理文档失败: {str(e)}") + self.db.rollback() + return False + + def search_documents(self, query: str, knowledge_base_ids: Optional[List[int]] = None, limit: int = 5) -> List[Dict[str, Any]]: + """搜索文档(保留原有接口兼容性)""" + try: + # 构建过滤条件 + filter_dict = None + if knowledge_base_ids: + filter_dict = {"knowledge_base_id": {"$in": knowledge_base_ids}} + + # 使用LangChain Chroma进行搜索 + results = self.vector_store.similarity_search_with_score( + query=query, + k=limit, + filter=filter_dict + ) + + # 格式化结果 + search_results = [] + for doc, distance in results: + metadata = doc.metadata if hasattr(doc, 'metadata') else {} + score = self._convert_distance_to_score(distance) + + search_results.append({ + "content": doc.page_content, + "metadata": metadata, + "score": score, + "distance": distance + }) + + return search_results + + except Exception as e: + print(f"搜索文档失败: {str(e)}") + return [] + + def _convert_distance_to_score(self, distance: float) -> float: + """将ChromaDB的distance转换为0-1范围的相似度分数""" + import math + + # 内积距离(负值) + if distance < 0: + return (1 + distance) / 2 + + # 大距离使用对数缩放 + if distance > 100: + return 1 / (1 + math.log(distance)) + + # 标准距离转换 + return 1 / (1 + distance) + + def get_document_chunks(self, document_id: int) -> List[DocumentChunk]: + """获取文档的所有块""" + return self.db.query(DocumentChunk).filter( + DocumentChunk.document_id == document_id + ).order_by(DocumentChunk.chunk_index).all() + + def delete_document_chunks(self, document_id: int) -> bool: + """删除文档的所有块""" + try: + self.db.query(DocumentChunk).filter( + DocumentChunk.document_id == document_id + ).delete() + self.db.commit() + return True + except Exception as e: + print(f"删除文档块失败: {str(e)}") + self.db.rollback() + return False \ No newline at end of file diff --git a/backend/src/services/file_watcher_service.py b/backend/src/services/file_watcher_service.py new file mode 100644 index 0000000..1dd32b8 --- /dev/null +++ b/backend/src/services/file_watcher_service.py @@ -0,0 +1,194 @@ +""" +文件监控服务 +""" +import os +import time +import threading +from pathlib import Path +from typing import Optional, Callable +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler, FileCreatedEvent, FileModifiedEvent, FileDeletedEvent + +from ..core.config import get_settings +from ..core.database import get_db +from .knowledge_base_service import KnowledgeBaseService + +settings = get_settings() + + +class KnowledgeBaseHandler(FileSystemEventHandler): + """知识库文件监控处理器""" + + def __init__(self, knowledge_base_service: KnowledgeBaseService): + self.kb_service = knowledge_base_service + self.knowledge_base_dir = Path(settings.knowledge_base_dir) + self.supported_extensions = settings.allowed_extensions + + def on_created(self, event): + """处理文件创建事件""" + if not event.is_directory and self._is_supported_file(event.src_path): + print(f"检测到新文件: {event.src_path}") + self._process_file_async(event.src_path, "created") + + def on_modified(self, event): + """处理文件修改事件""" + if not event.is_directory and self._is_supported_file(event.src_path): + print(f"检测到文件修改: {event.src_path}") + self._process_file_async(event.src_path, "modified") + + def on_deleted(self, event): + """处理文件删除事件""" + if not event.is_directory and self._is_supported_file(event.src_path): + print(f"检测到文件删除: {event.src_path}") + self._handle_file_deletion(event.src_path) + + def _is_supported_file(self, file_path: str) -> bool: + """检查是否为支持的文件类型""" + return Path(file_path).suffix.lower() in self.supported_extensions + + def _process_file_async(self, file_path: str, event_type: str): + """异步处理文件""" + def process(): + try: + # 等待文件写入完成 + time.sleep(1) + + result = self.kb_service.process_file(file_path) + print(f"文件处理结果 ({event_type}): {result}") + + except Exception as e: + print(f"处理文件失败: {file_path}, 错误: {str(e)}") + + # 在后台线程中处理 + thread = threading.Thread(target=process) + thread.daemon = True + thread.start() + + def _handle_file_deletion(self, file_path: str): + """处理文件删除""" + try: + # 查找并删除对应的数据库记录 + from ..models.document import Document + from sqlalchemy import and_ + + document = self.kb_service.db.query(Document).filter( + and_( + Document.file_path == file_path, + Document.source_type == "knowledge_base" + ) + ).first() + + if document: + result = self.kb_service.delete_document(document.id) + print(f"文件删除处理结果: {result}") + else: + print(f"未找到对应的数据库记录: {file_path}") + + except Exception as e: + print(f"处理文件删除失败: {file_path}, 错误: {str(e)}") + + +class FileWatcherService: + """文件监控服务""" + + def __init__(self): + self.observer: Optional[Observer] = None + self.knowledge_base_dir = Path(settings.knowledge_base_dir) + self.is_running = False + + def start(self): + """启动文件监控""" + if self.is_running: + print("文件监控服务已在运行") + return + + if not settings.enable_file_watcher: + print("文件监控服务已禁用") + return + + if not self.knowledge_base_dir.exists(): + print(f"知识库目录不存在: {self.knowledge_base_dir}") + return + + try: + # 创建数据库会话 + db = next(get_db()) + kb_service = KnowledgeBaseService(db) + + # 创建事件处理器 + event_handler = KnowledgeBaseHandler(kb_service) + + # 创建观察者 + self.observer = Observer() + self.observer.schedule( + event_handler, + str(self.knowledge_base_dir), + recursive=True # 递归监控子目录 + ) + + # 启动观察者 + self.observer.start() + self.is_running = True + + print(f"文件监控服务已启动,监控目录: {self.knowledge_base_dir}") + + # 执行初始扫描 + print("执行初始知识库扫描...") + scan_result = kb_service.scan_directory() + print(f"初始扫描结果: {scan_result}") + + except Exception as e: + print(f"启动文件监控服务失败: {str(e)}") + self.is_running = False + + def stop(self): + """停止文件监控""" + if self.observer and self.is_running: + self.observer.stop() + self.observer.join() + self.is_running = False + print("文件监控服务已停止") + + def is_active(self) -> bool: + """检查监控服务是否活跃""" + return self.is_running and self.observer and self.observer.is_alive() + + def get_status(self) -> dict: + """获取监控服务状态""" + return { + "is_running": self.is_running, + "is_active": self.is_active(), + "knowledge_base_dir": str(self.knowledge_base_dir), + "directory_exists": self.knowledge_base_dir.exists(), + "enable_file_watcher": settings.enable_file_watcher + } + + +# 全局文件监控服务实例 +file_watcher_service: Optional[FileWatcherService] = None + + +def get_file_watcher_service() -> FileWatcherService: + """获取文件监控服务实例""" + global file_watcher_service + if file_watcher_service is None: + file_watcher_service = FileWatcherService() + return file_watcher_service + + +def start_file_watcher(): + """启动文件监控服务""" + watcher = get_file_watcher_service() + watcher.start() + + +def stop_file_watcher(): + """停止文件监控服务""" + watcher = get_file_watcher_service() + watcher.stop() + + + + + + diff --git a/backend/src/services/image_generation_service.py b/backend/src/services/image_generation_service.py new file mode 100644 index 0000000..3534f88 --- /dev/null +++ b/backend/src/services/image_generation_service.py @@ -0,0 +1,97 @@ +""" +统一图像生成服务基类 +支持硅基流动平台的多种图像生成模型 +""" + +import base64 +import uuid +from pathlib import Path +from typing import Dict, Any +import httpx +from src.core.config import settings + + +class ImageGenerationService: + """统一的图像生成服务基类""" + + def __init__(self): + self.base_url = "https://api.siliconflow.cn/v1/image/generations" + self.api_key = settings.siliconflow_api_key + self.timeout = 60 + + async def call_api(self, model: str, payload: dict) -> dict: + """调用硅基流动 API""" + print(f"[DEBUG] 调用SiliconFlow API: {self.base_url}") + print(f"[DEBUG] 模型: {model}") + print(f"[DEBUG] 请求参数: {payload}") + + async with httpx.AsyncClient(timeout=self.timeout) as client: + response = await client.post( + self.base_url, + headers={ + "Authorization": f"Bearer {self.api_key}", + "Content-Type": "application/json" + }, + json={"model": model, **payload} + ) + response.raise_for_status() + + result = response.json() + print(f"[DEBUG] API响应状态: {response.status_code}") + print(f"[DEBUG] API响应类型: {type(result)}") + print(f"[DEBUG] API响应键: {list(result.keys()) if isinstance(result, dict) else '非字典类型'}") + + return result + + def save_image(self, image_id: str, base64_data: str) -> str: + """保存 base64 图像到本地文件系统""" + try: + # 清理base64数据(移除可能的data URL前缀) + if base64_data.startswith('data:image'): + base64_data = base64_data.split(',')[1] + + # 移除可能的空白字符 + base64_data = base64_data.strip() + + print(f"[DEBUG] 开始解码base64数据,长度: {len(base64_data)}") + + # 解码 base64 数据 + image_bytes = base64.b64decode(base64_data) + + # 验证是否为有效的图片数据 + if len(image_bytes) == 0: + raise Exception("解码后的图像数据为空") + + print(f"[DEBUG] 图像数据大小: {len(image_bytes)} bytes") + + # 确保目录存在 + image_dir = Path(settings.generated_images_dir) + image_dir.mkdir(parents=True, exist_ok=True) + + # 保存图像文件 + image_path = image_dir / f"{image_id}.png" + with open(image_path, "wb") as f: + f.write(image_bytes) + + print(f"[DEBUG] 图像已保存到: {image_path}") + + return str(image_path) + except Exception as e: + print(f"[ERROR] 保存图像失败: {str(e)}") + print(f"[ERROR] base64数据长度: {len(base64_data) if base64_data else 0}") + print(f"[ERROR] base64数据前100字符: {base64_data[:100] if base64_data else 'None'}") + raise Exception(f"保存图像失败: {str(e)}") + + def generate_image_id(self) -> str: + """生成唯一的图像ID""" + return str(uuid.uuid4()) + + def get_image_url(self, image_id: str) -> str: + """获取图像的访问URL""" + return f"/generated_images/{image_id}.png" + + + + + + diff --git a/backend/src/services/image_to_image_service.py b/backend/src/services/image_to_image_service.py new file mode 100644 index 0000000..c3570f9 --- /dev/null +++ b/backend/src/services/image_to_image_service.py @@ -0,0 +1,355 @@ +""" +图生图服务 +支持 Qwen/Qwen-Image-Edit 模型进行图像编辑 +""" + +import base64 +import httpx +from typing import List, Dict, Any, Optional +from pathlib import Path +from fastapi import UploadFile +from .image_generation_service import ImageGenerationService + + +class ImageToImageService(ImageGenerationService): + """图生图服务""" + + MODEL = "Qwen/Qwen-Image-Edit" + + EDIT_MODES = { + "optimize": "全图优化增强", + "style_transfer": "风格转换", + "local_edit": "局部编辑修改", + "outpaint": "图像智能扩展" + } + + async def edit_image( + self, + image_file: UploadFile, + prompt: str, + mode: str = "optimize", + mask_file: Optional[UploadFile] = None, + strength: float = 0.8 # 保留用于兼容性,API不支持 + ) -> Dict[str, Any]: + """编辑图像""" + + # 验证编辑模式 + if mode not in self.EDIT_MODES: + raise ValueError(f"不支持的编辑模式: {mode}") + + # 读取图像数据 + image_data = await image_file.read() + image_b64 = base64.b64encode(image_data).decode() + + # 构建 API 请求参数 + # 注意:Qwen-Image-Edit 不支持 strength 和 image_size 参数 + payload = { + "prompt": self._build_edit_prompt(prompt, mode), + "image": f"data:image/png;base64,{image_b64}", # 使用正确的 base64 格式 + } + + # 如果是局部编辑,添加蒙版(注意:API可能不支持mask) + if mode == "local_edit" and mask_file: + mask_data = await mask_file.read() + mask_b64 = base64.b64encode(mask_data).decode() + payload["mask_image"] = f"data:image/png;base64,{mask_b64}" + + try: + # 调用 API + result = await self.call_api(self.MODEL, payload) + + # 调试信息 + print(f"API响应结构: {type(result)}") + if isinstance(result, dict): + print(f"响应键: {list(result.keys())}") + if "images" in result: + print(f"图像数量: {len(result['images'])}") + if result["images"]: + print(f"第一个图像键: {list(result['images'][0].keys()) if isinstance(result['images'][0], dict) else '非字典类型'}") + + # 保存结果 + image_id = self.generate_image_id() + edited_image_data = result["images"][0] + + # 检查是否为字典类型 + if isinstance(edited_image_data, dict): + print(f"[DEBUG] 图像数据是字典,键: {list(edited_image_data.keys())}") + + # 优先检查URL字段 + if "url" in edited_image_data: + image_url = edited_image_data["url"] + print(f"[DEBUG] 检测到URL字段: {image_url}") + try: + image_path = await self.download_image_from_url(image_id, image_url) + print(f"[DEBUG] URL下载成功: {image_path}") + except Exception as e: + print(f"[ERROR] URL下载失败: {str(e)}") + raise Exception(f"下载图像失败: {str(e)}") + + # 如果没有URL,尝试base64字段 + elif any(key in edited_image_data for key in ["b64_json", "b64", "data"]): + image_b64 = edited_image_data.get("b64_json") or edited_image_data.get("b64") or edited_image_data.get("data") + print(f"[DEBUG] 检测到base64字段,长度: {len(image_b64) if image_b64 else 0}") + try: + image_path = self.save_image(image_id, image_b64) + print(f"[DEBUG] base64保存成功: {image_path}") + except Exception as e: + print(f"[ERROR] base64保存失败: {str(e)}") + raise Exception(f"保存图像失败: {str(e)}") + + else: + print(f"[ERROR] 未找到有效的图像数据字段") + raise Exception("API响应中未找到有效的图像数据") + + # 如果直接是字符串,判断是URL还是base64 + elif isinstance(edited_image_data, str): + print(f"[DEBUG] 图像数据是字符串,长度: {len(edited_image_data)}") + if edited_image_data.startswith('http'): + print(f"[DEBUG] 检测到URL字符串: {edited_image_data}") + try: + image_path = await self.download_image_from_url(image_id, edited_image_data) + print(f"[DEBUG] URL下载成功: {image_path}") + except Exception as e: + print(f"[ERROR] URL下载失败: {str(e)}") + raise Exception(f"下载图像失败: {str(e)}") + else: + print(f"[DEBUG] 检测到base64字符串") + try: + image_path = self.save_image(image_id, edited_image_data) + print(f"[DEBUG] base64保存成功: {image_path}") + except Exception as e: + print(f"[ERROR] base64保存失败: {str(e)}") + raise Exception(f"保存图像失败: {str(e)}") + + else: + print(f"[ERROR] 未知的图像数据类型: {type(edited_image_data)}") + raise Exception(f"不支持的图像数据类型: {type(edited_image_data)}") + + return { + "id": image_id, + "url": self.get_image_url(image_id), + "original_filename": image_file.filename, + "edit_prompt": prompt, + "mode": mode, + "metadata": { + "strength": strength, + "has_mask": mask_file is not None, + "file_path": image_path + } + } + + except Exception as e: + raise Exception(f"图像编辑失败: {str(e)}") + + async def create_variation( + self, + image_file: UploadFile, + num_variations: int = 3 + ) -> List[Dict[str, Any]]: + """生成图像变体""" + + # 读取图像数据 + image_data = await image_file.read() + image_b64 = base64.b64encode(image_data).decode() + + # 构建 API 请求参数 + payload = { + "image": image_b64, + "prompt": "create variations", + "batch_size": num_variations, + "strength": 0.6 # 变体强度 + } + + try: + # 调用 API + result = await self.call_api(self.MODEL, payload) + + # 调试信息 + print(f"API响应结构: {type(result)}") + if isinstance(result, dict): + print(f"响应键: {list(result.keys())}") + if "images" in result: + print(f"图像数量: {len(result['images'])}") + + # 处理变体结果 + variations = [] + for i, img_data in enumerate(result["images"]): + print(f"[DEBUG] 处理第 {i+1} 个变体") + image_id = self.generate_image_id() + + # 检查是否为字典类型 + if isinstance(img_data, dict): + print(f"[DEBUG] 图像数据是字典,键: {list(img_data.keys())}") + + # 优先检查URL字段 + if "url" in img_data: + image_url = img_data["url"] + print(f"[DEBUG] 检测到URL字段: {image_url}") + try: + image_path = await self.download_image_from_url(image_id, image_url) + print(f"[DEBUG] URL下载成功: {image_path}") + except Exception as e: + print(f"[ERROR] URL下载失败: {str(e)}") + raise Exception(f"下载图像失败: {str(e)}") + + # 如果没有URL,尝试base64字段 + elif any(key in img_data for key in ["b64_json", "b64", "data"]): + image_b64 = img_data.get("b64_json") or img_data.get("b64") or img_data.get("data") + print(f"[DEBUG] 检测到base64字段,长度: {len(image_b64) if image_b64 else 0}") + try: + image_path = self.save_image(image_id, image_b64) + print(f"[DEBUG] base64保存成功: {image_path}") + except Exception as e: + print(f"[ERROR] base64保存失败: {str(e)}") + raise Exception(f"保存图像失败: {str(e)}") + + else: + print(f"[ERROR] 未找到有效的图像数据字段") + raise Exception("API响应中未找到有效的图像数据") + + # 如果直接是字符串,判断是URL还是base64 + elif isinstance(img_data, str): + print(f"[DEBUG] 图像数据是字符串,长度: {len(img_data)}") + if img_data.startswith('http'): + print(f"[DEBUG] 检测到URL字符串: {img_data}") + try: + image_path = await self.download_image_from_url(image_id, img_data) + print(f"[DEBUG] URL下载成功: {image_path}") + except Exception as e: + print(f"[ERROR] URL下载失败: {str(e)}") + raise Exception(f"下载图像失败: {str(e)}") + else: + print(f"[DEBUG] 检测到base64字符串") + try: + image_path = self.save_image(image_id, img_data) + print(f"[DEBUG] base64保存成功: {image_path}") + except Exception as e: + print(f"[ERROR] base64保存失败: {str(e)}") + raise Exception(f"保存图像失败: {str(e)}") + + else: + print(f"[ERROR] 未知的图像数据类型: {type(img_data)}") + raise Exception(f"不支持的图像数据类型: {type(img_data)}") + + variations.append({ + "id": image_id, + "url": self.get_image_url(image_id), + "type": "variation", + "metadata": { + "original_filename": image_file.filename, + "file_path": image_path + } + }) + + return variations + + except Exception as e: + raise Exception(f"生成图像变体失败: {str(e)}") + + async def style_transfer( + self, + image_file: UploadFile, + style_prompt: str, + strength: float = 0.8 # 保留参数用于兼容性,但不传递给API + ) -> Dict[str, Any]: + """风格转换""" + return await self.edit_image( + image_file=image_file, + prompt=style_prompt, + mode="style_transfer" + ) + + async def optimize_image( + self, + image_file: UploadFile, + optimization_prompt: str = "优化图像质量,增强细节,提高清晰度", + strength: float = 0.6 # 保留参数用于兼容性,但不传递给API + ) -> Dict[str, Any]: + """图像优化""" + return await self.edit_image( + image_file=image_file, + prompt=optimization_prompt, + mode="optimize" + ) + + async def outpaint_image( + self, + image_file: UploadFile, + expansion_prompt: str, + strength: float = 0.7 # 保留参数用于兼容性,但不传递给API + ) -> Dict[str, Any]: + """图像智能扩展""" + return await self.edit_image( + image_file=image_file, + prompt=expansion_prompt, + mode="outpaint" + ) + + def _build_edit_prompt(self, prompt: str, mode: str) -> str: + """构建编辑提示词""" + mode_prefix = { + "optimize": "优化和增强图像质量,", + "style_transfer": "转换为以下风格:", + "local_edit": "局部修改:", + "outpaint": "智能扩展图像,保持连贯性," + } + + prefix = mode_prefix.get(mode, "") + return f"{prefix}{prompt}" + + def get_available_modes(self) -> List[Dict[str, str]]: + """获取可用的编辑模式""" + return [ + {"id": "optimize", "name": "全图优化", "description": "优化和增强图像质量,提高清晰度"}, + {"id": "style_transfer", "name": "风格转换", "description": "将图像转换为指定风格"}, + {"id": "local_edit", "name": "局部编辑", "description": "使用蒙版进行局部修改"}, + {"id": "outpaint", "name": "图像扩展", "description": "智能扩展图像边界,保持连贯性"} + ] + + def get_style_presets(self) -> List[Dict[str, str]]: + """获取预设风格选项""" + return [ + {"id": "realistic", "name": "真实感", "description": "转换为真实摄影风格"}, + {"id": "artistic", "name": "艺术化", "description": "转换为艺术绘画风格"}, + {"id": "technical", "name": "技术图", "description": "转换为技术图纸风格"}, + {"id": "sketch", "name": "素描", "description": "转换为素描手绘风格"}, + {"id": "watercolor", "name": "水彩", "description": "转换为水彩画风格"}, + {"id": "oil_painting", "name": "油画", "description": "转换为油画风格"} + ] + + async def download_image_from_url(self, image_id: str, image_url: str) -> str: + """从URL下载图像""" + try: + print(f"[DEBUG] 下载图像URL: {image_url}") + + # 下载图像 + async with httpx.AsyncClient(timeout=30) as client: + response = await client.get(image_url) + response.raise_for_status() + image_bytes = response.content + + if len(image_bytes) == 0: + raise Exception("下载的图像数据为空") + + print(f"[DEBUG] 下载图像数据大小: {len(image_bytes)} bytes") + + # 确保目录存在 + image_dir = Path(self.get_image_dir()) + image_dir.mkdir(parents=True, exist_ok=True) + + # 保存图像文件 + image_path = image_dir / f"{image_id}.png" + with open(image_path, "wb") as f: + f.write(image_bytes) + + print(f"[DEBUG] 图像已保存到: {image_path}") + return str(image_path) + + except Exception as e: + print(f"[ERROR] 下载图像失败: {str(e)}") + raise Exception(f"下载图像失败: {str(e)}") + + def get_image_dir(self) -> str: + """获取图像目录""" + from src.core.config import settings + return settings.generated_images_dir diff --git a/backend/src/services/knowledge_base_service.py b/backend/src/services/knowledge_base_service.py new file mode 100644 index 0000000..23f1e28 --- /dev/null +++ b/backend/src/services/knowledge_base_service.py @@ -0,0 +1,466 @@ +""" +知识库管理服务 +""" +import os +import hashlib +from pathlib import Path +from typing import List, Dict, Any, Optional +from datetime import datetime +from sqlalchemy.orm import Session +from sqlalchemy import and_ + +from ..models.document import Document, DocumentChunk +from ..core.config import get_settings +from .document_service import DocumentService + +settings = get_settings() + + +class KnowledgeBaseService: + """知识库管理服务""" + + def __init__(self, db: Session): + self.db = db + self.document_service = DocumentService(db) + self.knowledge_base_dir = Path(settings.knowledge_base_dir) + + def scan_directory(self, directory: Optional[str] = None) -> Dict[str, Any]: + """扫描知识库目录并批量导入""" + if directory is None: + directory = self.knowledge_base_dir + else: + directory = Path(directory) + + if not directory.exists(): + return {"success": False, "message": f"目录不存在: {directory}"} + + results = { + "scanned_files": 0, + "new_files": 0, + "updated_files": 0, + "skipped_files": 0, + "errors": [] + } + + # 递归扫描目录 + for file_path in directory.rglob("*"): + if file_path.is_file() and self._is_supported_file(file_path): + try: + result = self.process_file(str(file_path)) + results["scanned_files"] += 1 + + if result["status"] == "new": + results["new_files"] += 1 + elif result["status"] == "updated": + results["updated_files"] += 1 + elif result["status"] == "skipped": + results["skipped_files"] += 1 + elif result["status"] == "error": + results["errors"].append({ + "file": str(file_path), + "error": result["error"] + }) + + except Exception as e: + results["errors"].append({ + "file": str(file_path), + "error": str(e) + }) + + results["success"] = len(results["errors"]) == 0 + return results + + def process_file(self, file_path: str) -> Dict[str, Any]: + """处理单个文件(检查、提取、入库)""" + try: + file_path = Path(file_path) + + # 检查文件是否存在 + if not file_path.exists(): + return {"status": "error", "error": "文件不存在"} + + # 检查文件类型 + if not self._is_supported_file(file_path): + return {"status": "skipped", "message": "不支持的文件类型"} + + # 获取文件信息 + file_stat = file_path.stat() + file_size = file_stat.st_size + last_modified = datetime.fromtimestamp(file_stat.st_mtime) + + # 计算文件哈希 + file_hash = self._calculate_file_hash(file_path) + + # 检查文件是否已存在 + existing_doc = self.db.query(Document).filter( + and_( + Document.file_path == str(file_path), + Document.source_type == "knowledge_base" + ) + ).first() + + if existing_doc: + # 检查是否需要更新 + if (existing_doc.last_modified and + existing_doc.last_modified >= last_modified and + existing_doc.file_hash == file_hash): + return {"status": "skipped", "message": "文件未修改"} + + # 更新现有文档 + return self._update_document(existing_doc, file_path, file_size, last_modified, file_hash) + else: + # 创建新文档 + return self._create_document(file_path, file_size, last_modified, file_hash) + + except Exception as e: + return {"status": "error", "error": str(e)} + + def _is_supported_file(self, file_path: Path) -> bool: + """检查是否为支持的文件类型""" + return file_path.suffix.lower() in settings.allowed_extensions + + def _calculate_file_hash(self, file_path: Path) -> str: + """计算文件哈希""" + hash_md5 = hashlib.md5() + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + return hash_md5.hexdigest() + + def _create_document(self, file_path: Path, file_size: int, last_modified: datetime, file_hash: str, + knowledge_base_id: Optional[int] = None, user_id: Optional[int] = None) -> Dict[str, Any]: + """创建新文档""" + try: + # 计算相对路径用于描述 + try: + relative_path = file_path.relative_to(self.knowledge_base_dir) + except ValueError: + relative_path = file_path.name + + # 创建文档记录 + document = Document( + user_id=user_id, # 如果指定了user_id则使用,否则为None(系统文档) + knowledge_base_id=knowledge_base_id, # 关联知识库 + filename=file_path.name, + original_filename=file_path.name, + file_path=str(file_path), + file_size=file_size, + file_type=file_path.suffix.lower(), + title=file_path.stem, + description=f"知识库文档: {relative_path}", + is_processed=False, + is_public=True, + source_type="knowledge_base", + last_modified=last_modified, + file_hash=file_hash + ) + + self.db.add(document) + self.db.commit() + self.db.refresh(document) + + # 处理文档(向量化)- 在后台异步处理,不阻塞主流程 + try: + # 使用同步方法,但不等待完成(在后台处理) + import threading + def process_in_background(): + try: + self.document_service.process_document(document.id) + except Exception as e: + print(f"后台处理文档 {document.id} 失败: {e}") + + thread = threading.Thread(target=process_in_background, daemon=True) + thread.start() + except Exception as e: + print(f"启动文档处理线程失败: {e}") + + return {"status": "new", "document_id": document.id, "message": "文档创建成功,正在处理中"} + + except Exception as e: + self.db.rollback() + return {"status": "error", "error": str(e)} + + + def _update_document(self, document: Document, file_path: Path, file_size: int, last_modified: datetime, file_hash: str) -> Dict[str, Any]: + """更新现有文档""" + try: + # 更新文档信息 + document.file_size = file_size + document.last_modified = last_modified + document.file_hash = file_hash + document.is_processed = False # 标记为未处理,需要重新处理 + + # 删除旧的文档块 + self.db.query(DocumentChunk).filter(DocumentChunk.document_id == document.id).delete() + + self.db.commit() + + # 重新处理文档 - 在后台异步处理 + try: + import threading + def process_in_background(): + try: + self.document_service.process_document(document.id) + except Exception as e: + print(f"后台处理文档 {document.id} 失败: {e}") + + thread = threading.Thread(target=process_in_background, daemon=True) + thread.start() + except Exception as e: + print(f"启动文档处理线程失败: {e}") + + return {"status": "updated", "document_id": document.id, "message": "文档更新成功,正在重新处理中"} + + except Exception as e: + self.db.rollback() + return {"status": "error", "error": str(e)} + + def is_file_updated(self, file_path: str) -> bool: + """检查文件是否需要更新""" + try: + file_path = Path(file_path) + if not file_path.exists(): + return False + + # 获取文件信息 + file_stat = file_path.stat() + last_modified = datetime.fromtimestamp(file_stat.st_mtime) + file_hash = self._calculate_file_hash(file_path) + + # 查询数据库中的记录 + existing_doc = self.db.query(Document).filter( + and_( + Document.file_path == str(file_path), + Document.source_type == "knowledge_base" + ) + ).first() + + if not existing_doc: + return True # 新文件 + + # 检查修改时间和哈希 + if (existing_doc.last_modified and + existing_doc.last_modified < last_modified): + return True + + if existing_doc.file_hash != file_hash: + return True + + return False + + except Exception: + return True # 出错时默认需要更新 + + def get_knowledge_base_status(self) -> Dict[str, Any]: + """获取知识库状态""" + try: + # 统计文档数量 + total_docs = self.db.query(Document).filter( + Document.source_type == "knowledge_base" + ).count() + + processed_docs = self.db.query(Document).filter( + and_( + Document.source_type == "knowledge_base", + Document.is_processed == True + ) + ).count() + + # 统计文件大小 + total_size = self.db.query(Document).filter( + Document.source_type == "knowledge_base" + ).with_entities(Document.file_size).all() + + total_size_bytes = sum(size[0] for size in total_size) if total_size else 0 + + # 统计文件类型 + file_types = {} + docs_by_type = self.db.query(Document.file_type).filter( + Document.source_type == "knowledge_base" + ).all() + + for file_type in docs_by_type: + file_type_str = file_type[0] + file_types[file_type_str] = file_types.get(file_type_str, 0) + 1 + + return { + "total_documents": total_docs, + "processed_documents": processed_docs, + "unprocessed_documents": total_docs - processed_docs, + "total_size_bytes": total_size_bytes, + "total_size_mb": round(total_size_bytes / (1024 * 1024), 2), + "file_types": file_types, + "knowledge_base_dir": str(self.knowledge_base_dir), + "directory_exists": self.knowledge_base_dir.exists() + } + + except Exception as e: + return {"error": str(e)} + + def delete_document(self, document_id: int) -> Dict[str, Any]: + """删除知识库文档""" + try: + document = self.db.query(Document).filter( + and_( + Document.id == document_id, + Document.source_type == "knowledge_base" + ) + ).first() + + if not document: + return {"success": False, "message": "文档不存在"} + + # 删除文档块 + self.db.query(DocumentChunk).filter(DocumentChunk.document_id == document_id).delete() + + # 删除文档记录 + self.db.delete(document) + self.db.commit() + + return {"success": True, "message": "文档删除成功"} + + except Exception as e: + self.db.rollback() + return {"success": False, "message": str(e)} + + def reindex_document(self, document_id: int) -> Dict[str, Any]: + """重新索引指定文档""" + try: + document = self.db.query(Document).filter( + and_( + Document.id == document_id, + Document.source_type == "knowledge_base" + ) + ).first() + + if not document: + return {"success": False, "message": "文档不存在"} + + # 删除旧的文档块 + self.db.query(DocumentChunk).filter(DocumentChunk.document_id == document_id).delete() + + # 重新处理文档 + success = self.document_service.process_document(document_id) + + if success: + return {"success": True, "message": "文档重新索引成功"} + else: + return {"success": False, "message": "文档重新索引失败"} + + except Exception as e: + self.db.rollback() + return {"success": False, "message": str(e)} + + def import_files_to_knowledge_base( + self, + knowledge_base_id: int, + directory: Path, + user_id: Optional[int] = None + ) -> Dict[str, Any]: + """ + 从指定目录导入真实文件到知识库 + + Args: + knowledge_base_id: 知识库ID + directory: 要扫描的目录路径 + user_id: 用户ID(可选,用于系统知识库时可为None) + + Returns: + 包含统计信息的字典 + """ + if isinstance(directory, str): + directory = Path(directory) + + if not directory.exists(): + return { + "success": False, + "message": f"目录不存在: {directory}", + "scanned_files": 0, + "new_files": 0, + "updated_files": 0, + "skipped_files": 0, + "errors": [] + } + + results = { + "scanned_files": 0, + "new_files": 0, + "updated_files": 0, + "skipped_files": 0, + "errors": [] + } + + # 递归扫描目录下的所有真实文件 + all_files = [f for f in directory.rglob("*") if f.is_file() and self._is_supported_file(f)] + total_files = len(all_files) + + print(f" 找到 {total_files} 个支持的文件,开始处理...") + + for idx, file_path in enumerate(all_files, 1): + try: + # 获取文件信息 + file_stat = file_path.stat() + file_size = file_stat.st_size + last_modified = datetime.fromtimestamp(file_stat.st_mtime) + file_hash = self._calculate_file_hash(file_path) + + # 检查文件是否已存在于该知识库中 + existing_doc = self.db.query(Document).filter( + and_( + Document.file_path == str(file_path), + Document.knowledge_base_id == knowledge_base_id, + Document.source_type == "knowledge_base" + ) + ).first() + + results["scanned_files"] += 1 + + # 显示进度(每10个文件或最后一个文件时显示) + if idx % 10 == 0 or idx == total_files: + percentage = (idx * 100) // total_files if total_files > 0 else 0 + print(f"\r 处理进度: {idx}/{total_files} ({percentage}%)", end="", flush=True) + + if existing_doc: + # 检查是否需要更新 + if (existing_doc.last_modified and + existing_doc.last_modified >= last_modified and + existing_doc.file_hash == file_hash): + results["skipped_files"] += 1 + continue + + # 更新现有文档 + result = self._update_document(existing_doc, file_path, file_size, last_modified, file_hash) + if result["status"] == "updated": + results["updated_files"] += 1 + else: + results["errors"].append({ + "file": str(file_path), + "error": result.get("error", "更新失败") + }) + else: + # 创建新文档 + result = self._create_document( + file_path, + file_size, + last_modified, + file_hash, + knowledge_base_id=knowledge_base_id, + user_id=user_id + ) + if result["status"] == "new": + results["new_files"] += 1 + else: + results["errors"].append({ + "file": str(file_path), + "error": result.get("error", "创建失败") + }) + + except Exception as e: + results["errors"].append({ + "file": str(file_path), + "error": str(e) + }) + + print() # 换行 + results["success"] = len(results["errors"]) == 0 + return results diff --git a/backend/src/services/latex_parser.py b/backend/src/services/latex_parser.py new file mode 100644 index 0000000..8aadbe9 --- /dev/null +++ b/backend/src/services/latex_parser.py @@ -0,0 +1,326 @@ +""" +LaTeX文件解析器 +解析章节文件,提取章节、节、小节的标题和内容 +层级结构:书籍 -> Chapter -> Section -> Subsection(知识点) +""" +import re +from pathlib import Path +from typing import List, Dict, Any + + +class LaTeXParser: + """LaTeX解析器""" + + def __init__(self, base_dir: Path): + """ + 初始化解析器 + + Args: + base_dir: 书籍目录路径 + """ + self.base_dir = base_dir + + def parse_chapter_file(self, file_path: Path) -> List[Dict[str, Any]]: + """ + 解析单个LaTeX章节文件,提取章节、节、小节的标题和行号。 + + 层级结构: + - \chapter{} -> Chapter + - \section{} -> Section + - \subsection{} -> Subsection(知识点,包含其下所有subsubsection内容) + - \subsubsection{} -> 忽略,内容合并到subsection中 + + Returns: + 包含章节结构的列表,格式: + [{ + "type": "chapter", + "title": "...", + "start_line": 1, + "end_line": 100, + "sections": [ + { + "type": "section", + "title": "...", + "start_line": 5, + "end_line": 50, + "subsections": [ + { + "type": "subsection", + "title": "...", + "start_line": 10, + "end_line": 30, + "subsection_number": 1 + } + ], + "section_number": 1 + } + ], + "chapter_number": 1 + }] + """ + content = file_path.read_text(encoding='utf-8') + lines = content.splitlines() + structure = [] + + # Regex for \chapter, \section, \subsection, \subsubsection + chapter_re = re.compile(r'^\\chapter\*?{(.*?)}') + section_re = re.compile(r'^\\section\*?{(.*?)}') + subsection_re = re.compile(r'^\\subsection\*?{(.*?)}') + subsubsection_re = re.compile(r'^\\subsubsection\*?{(.*?)}') + + current_chapter = None + current_section = None + current_subsection = None + + for i, line in enumerate(lines): + line_num = i + 1 # 1-based line number + + # Try to match chapter first (highest level) + match_chapter = chapter_re.match(line) + if match_chapter: + # Finalize previous chapter's end_line + if current_chapter: + if current_section: + current_section["end_line"] = line_num - 1 + current_chapter["end_line"] = line_num - 1 + + title = match_chapter.group(1).strip() + # Extract chapter number from filename if possible + chapter_num_match = re.search(r'chapter(\d+)', file_path.name) + chapter_number = int(chapter_num_match.group(1)) if chapter_num_match else len(structure) + 1 + + current_chapter = { + "type": "chapter", + "title": title, + "start_line": line_num, + "end_line": line_num, # Will be updated later + "chapter_number": chapter_number, + "sections": [] + } + structure.append(current_chapter) + current_section = None + current_subsection = None + continue + + # Try to match section + match_section = section_re.match(line) + if match_section: + # Finalize previous section's end_line + if current_section: + if current_subsection: + current_subsection["end_line"] = line_num - 1 + current_section["end_line"] = line_num - 1 + + title = match_section.group(1).strip() + # Remove numbering if present in title + title = re.sub(r'^\d+(\.\d+)*\.\s*', '', title) + + if current_chapter: + section_number = len(current_chapter["sections"]) + 1 + current_section = { + "type": "section", + "title": title, + "start_line": line_num, + "end_line": line_num, # Will be updated later + "section_number": section_number, + "subsections": [] + } + current_chapter["sections"].append(current_section) + current_subsection = None + continue + + # Try to match subsection (知识点) + match_subsection = subsection_re.match(line) + if match_subsection: + # Finalize previous subsection's end_line + if current_subsection and current_section: + current_subsection["end_line"] = line_num - 1 + + title = match_subsection.group(1).strip() + # Remove numbering if present in title + title = re.sub(r'^\d+(\.\d+)*\.\s*', '', title) + + # Ensure current_section exists before adding subsection + if current_section: + subsection_number = len(current_section["subsections"]) + 1 + current_subsection = { + "type": "subsection", + "title": title, + "start_line": line_num, + "end_line": line_num, # Will be updated later, includes all subsubsections + "subsection_number": subsection_number + } + current_section["subsections"].append(current_subsection) + continue + + # Try to match subsubsection (忽略,但内容会包含在subsection中) + match_subsubsection = subsubsection_re.match(line) + if match_subsubsection: + # Subsubsection内容会被包含在当前subsection中 + # 不需要单独处理,subsection的end_line会包含所有subsubsection + continue + + # Finalize the end_line for the last chapter/section/subsection + if current_chapter: + if current_section: + if current_subsection: + current_subsection["end_line"] = len(lines) + current_section["end_line"] = len(lines) + current_chapter["end_line"] = len(lines) + + # Post-process to ensure end_lines are correctly set for all elements + for chap in structure: + if chap["end_line"] == chap["start_line"]: + chap["end_line"] = len(lines) + for sec in chap["sections"]: + if sec["end_line"] == sec["start_line"]: + sec["end_line"] = len(lines) + for sub in sec["subsections"]: + if sub["end_line"] == sub["start_line"]: + # Find next subsection or end of section + next_subsection_start = None + for other_sub in sec["subsections"]: + if other_sub["start_line"] > sub["start_line"]: + next_subsection_start = other_sub["start_line"] + break + if next_subsection_start: + sub["end_line"] = next_subsection_start - 1 + else: + sub["end_line"] = sec["end_line"] + + return structure + + def get_content_by_lines(self, file_path: Path, start_line: int, end_line: int) -> str: + """ + 从指定文件的指定行范围读取内容。 + 包含subsection及其下所有subsubsection的内容。 + """ + if not file_path.exists(): + return "" + + lines = file_path.read_text(encoding='utf-8').splitlines() + + # Adjust for 0-based indexing in Python list + start_idx = max(0, start_line - 1) + end_idx = min(len(lines), end_line) + + content_lines = lines[start_idx:end_idx] + + # 移除LaTeX命令,只保留纯文本 + cleaned_content = self._clean_latex_commands("\n".join(content_lines)) + return cleaned_content + + def _convert_latex_table_to_markdown(self, table_content: str) -> str: + """ + 将LaTeX表格转换为Markdown格式。 + + Args: + table_content: LaTeX表格内容(不包含\begin{tabular}和\end{tabular}) + + Returns: + Markdown格式的表格字符串 + """ + if not table_content: + return "" + + # 先按 \\ 分割行(LaTeX表格使用 \\ 作为行分隔符) + raw_lines = table_content.split('\\\\') + rows = [] + + for raw_line in raw_lines: + line = raw_line.strip() + # 移除行内的 \hline 命令 + line = re.sub(r'\\hline', '', line) + if not line: + continue + + # 分割单元格(使用 & 分隔符) + cells = [cell.strip() for cell in line.split('&')] + + # 清理单元格内容(移除LaTeX命令) + cleaned_cells = [] + for cell in cells: + # 移除常见的LaTeX命令,但保留文本内容 + cell = re.sub(r'\\(textbf|textit|emph|text)\{([^}]+)\}', r'\2', cell) + # 移除其他带大括号的命令 + cell = re.sub(r'\\[a-zA-Z]+\{[^}]*\}', '', cell) + # 移除单独的LaTeX命令 + cell = re.sub(r'\\([a-zA-Z]+)', '', cell) + cell = cell.strip() + cleaned_cells.append(cell) + + # 过滤掉空行 + if cleaned_cells and any(cell for cell in cleaned_cells): + rows.append(cleaned_cells) + + if not rows: + return "" + + # 转换为Markdown表格 + markdown_lines = [] + + # 表头(第一行) + if rows: + header = rows[0] + if not header or not any(header): + if len(rows) > 1: + header = rows[1] + rows = rows[1:] + else: + return "" + + markdown_lines.append('| ' + ' | '.join(header) + ' |') + markdown_lines.append('| ' + ' | '.join(['---'] * len(header)) + ' |') + + # 数据行(跳过表头) + for row in rows[1:]: + while len(row) < len(header): + row.append('') + markdown_lines.append('| ' + ' | '.join(row[:len(header)]) + ' |') + + return '\n'.join(markdown_lines) + + def _clean_latex_commands(self, text: str) -> str: + """ + 移除LaTeX命令和环境,保留纯文本。 + 注意:保留段落文本内容和表格(转换为Markdown格式)。 + """ + if not text: + return "" + + # 移除 \chapter{}, \section{}, \subsection{}, \subsubsection{} 命令行 + text = re.sub(r'^\s*\\(chapter|section|subsection|subsubsection)\*?{.*?}\s*$', '', text, flags=re.MULTILINE) + # 移除 \label{}, \ref{}, \cite{} 等命令(但保留内容) + text = re.sub(r'\\label\{[^}]+\}', '', text) + text = re.sub(r'\\ref\{[^}]+\}', '', text) + text = re.sub(r'\\cite\{[^}]+\}', '', text) + + # 处理表格:将LaTeX表格转换为Markdown表格 + def replace_table(match): + table_content = match.group(0) + # 提取tabular环境内容 + tabular_pattern = r'\\begin\{tabular\}[^{]*\{[^}]*\}(.*?)\\end\{tabular\}' + tabular_match = re.search(tabular_pattern, table_content, re.DOTALL) + if tabular_match: + inner_content = tabular_match.group(1) + markdown_table = self._convert_latex_table_to_markdown(inner_content) + return '\n\n' + markdown_table + '\n\n' if markdown_table else '' + return '' + + # 先处理完整的table环境(包含tabular) + text = re.sub(r'\\begin\{table\}.*?\\end\{table\}', replace_table, text, flags=re.DOTALL) + # 再处理单独的tabular环境(如果table环境没有匹配到) + text = re.sub(r'\\begin\{tabular\}.*?\\end\{tabular\}', replace_table, text, flags=re.DOTALL) + + # 移除图片环境 + text = re.sub(r'\\begin\{figure\}.*?\\end\{figure\}', '', text, flags=re.DOTALL) + # 移除表格相关的LaTeX命令 + text = re.sub(r'\\(centering|caption|toprule|midrule|bottomrule|hline)\b', '', text) + # 移除注释 + text = re.sub(r'%.*$', '', text, flags=re.MULTILINE) + # 移除多余的空行(保留段落间的空行) + text = re.sub(r'\n{3,}', '\n\n', text) + # 移除行首尾的空白 + lines = [line.strip() for line in text.split('\n')] + text = '\n'.join(lines) + return text.strip() diff --git a/backend/src/services/text_to_image_service.py b/backend/src/services/text_to_image_service.py new file mode 100644 index 0000000..f9c28f1 --- /dev/null +++ b/backend/src/services/text_to_image_service.py @@ -0,0 +1,253 @@ +""" +文生图服务 +支持 Kwai-Kolors/Kolors 和 Qwen/Qwen-Image 模型 +""" + +import uuid +import httpx +from typing import List, Dict, Any +from pathlib import Path +from .image_generation_service import ImageGenerationService + + +class TextToImageService(ImageGenerationService): + """文生图服务""" + + MODELS = { + "kolors": "Kwai-Kolors/Kolors", + "qwen": "Qwen/Qwen-Image" + } + + PROMPT_TEMPLATES = { + "urban_planning": "城市总体规划图,{prompt},鸟瞰视角,清晰的功能分区,道路网络完整", + "land_use": "土地利用规划图,{prompt},色块清晰,图例完整,专业制图风格", + "ecological": "生态保护规划图,{prompt},生态敏感区标注,绿色基调,自然元素", + "transportation": "交通规划图,{prompt},路网清晰,站点标注,流线设计", + "custom": "{prompt}" + } + + STYLE_ENHANCEMENTS = { + "realistic": "高清真实感,专业摄影风格,细节丰富", + "conceptual": "概念设计图,简洁明了,设计感强,现代风格", + "technical": "技术图纸风格,精确详细,工程制图,CAD风格", + "artistic": "艺术化表现,创意设计,视觉冲击力强,插画风格", + "schematic": "示意图风格,清晰标注,信息传达准确,图表化" + } + + SIZE_OPTIONS = { + "512x512": "512x512", + "1024x1024": "1024x1024", + "1024x1792": "1024x1792", + "1792x1024": "1792x1024" + } + + async def generate( + self, + prompt: str, + model: str = "kolors", + template: str = "custom", + style: str = "realistic", + size: str = "1024x1024", + num_images: int = 1 + ) -> List[Dict[str, Any]]: + """生成图像""" + + # 验证模型 + if model not in self.MODELS: + raise ValueError(f"不支持的模型: {model}") + + # 构建增强提示词 + enhanced_prompt = self._build_prompt(prompt, template, style) + + # 构建 API 请求参数 + payload = { + "prompt": enhanced_prompt, + "image_size": size, + "num_inference_steps": 50, + "guidance_scale": 7.5, + "batch_size": num_images + } + + try: + # 调用 API + result = await self.call_api(self.MODELS[model], payload) + + # 调试信息 + print(f"API响应结构: {type(result)}") + if isinstance(result, dict): + print(f"响应键: {list(result.keys())}") + if "images" in result: + print(f"图像数量: {len(result['images'])}") + if result["images"]: + print(f"第一个图像键: {list(result['images'][0].keys()) if isinstance(result['images'][0], dict) else '非字典类型'}") + + # 处理结果 + images = [] + for i, img_data in enumerate(result.get("images", [])): + print(f"[DEBUG] 处理第 {i+1} 张图像") + image_id = self.generate_image_id() + + # 检查是否为字典类型 + if isinstance(img_data, dict): + print(f"[DEBUG] 图像数据是字典,键: {list(img_data.keys())}") + + # 优先检查URL字段 + if "url" in img_data: + image_url = img_data["url"] + print(f"[DEBUG] 检测到URL字段: {image_url}") + try: + image_path = await self.download_image_from_url(image_id, image_url) + print(f"[DEBUG] URL下载成功: {image_path}") + except Exception as e: + print(f"[ERROR] URL下载失败: {str(e)}") + raise Exception(f"下载图像失败: {str(e)}") + + # 如果没有URL,尝试base64字段 + elif any(key in img_data for key in ["b64_json", "b64", "data"]): + image_b64 = img_data.get("b64_json") or img_data.get("b64") or img_data.get("data") + print(f"[DEBUG] 检测到base64字段,长度: {len(image_b64) if image_b64 else 0}") + try: + image_path = self.save_image(image_id, image_b64) + print(f"[DEBUG] base64保存成功: {image_path}") + except Exception as e: + print(f"[ERROR] base64保存失败: {str(e)}") + raise Exception(f"保存图像失败: {str(e)}") + + else: + print(f"[ERROR] 未找到有效的图像数据字段") + raise Exception("API响应中未找到有效的图像数据") + + # 如果直接是字符串,判断是URL还是base64 + elif isinstance(img_data, str): + print(f"[DEBUG] 图像数据是字符串,长度: {len(img_data)}") + if img_data.startswith('http'): + print(f"[DEBUG] 检测到URL字符串: {img_data}") + try: + image_path = await self.download_image_from_url(image_id, img_data) + print(f"[DEBUG] URL下载成功: {image_path}") + except Exception as e: + print(f"[ERROR] URL下载失败: {str(e)}") + raise Exception(f"下载图像失败: {str(e)}") + else: + print(f"[DEBUG] 检测到base64字符串") + try: + image_path = self.save_image(image_id, img_data) + print(f"[DEBUG] base64保存成功: {image_path}") + except Exception as e: + print(f"[ERROR] base64保存失败: {str(e)}") + raise Exception(f"保存图像失败: {str(e)}") + + else: + print(f"[ERROR] 未知的图像数据类型: {type(img_data)}") + raise Exception(f"不支持的图像数据类型: {type(img_data)}") + + images.append({ + "id": image_id, + "url": self.get_image_url(image_id), + "prompt": enhanced_prompt, + "model": model, + "metadata": { + "original_prompt": prompt, + "template": template, + "style": style, + "size": size, + "file_path": image_path + } + }) + + return images + + except Exception as e: + raise Exception(f"图像生成失败: {str(e)}") + + def _build_prompt(self, prompt: str, template: str, style: str) -> str: + """构建增强提示词""" + # 应用模板 + if template in self.PROMPT_TEMPLATES: + templated_prompt = self.PROMPT_TEMPLATES[template].format(prompt=prompt) + else: + templated_prompt = prompt + + # 添加风格描述 + style_desc = self.STYLE_ENHANCEMENTS.get(style, "") + + # 组合最终提示词 + if style_desc: + final_prompt = f"{templated_prompt},{style_desc}" + else: + final_prompt = templated_prompt + + return final_prompt + + async def download_image_from_url(self, image_id: str, image_url: str) -> str: + """从URL下载图像""" + try: + print(f"[DEBUG] 下载图像URL: {image_url}") + + # 下载图像 + async with httpx.AsyncClient(timeout=30) as client: + response = await client.get(image_url) + response.raise_for_status() + image_bytes = response.content + + if len(image_bytes) == 0: + raise Exception("下载的图像数据为空") + + print(f"[DEBUG] 下载图像数据大小: {len(image_bytes)} bytes") + + # 确保目录存在 + image_dir = Path(self.get_image_dir()) + image_dir.mkdir(parents=True, exist_ok=True) + + # 保存图像文件 + image_path = image_dir / f"{image_id}.png" + with open(image_path, "wb") as f: + f.write(image_bytes) + + print(f"[DEBUG] 图像已保存到: {image_path}") + return str(image_path) + + except Exception as e: + print(f"[ERROR] 下载图像失败: {str(e)}") + raise Exception(f"下载图像失败: {str(e)}") + + def get_image_dir(self) -> str: + """获取图像目录""" + from src.core.config import settings + return settings.generated_images_dir + + def get_available_models(self) -> List[Dict[str, str]]: + """获取可用的模型列表""" + return [ + {"id": "kolors", "name": "Kwai-Kolors/Kolors", "description": "快手可图,中英双语,高质量生成"}, + {"id": "qwen", "name": "Qwen/Qwen-Image", "description": "通义万象,多场景支持,快速生成"} + ] + + def get_available_templates(self) -> List[Dict[str, str]]: + """获取可用的提示词模板""" + return [ + {"id": "custom", "name": "自定义", "description": "直接使用用户输入的提示词"}, + {"id": "urban_planning", "name": "城市规划", "description": "城市总体规划图,鸟瞰视角,功能分区清晰"}, + {"id": "land_use", "name": "土地利用", "description": "土地利用规划图,色块清晰,专业制图风格"}, + {"id": "ecological", "name": "生态保护", "description": "生态保护规划图,生态敏感区标注,绿色基调"}, + {"id": "transportation", "name": "交通规划", "description": "交通规划图,路网清晰,站点标注,流线设计"} + ] + + def get_available_styles(self) -> List[Dict[str, str]]: + """获取可用的风格选项""" + return [ + {"id": "realistic", "name": "真实感", "description": "高清真实感,专业摄影风格,细节丰富"}, + {"id": "conceptual", "name": "概念图", "description": "概念设计图,简洁明了,设计感强,现代风格"}, + {"id": "technical", "name": "技术图", "description": "技术图纸风格,精确详细,工程制图,CAD风格"}, + {"id": "artistic", "name": "艺术化", "description": "艺术化表现,创意设计,视觉冲击力强,插画风格"}, + {"id": "schematic", "name": "示意图", "description": "示意图风格,清晰标注,信息传达准确,图表化"} + ] + + def get_available_sizes(self) -> List[Dict[str, str]]: + """获取可用的尺寸选项""" + return [ + {"id": "512x512", "name": "512×512", "description": "正方形,适合头像和图标"}, + {"id": "1024x1024", "name": "1024×1024", "description": "高清正方形,适合详细图像"}, + {"id": "1024x1792", "name": "1024×1792", "description": "竖版,适合海报和长图"}, + {"id": "1792x1024", "name": "1792×1024", "description": "横版,适合横幅和全景图"} + ] diff --git a/backend/uv.lock b/backend/uv.lock new file mode 100644 index 0000000..dde4bb1 --- /dev/null +++ b/backend/uv.lock @@ -0,0 +1,4358 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" +resolution-markers = [ + "python_full_version >= '3.13'", + "python_full_version < '3.13'", +] + +[[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.0" +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/62/f1/8515650ac3121a9e55c7b217c60e7fae3e0134b5acfe65691781b5356929/aiohttp-3.13.0.tar.gz", hash = "sha256:378dbc57dd8cf341ce243f13fa1fa5394d68e2e02c15cd5f28eae35a70ec7f67", size = 7832348, upload-time = "2025-10-06T19:58:48.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/95/7e8bdfa6e79099a086d59d42589492f1fe9d29aae3cefb58b676015ce278/aiohttp-3.13.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1c272a9a18a5ecc48a7101882230046b83023bb2a662050ecb9bfcb28d9ab53a", size = 735585, upload-time = "2025-10-06T19:55:43.401Z" }, + { url = "https://files.pythonhosted.org/packages/9f/20/2f1d3ee06ee94eafe516810705219bff234d09f135d6951661661d5595ae/aiohttp-3.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:97891a23d7fd4e1afe9c2f4473e04595e4acb18e4733b910b6577b74e7e21985", size = 490613, upload-time = "2025-10-06T19:55:45.237Z" }, + { url = "https://files.pythonhosted.org/packages/74/15/ab8600ef6dc1dcd599009a81acfed2ea407037e654d32e47e344e0b08c34/aiohttp-3.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:475bd56492ce5f4cffe32b5533c6533ee0c406d1d0e6924879f83adcf51da0ae", size = 489750, upload-time = "2025-10-06T19:55:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/33/59/752640c2b86ca987fe5703a01733b00d375e6cd2392bc7574489934e64e5/aiohttp-3.13.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c32ada0abb4bc94c30be2b681c42f058ab104d048da6f0148280a51ce98add8c", size = 1736812, upload-time = "2025-10-06T19:55:48.917Z" }, + { url = "https://files.pythonhosted.org/packages/3d/c6/dd6b86ddb852a7fdbcdc7a45b6bdc80178aef713c08279afcaee7a5a9f07/aiohttp-3.13.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4af1f8877ca46ecdd0bc0d4a6b66d4b2bddc84a79e2e8366bc0d5308e76bceb8", size = 1698535, upload-time = "2025-10-06T19:55:50.75Z" }, + { url = "https://files.pythonhosted.org/packages/33/e2/27c92d205b9e8cee7661670e8e9f187931b71e26d42796b153d2a0ba6949/aiohttp-3.13.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e04ab827ec4f775817736b20cdc8350f40327f9b598dec4e18c9ffdcbea88a93", size = 1766573, upload-time = "2025-10-06T19:55:53.106Z" }, + { url = "https://files.pythonhosted.org/packages/df/6a/1fc1ad71d130a30f7a207d8d958a41224c29b834463b5185efb2dbff6ad4/aiohttp-3.13.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a6d9487b9471ec36b0faedf52228cd732e89be0a2bbd649af890b5e2ce422353", size = 1865229, upload-time = "2025-10-06T19:55:55.01Z" }, + { url = "https://files.pythonhosted.org/packages/14/51/d0c1701a79fcb0109cff5304da16226581569b89a282d8e7f1549a7e3ec0/aiohttp-3.13.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e66c57416352f36bf98f6641ddadd47c93740a22af7150d3e9a1ef6e983f9a8", size = 1750379, upload-time = "2025-10-06T19:55:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3d/2ec4b934f85856de1c0c18e90adc8902adadbfac2b3c0b831bfeb7214fc8/aiohttp-3.13.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:469167d5372f5bb3aedff4fc53035d593884fff2617a75317740e885acd48b04", size = 1560798, upload-time = "2025-10-06T19:55:58.888Z" }, + { url = "https://files.pythonhosted.org/packages/38/56/e23d9c3e13006e599fdce3851517c70279e177871e3e567d22cf3baf5d6c/aiohttp-3.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a9f3546b503975a69b547c9fd1582cad10ede1ce6f3e313a2f547c73a3d7814f", size = 1697552, upload-time = "2025-10-06T19:56:01.172Z" }, + { url = "https://files.pythonhosted.org/packages/56/cb/caa32c2ccaeca0a3dc39129079fd2ad02f9406c3a5f7924340435b87d4cd/aiohttp-3.13.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6b4174fcec98601f0cfdf308ee29a6ae53c55f14359e848dab4e94009112ee7d", size = 1718609, upload-time = "2025-10-06T19:56:03.102Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c0/5911856fef9e40fd1ccbb8c54a90116875d5753a92c1cac66ce2059b390d/aiohttp-3.13.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a533873a7a4ec2270fb362ee5a0d3b98752e4e1dc9042b257cd54545a96bd8ed", size = 1735887, upload-time = "2025-10-06T19:56:04.841Z" }, + { url = "https://files.pythonhosted.org/packages/0e/48/8d6f4757a24c02f0a454c043556593a00645d10583859f7156db44d8b7d3/aiohttp-3.13.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ce887c5e54411d607ee0959cac15bb31d506d86a9bcaddf0b7e9d63325a7a802", size = 1553079, upload-time = "2025-10-06T19:56:07.197Z" }, + { url = "https://files.pythonhosted.org/packages/39/fa/e82c9445e40b50e46770702b5b6ca2f767966d53e1a5eef03583ceac6df6/aiohttp-3.13.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d871f6a30d43e32fc9252dc7b9febe1a042b3ff3908aa83868d7cf7c9579a59b", size = 1762750, upload-time = "2025-10-06T19:56:09.376Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e6/9d30554e7f1e700bfeae4ab6b153d5dc7441606a9ec5e929288fa93a1477/aiohttp-3.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:222c828243b4789d79a706a876910f656fad4381661691220ba57b2ab4547865", size = 1717461, upload-time = "2025-10-06T19:56:11.551Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e5/29cca547990a59ea54f0674fc01de98519fc628cfceeab6175711750eca7/aiohttp-3.13.0-cp312-cp312-win32.whl", hash = "sha256:682d2e434ff2f1108314ff7f056ce44e457f12dbed0249b24e106e385cf154b9", size = 424633, upload-time = "2025-10-06T19:56:13.316Z" }, + { url = "https://files.pythonhosted.org/packages/8b/68/46dd042d7bc62eab30bafdb8569f55ef125c3a88bb174270324224f8df56/aiohttp-3.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:0a2be20eb23888df130214b91c262a90e2de1553d6fb7de9e9010cec994c0ff2", size = 451401, upload-time = "2025-10-06T19:56:15.188Z" }, + { url = "https://files.pythonhosted.org/packages/86/2c/ac53efdc9c10e41399acc2395af98f835b86d0141d5c3820857eb9f6a14a/aiohttp-3.13.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:00243e51f16f6ec0fb021659d4af92f675f3cf9f9b39efd142aa3ad641d8d1e6", size = 730090, upload-time = "2025-10-06T19:56:16.858Z" }, + { url = "https://files.pythonhosted.org/packages/13/18/1ac95683e1c1d48ef4503965c96f5401618a04c139edae12e200392daae8/aiohttp-3.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:059978d2fddc462e9211362cbc8446747ecd930537fa559d3d25c256f032ff54", size = 488041, upload-time = "2025-10-06T19:56:18.659Z" }, + { url = "https://files.pythonhosted.org/packages/fd/79/ef0d477c771a642d1a881b92d226314c43d3c74bc674c93e12e679397a97/aiohttp-3.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:564b36512a7da3b386143c611867e3f7cfb249300a1bf60889bd9985da67ab77", size = 486989, upload-time = "2025-10-06T19:56:20.371Z" }, + { url = "https://files.pythonhosted.org/packages/37/b4/0e440481a0e77a551d6c5dcab5d11f1ff6b2b2ddb8dedc24f54f5caad732/aiohttp-3.13.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4aa995b9156ae499393d949a456a7ab0b994a8241a96db73a3b73c7a090eff6a", size = 1718331, upload-time = "2025-10-06T19:56:22.188Z" }, + { url = "https://files.pythonhosted.org/packages/e6/59/76c421cc4a75bb1aceadb92f20ee6f05a990aa6960c64b59e8e0d340e3f5/aiohttp-3.13.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55ca0e95a3905f62f00900255ed807c580775174252999286f283e646d675a49", size = 1686263, upload-time = "2025-10-06T19:56:24.393Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ac/5095f12a79c7775f402cfc3e83651b6e0a92ade10ddf7f2c78c4fed79f71/aiohttp-3.13.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:49ce7525853a981fc35d380aa2353536a01a9ec1b30979ea4e35966316cace7e", size = 1754265, upload-time = "2025-10-06T19:56:26.365Z" }, + { url = "https://files.pythonhosted.org/packages/05/d7/a48e4989bd76cc70600c505bbdd0d90ca1ad7f9053eceeb9dbcf9345a9ec/aiohttp-3.13.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2117be9883501eaf95503bd313eb4c7a23d567edd44014ba15835a1e9ec6d852", size = 1856486, upload-time = "2025-10-06T19:56:28.438Z" }, + { url = "https://files.pythonhosted.org/packages/1e/02/45b388b49e37933f316e1fb39c0de6fb1d77384b0c8f4cf6af5f2cbe3ea6/aiohttp-3.13.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d169c47e40c911f728439da853b6fd06da83761012e6e76f11cb62cddae7282b", size = 1737545, upload-time = "2025-10-06T19:56:30.688Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a7/4fde058f1605c34a219348a83a99f14724cc64e68a42480fc03cf40f9ea3/aiohttp-3.13.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:703ad3f742fc81e543638a7bebddd35acadaa0004a5e00535e795f4b6f2c25ca", size = 1552958, upload-time = "2025-10-06T19:56:32.528Z" }, + { url = "https://files.pythonhosted.org/packages/d1/12/0bac4d29231981e3aa234e88d1931f6ba38135ff4c2cf3afbb7895527630/aiohttp-3.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bf635c3476f4119b940cc8d94ad454cbe0c377e61b4527f0192aabeac1e9370", size = 1681166, upload-time = "2025-10-06T19:56:34.81Z" }, + { url = "https://files.pythonhosted.org/packages/71/95/b829eb5f8ac1ca1d8085bb8df614c8acf3ff32e23ad5ad1173c7c9761daa/aiohttp-3.13.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:cfe6285ef99e7ee51cef20609be2bc1dd0e8446462b71c9db8bb296ba632810a", size = 1710516, upload-time = "2025-10-06T19:56:36.787Z" }, + { url = "https://files.pythonhosted.org/packages/47/6d/15ccf4ef3c254d899f62580e0c7fc717014f4d14a3ac31771e505d2c736c/aiohttp-3.13.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8af6391c5f2e69749d7f037b614b8c5c42093c251f336bdbfa4b03c57d6c4", size = 1731354, upload-time = "2025-10-06T19:56:38.659Z" }, + { url = "https://files.pythonhosted.org/packages/46/6a/8acf6c57e03b6fdcc8b4c06392e66abaff3213ea275e41db3edb20738d91/aiohttp-3.13.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:12f5d820fadc5848d4559ea838aef733cf37ed2a1103bba148ac2f5547c14c29", size = 1548040, upload-time = "2025-10-06T19:56:40.578Z" }, + { url = "https://files.pythonhosted.org/packages/75/7d/fbfd59ab2a83fe2578ce79ac3db49727b81e9f4c3376217ad09c03c6d279/aiohttp-3.13.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f1338b61ea66f4757a0544ed8a02ccbf60e38d9cfb3225888888dd4475ebb96", size = 1756031, upload-time = "2025-10-06T19:56:42.492Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/cc9f0fdf06cab3ca61e6b62bff9a4b978b8ca736e9d76ddf54365673ab19/aiohttp-3.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:582770f82513419512da096e8df21ca44f86a2e56e25dc93c5ab4df0fe065bf0", size = 1714933, upload-time = "2025-10-06T19:56:45.542Z" }, + { url = "https://files.pythonhosted.org/packages/db/43/7abbe1de94748a58a71881163ee280fd3217db36e8344d109f63638fe16a/aiohttp-3.13.0-cp313-cp313-win32.whl", hash = "sha256:3194b8cab8dbc882f37c13ef1262e0a3d62064fa97533d3aa124771f7bf1ecee", size = 423799, upload-time = "2025-10-06T19:56:47.779Z" }, + { url = "https://files.pythonhosted.org/packages/c9/58/afab7f2b9e7df88c995995172eb78cae8a3d5a62d5681abaade86b3f0089/aiohttp-3.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:7897298b3eedc790257fef8a6ec582ca04e9dbe568ba4a9a890913b925b8ea21", size = 450138, upload-time = "2025-10-06T19:56:49.49Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c1/93bb1e35cd0c4665bb422b1ca3d87b588f4bca2656bbe9292b963d5b76a9/aiohttp-3.13.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c417f8c2e1137775569297c584a8a7144e5d1237789eae56af4faf1894a0b861", size = 733187, upload-time = "2025-10-06T19:56:51.385Z" }, + { url = "https://files.pythonhosted.org/packages/5e/36/2d50eba91992d3fe7a6452506ccdab45d03685ee8d8acaa5b289384a7d4c/aiohttp-3.13.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f84b53326abf8e56ebc28a35cebf4a0f396a13a76300f500ab11fe0573bf0b52", size = 488684, upload-time = "2025-10-06T19:56:53.25Z" }, + { url = "https://files.pythonhosted.org/packages/82/93/fa4b1d5ecdc7805bdf0815ef00257db4632ccf0a8bffd44f9fc4657b1677/aiohttp-3.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:990a53b9d6a30b2878789e490758e568b12b4a7fb2527d0c89deb9650b0e5813", size = 489255, upload-time = "2025-10-06T19:56:55.136Z" }, + { url = "https://files.pythonhosted.org/packages/05/0f/85241f0d158da5e24e8ac9d50c0849ed24f882cafc53dc95749ef85eef09/aiohttp-3.13.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c811612711e01b901e18964b3e5dec0d35525150f5f3f85d0aee2935f059910a", size = 1715914, upload-time = "2025-10-06T19:56:57.286Z" }, + { url = "https://files.pythonhosted.org/packages/ab/fc/c755590d6f6d2b5d1565c72d6ee658d3c30ec61acb18964d1e9bf991d9b5/aiohttp-3.13.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee433e594d7948e760b5c2a78cc06ac219df33b0848793cf9513d486a9f90a52", size = 1665171, upload-time = "2025-10-06T19:56:59.688Z" }, + { url = "https://files.pythonhosted.org/packages/3a/de/caa61e213ff546b8815aef5e931d7eae1dbe8c840a3f11ec5aa41c5ae462/aiohttp-3.13.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:19bb08e56f57c215e9572cd65cb6f8097804412c54081d933997ddde3e5ac579", size = 1755124, upload-time = "2025-10-06T19:57:02.69Z" }, + { url = "https://files.pythonhosted.org/packages/fb/b7/40c3219dd2691aa35cf889b4fbb0c00e48a19092928707044bfe92068e01/aiohttp-3.13.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f27b7488144eb5dd9151cf839b195edd1569629d90ace4c5b6b18e4e75d1e63a", size = 1835949, upload-time = "2025-10-06T19:57:05.251Z" }, + { url = "https://files.pythonhosted.org/packages/57/e8/66e3c32841fc0e26a09539c377aa0f3bbf6deac1957ac5182cf276c5719c/aiohttp-3.13.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d812838c109757a11354a161c95708ae4199c4fd4d82b90959b20914c1d097f6", size = 1714276, upload-time = "2025-10-06T19:57:07.41Z" }, + { url = "https://files.pythonhosted.org/packages/6b/a5/c68e5b46ff0410fe3abfa508651b09372428f27036138beacf4ff6b7cb8c/aiohttp-3.13.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7c20db99da682f9180fa5195c90b80b159632fb611e8dbccdd99ba0be0970620", size = 1545929, upload-time = "2025-10-06T19:57:09.336Z" }, + { url = "https://files.pythonhosted.org/packages/7a/a6/4c97dc27f9935c0c0aa6e3e10e5b4548823ab5d056636bde374fcd297256/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cf8b0870047900eb1f17f453b4b3953b8ffbf203ef56c2f346780ff930a4d430", size = 1679988, upload-time = "2025-10-06T19:57:11.367Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1b/11f9c52fd72b786a47e796e6794883417280cdca8eb1032d8d0939928dfa/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5b8a5557d5af3f4e3add52a58c4cf2b8e6e59fc56b261768866f5337872d596d", size = 1678031, upload-time = "2025-10-06T19:57:13.357Z" }, + { url = "https://files.pythonhosted.org/packages/ea/eb/948903d40505f3a25e53e051488d2714ded3afac1f961df135f2936680f9/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:052bcdd80c1c54b8a18a9ea0cd5e36f473dc8e38d51b804cea34841f677a9971", size = 1726184, upload-time = "2025-10-06T19:57:15.478Z" }, + { url = "https://files.pythonhosted.org/packages/44/14/c8ced38c7dfe80804dec17a671963ccf3cb282f12700ec70b1f689d8de7d/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:76484ba17b2832776581b7ab466d094e48eba74cb65a60aea20154dae485e8bd", size = 1542344, upload-time = "2025-10-06T19:57:17.611Z" }, + { url = "https://files.pythonhosted.org/packages/a4/6e/f2e6bff550a51fd7c45fdab116a1dab7cc502e5d942956f10fc5c626bb15/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:62d8a0adcdaf62ee56bfb37737153251ac8e4b27845b3ca065862fb01d99e247", size = 1740913, upload-time = "2025-10-06T19:57:19.821Z" }, + { url = "https://files.pythonhosted.org/packages/da/00/8f057300d9b598a706348abb375b3de9a253195fb615f17c0b2be2a72836/aiohttp-3.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5004d727499ecb95f7c9147dd0bfc5b5670f71d355f0bd26d7af2d3af8e07d2f", size = 1695535, upload-time = "2025-10-06T19:57:21.856Z" }, + { url = "https://files.pythonhosted.org/packages/8a/ab/6919d584d8f053a14b15f0bfa3f315b3f548435c2142145459da2efa8673/aiohttp-3.13.0-cp314-cp314-win32.whl", hash = "sha256:a1c20c26af48aea984f63f96e5d7af7567c32cb527e33b60a0ef0a6313cf8b03", size = 429548, upload-time = "2025-10-06T19:57:24.285Z" }, + { url = "https://files.pythonhosted.org/packages/c5/59/5d9e78de6132079066f5077d9687bf524f764a2f8207e04d8d68790060c6/aiohttp-3.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:56f7d230ec66e799fbfd8350e9544f8a45a4353f1cf40c1fea74c1780f555b8f", size = 455548, upload-time = "2025-10-06T19:57:26.136Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ea/7d98da03d1e9798bb99c3ca4963229150d45c9b7a3a16210c5b4a5f89e07/aiohttp-3.13.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:2fd35177dc483ae702f07b86c782f4f4b100a8ce4e7c5778cea016979023d9fd", size = 765319, upload-time = "2025-10-06T19:57:28.278Z" }, + { url = "https://files.pythonhosted.org/packages/5c/02/37f29beced8213bb467c52ad509a5e3b41e6e967de2f6eaf7f8db63bea54/aiohttp-3.13.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:4df1984c8804ed336089e88ac81a9417b1fd0db7c6f867c50a9264488797e778", size = 502567, upload-time = "2025-10-06T19:57:30.273Z" }, + { url = "https://files.pythonhosted.org/packages/e7/22/b0afcafcfe3637bc8d7992abf08ee9452018366c0801e4e7d4efda2ed839/aiohttp-3.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e68c0076052dd911a81d3acc4ef2911cc4ef65bf7cadbfbc8ae762da24da858f", size = 507078, upload-time = "2025-10-06T19:57:32.619Z" }, + { url = "https://files.pythonhosted.org/packages/49/4c/046c847b7a1993b49f3855cc3b97872d5df193d9240de835d0dc6a97b164/aiohttp-3.13.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc95c49853cd29613e4fe4ff96d73068ff89b89d61e53988442e127e8da8e7ba", size = 1862115, upload-time = "2025-10-06T19:57:34.758Z" }, + { url = "https://files.pythonhosted.org/packages/1a/25/1449a59e3c6405da5e47b0138ee0855414dc12a8c306685d7fc3dd300e1f/aiohttp-3.13.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3b3bdc89413117b40cc39baae08fd09cbdeb839d421c4e7dce6a34f6b54b3ac1", size = 1717147, upload-time = "2025-10-06T19:57:36.938Z" }, + { url = "https://files.pythonhosted.org/packages/23/8f/50cc34ad267b38608f21c6a74327015dd08a66f1dd8e7ceac954d0953191/aiohttp-3.13.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e77a729df23be2116acc4e9de2767d8e92445fbca68886dd991dc912f473755", size = 1841443, upload-time = "2025-10-06T19:57:39.708Z" }, + { url = "https://files.pythonhosted.org/packages/df/b9/b3ab1278faa0d1b8f434c85f9cf34eeb0a25016ffe1ee6bc361d09fef0ec/aiohttp-3.13.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e88ab34826d6eeb6c67e6e92400b9ec653faf5092a35f07465f44c9f1c429f82", size = 1933652, upload-time = "2025-10-06T19:57:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/88/e2/86050aaa3bd7021b115cdfc88477b754e8cf93ef0079867840eee22d3c34/aiohttp-3.13.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:019dbef24fe28ce2301419dd63a2b97250d9760ca63ee2976c2da2e3f182f82e", size = 1790682, upload-time = "2025-10-06T19:57:44.851Z" }, + { url = "https://files.pythonhosted.org/packages/78/8d/9af903324c2ba24a0c4778e9bcc738b773c98dded3a4fcf8041d5211769f/aiohttp-3.13.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2c4aeaedd20771b7b4bcdf0ae791904445df6d856c02fc51d809d12d17cffdc7", size = 1622011, upload-time = "2025-10-06T19:57:47.025Z" }, + { url = "https://files.pythonhosted.org/packages/84/97/5174971ba4986d913554ceb248b0401eb5358cb60672ea0166f9f596cd08/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b3a8e6a2058a0240cfde542b641d0e78b594311bc1a710cbcb2e1841417d5cb3", size = 1787148, upload-time = "2025-10-06T19:57:49.149Z" }, + { url = "https://files.pythonhosted.org/packages/dd/ae/8b397e980ac613ef3ddd8e996aa7a40a1828df958257800d4bb325657db3/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f8e38d55ca36c15f36d814ea414ecb2401d860de177c49f84a327a25b3ee752b", size = 1774816, upload-time = "2025-10-06T19:57:51.523Z" }, + { url = "https://files.pythonhosted.org/packages/c7/54/0e8e2111dd92051c787e934b6bbf30c213daaa5e7ee5f51bca8913607492/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a921edbe971aade1bf45bcbb3494e30ba6863a5c78f28be992c42de980fd9108", size = 1788610, upload-time = "2025-10-06T19:57:54.337Z" }, + { url = "https://files.pythonhosted.org/packages/fa/dd/c9283dbfd9325ed6fa6c91f009db6344d8d370a7bcf09f36e7b2fcbfae02/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:474cade59a447cb4019c0dce9f0434bf835fb558ea932f62c686fe07fe6db6a1", size = 1615498, upload-time = "2025-10-06T19:57:56.604Z" }, + { url = "https://files.pythonhosted.org/packages/8c/f6/da76230679bd9ef175d876093f89e7fd6d6476c18505e115e3026fe5ef95/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:99a303ad960747c33b65b1cb65d01a62ac73fa39b72f08a2e1efa832529b01ed", size = 1815187, upload-time = "2025-10-06T19:57:59.036Z" }, + { url = "https://files.pythonhosted.org/packages/d5/78/394003ac738703822616f4f922705b54e5b3d8e7185831ecc1c97904174d/aiohttp-3.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bb34001fc1f05f6b323e02c278090c07a47645caae3aa77ed7ed8a3ce6abcce9", size = 1760281, upload-time = "2025-10-06T19:58:01.585Z" }, + { url = "https://files.pythonhosted.org/packages/bd/b0/4bad0a9dd5910bd01c3119f8bd3d71887cd412d4105e4acddcdacf3cfa76/aiohttp-3.13.0-cp314-cp314t-win32.whl", hash = "sha256:dea698b64235d053def7d2f08af9302a69fcd760d1c7bd9988fd5d3b6157e657", size = 462608, upload-time = "2025-10-06T19:58:03.674Z" }, + { url = "https://files.pythonhosted.org/packages/bd/af/ad12d592f623aae2bd1d3463201dc39c201ea362f9ddee0d03efd9e83720/aiohttp-3.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1f164699a060c0b3616459d13c1464a981fddf36f892f0a5027cbd45121fb14b", size = 496010, upload-time = "2025-10-06T19:58:05.589Z" }, +] + +[[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.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 = "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 = "backoff" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001, upload-time = "2022-10-05T19:19:32.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148, upload-time = "2022-10-05T19:19:30.546Z" }, +] + +[[package]] +name = "bcrypt" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/ae/3af7d006aacf513975fd1948a6b4d6f8b4a307f8a244e1a3d3774b297aad/bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd", size = 25498, upload-time = "2022-10-09T15:36:49.775Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/d4/3b2657bd58ef02b23a07729b0df26f21af97169dbd0b5797afa9e97ebb49/bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f", size = 473446, upload-time = "2022-10-09T15:36:25.481Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0a/1582790232fef6c2aa201f345577306b8bfe465c2c665dec04c86a016879/bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0", size = 583044, upload-time = "2022-10-09T15:37:09.447Z" }, + { url = "https://files.pythonhosted.org/packages/41/16/49ff5146fb815742ad58cafb5034907aa7f166b1344d0ddd7fd1c818bd17/bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410", size = 583189, upload-time = "2022-10-09T15:37:10.69Z" }, + { url = "https://files.pythonhosted.org/packages/aa/48/fd2b197a9741fa790ba0b88a9b10b5e88e62ff5cf3e1bc96d8354d7ce613/bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344", size = 593473, upload-time = "2022-10-09T15:36:27.195Z" }, + { url = "https://files.pythonhosted.org/packages/7d/50/e683d8418974a602ba40899c8a5c38b3decaf5a4d36c32fc65dce454d8a8/bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a", size = 593249, upload-time = "2022-10-09T15:36:28.481Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a7/ee4561fd9b78ca23c8e5591c150cc58626a5dfb169345ab18e1c2c664ee0/bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3", size = 583586, upload-time = "2022-10-09T15:37:11.962Z" }, + { url = "https://files.pythonhosted.org/packages/64/fe/da28a5916128d541da0993328dc5cf4b43dfbf6655f2c7a2abe26ca2dc88/bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2", size = 593659, upload-time = "2022-10-09T15:36:30.049Z" }, + { url = "https://files.pythonhosted.org/packages/dd/4f/3632a69ce344c1551f7c9803196b191a8181c6a1ad2362c225581ef0d383/bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535", size = 613116, upload-time = "2022-10-09T15:37:14.107Z" }, + { url = "https://files.pythonhosted.org/packages/87/69/edacb37481d360d06fc947dab5734aaf511acb7d1a1f9e2849454376c0f8/bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e", size = 624290, upload-time = "2022-10-09T15:36:31.251Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ca/6a534669890725cbb8c1fb4622019be31813c8edaa7b6d5b62fc9360a17e/bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab", size = 159428, upload-time = "2022-10-09T15:36:32.893Z" }, + { url = "https://files.pythonhosted.org/packages/46/81/d8c22cd7e5e1c6a7d48e41a1d1d46c92f17dae70a54d9814f746e6027dec/bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9", size = 152930, upload-time = "2022-10-09T15:36:34.635Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" }, +] + +[[package]] +name = "black" +version = "25.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pytokens" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/43/20b5c90612d7bdb2bdbcceeb53d588acca3bb8f0e4c5d5c751a2c8fdd55a/black-25.9.0.tar.gz", hash = "sha256:0474bca9a0dd1b51791fcc507a4e02078a1c63f6d4e4ae5544b9848c7adfb619", size = 648393, upload-time = "2025-09-19T00:27:37.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/8e/319cfe6c82f7e2d5bfb4d3353c6cc85b523d677ff59edc61fdb9ee275234/black-25.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1b9dc70c21ef8b43248f1d86aedd2aaf75ae110b958a7909ad8463c4aa0880b0", size = 1742012, upload-time = "2025-09-19T00:33:08.678Z" }, + { url = "https://files.pythonhosted.org/packages/94/cc/f562fe5d0a40cd2a4e6ae3f685e4c36e365b1f7e494af99c26ff7f28117f/black-25.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8e46eecf65a095fa62e53245ae2795c90bdecabd53b50c448d0a8bcd0d2e74c4", size = 1581421, upload-time = "2025-09-19T00:35:25.937Z" }, + { url = "https://files.pythonhosted.org/packages/84/67/6db6dff1ebc8965fd7661498aea0da5d7301074b85bba8606a28f47ede4d/black-25.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9101ee58ddc2442199a25cb648d46ba22cd580b00ca4b44234a324e3ec7a0f7e", size = 1655619, upload-time = "2025-09-19T00:30:49.241Z" }, + { url = "https://files.pythonhosted.org/packages/10/10/3faef9aa2a730306cf469d76f7f155a8cc1f66e74781298df0ba31f8b4c8/black-25.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:77e7060a00c5ec4b3367c55f39cf9b06e68965a4f2e61cecacd6d0d9b7ec945a", size = 1342481, upload-time = "2025-09-19T00:31:29.625Z" }, + { url = "https://files.pythonhosted.org/packages/48/99/3acfea65f5e79f45472c45f87ec13037b506522719cd9d4ac86484ff51ac/black-25.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0172a012f725b792c358d57fe7b6b6e8e67375dd157f64fa7a3097b3ed3e2175", size = 1742165, upload-time = "2025-09-19T00:34:10.402Z" }, + { url = "https://files.pythonhosted.org/packages/3a/18/799285282c8236a79f25d590f0222dbd6850e14b060dfaa3e720241fd772/black-25.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3bec74ee60f8dfef564b573a96b8930f7b6a538e846123d5ad77ba14a8d7a64f", size = 1581259, upload-time = "2025-09-19T00:32:49.685Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ce/883ec4b6303acdeca93ee06b7622f1fa383c6b3765294824165d49b1a86b/black-25.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b756fc75871cb1bcac5499552d771822fd9db5a2bb8db2a7247936ca48f39831", size = 1655583, upload-time = "2025-09-19T00:30:44.505Z" }, + { url = "https://files.pythonhosted.org/packages/21/17/5c253aa80a0639ccc427a5c7144534b661505ae2b5a10b77ebe13fa25334/black-25.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:846d58e3ce7879ec1ffe816bb9df6d006cd9590515ed5d17db14e17666b2b357", size = 1343428, upload-time = "2025-09-19T00:32:13.839Z" }, + { url = "https://files.pythonhosted.org/packages/1b/46/863c90dcd3f9d41b109b7f19032ae0db021f0b2a81482ba0a1e28c84de86/black-25.9.0-py3-none-any.whl", hash = "sha256:474b34c1342cdc157d307b56c4c65bce916480c4a8f6551fdc6bf9b486a7c4ae", size = 203363, upload-time = "2025-09-19T00:27:35.724Z" }, +] + +[[package]] +name = "build" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "os_name == 'nt'" }, + { name = "packaging" }, + { name = "pyproject-hooks" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/1c/23e33405a7c9eac261dff640926b8b5adaed6a6eb3e1767d441ed611d0c0/build-1.3.0.tar.gz", hash = "sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397", size = 48544, upload-time = "2025-08-01T21:27:09.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/8c/2b30c12155ad8de0cf641d76a8b396a16d2c36bc6d50b621a62b7c4567c1/build-1.3.0-py3-none-any.whl", hash = "sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4", size = 23382, upload-time = "2025-08-01T21:27:07.844Z" }, +] + +[[package]] +name = "cachetools" +version = "6.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/7e/b975b5814bd36faf009faebe22c1072a1fa1168db34d285ef0ba071ad78c/cachetools-6.2.1.tar.gz", hash = "sha256:3f391e4bd8f8bf0931169baf7456cc822705f4e2a31f840d218f445b9a854201", size = 31325, upload-time = "2025-10-12T14:55:30.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/c5/1e741d26306c42e2bf6ab740b2202872727e0f606033c9dd713f8b93f5a8/cachetools-6.2.1-py3-none-any.whl", hash = "sha256:09868944b6dde876dfd44e1d47e18484541eaf12f26f29b7af91b26cc892d701", size = 11280, upload-time = "2025-10-12T14:55:28.382Z" }, +] + +[[package]] +name = "certifi" +version = "2025.10.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, +] + +[[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/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.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/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 = "chromadb" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bcrypt" }, + { name = "build" }, + { name = "grpcio" }, + { name = "httpx" }, + { name = "importlib-resources" }, + { name = "jsonschema" }, + { name = "kubernetes" }, + { name = "mmh3" }, + { name = "numpy" }, + { name = "onnxruntime" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-grpc" }, + { name = "opentelemetry-sdk" }, + { name = "orjson" }, + { name = "overrides" }, + { name = "posthog" }, + { name = "pybase64" }, + { name = "pydantic" }, + { name = "pypika" }, + { name = "pyyaml" }, + { name = "rich" }, + { name = "tenacity" }, + { name = "tokenizers" }, + { name = "tqdm" }, + { name = "typer" }, + { name = "typing-extensions" }, + { name = "uvicorn", extra = ["standard"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7f/48/11851dddeadad6abe36ee071fedc99b5bdd2c324df3afa8cb952ae02798b/chromadb-1.1.1.tar.gz", hash = "sha256:ebfce0122753e306a76f1e291d4ddaebe5f01b5979b97ae0bc80b1d4024ff223", size = 1338109, upload-time = "2025-10-05T02:49:14.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/59/0d881a9b7eb63d8d2446cf67fcbb53fb8ae34991759d2b6024a067e90a9a/chromadb-1.1.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:27fe0e25ef0f83fb09c30355ab084fe6f246808a7ea29e8c19e85cf45785b90d", size = 19175479, upload-time = "2025-10-05T02:49:12.525Z" }, + { url = "https://files.pythonhosted.org/packages/94/4f/5a9fa317c84c98e70af48f74b00aa25589626c03a0428b4381b2095f3d73/chromadb-1.1.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:95aed58869683f12e7dcbf68b039fe5f576dbe9d1b86b8f4d014c9d077ccafd2", size = 18267188, upload-time = "2025-10-05T02:49:09.236Z" }, + { url = "https://files.pythonhosted.org/packages/45/1a/02defe2f1c8d1daedb084bbe85f5b6083510a3ba192ed57797a3649a4310/chromadb-1.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06776dad41389a00e7d63d936c3a15c179d502becaf99f75745ee11b062c9b6a", size = 18855754, upload-time = "2025-10-05T02:49:03.299Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0d/80be82717e5dc19839af24558494811b6f2af2b261a8f21c51b872193b09/chromadb-1.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bba0096a7f5e975875ead23a91c0d41d977fbd3767f60d3305a011b0ace7afd3", size = 19893681, upload-time = "2025-10-05T02:49:06.481Z" }, + { url = "https://files.pythonhosted.org/packages/2d/6e/956e62975305a4e31daf6114a73b3b0683a8f36f8d70b20aabd466770edb/chromadb-1.1.1-cp39-abi3-win_amd64.whl", hash = "sha256:a77aa026a73a18181fd89bbbdb86191c9a82fd42aa0b549ff18d8cae56394c8b", size = 19844042, upload-time = "2025-10-05T02:49:16.925Z" }, +] + +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, +] + +[[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 = "course-agent-backend" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "bcrypt" }, + { name = "chromadb" }, + { name = "docx2txt" }, + { name = "duckduckgo-search" }, + { name = "fastapi" }, + { name = "httpx" }, + { name = "jinja2" }, + { name = "langchain" }, + { name = "langchain-chroma" }, + { name = "langchain-community" }, + { name = "langchain-openai" }, + { name = "langchain-text-splitters" }, + { name = "langgraph" }, + { name = "lxml" }, + { name = "markdownify" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "passlib", extra = ["bcrypt"] }, + { name = "psycopg", extra = ["binary"] }, + { name = "pydantic", extra = ["email"] }, + { name = "pydantic-settings" }, + { name = "pypdf" }, + { name = "pypdf2" }, + { name = "python-docx" }, + { name = "python-dotenv" }, + { name = "python-jose", extra = ["cryptography"] }, + { name = "python-multipart" }, + { name = "sentence-transformers" }, + { name = "sqlalchemy" }, + { name = "sse-starlette" }, + { name = "uvicorn", extra = ["standard"] }, + { name = "watchdog" }, + { name = "zstandard" }, +] + +[package.optional-dependencies] +dev = [ + { name = "black" }, + { name = "mypy" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "bcrypt", specifier = "==4.0.1" }, + { name = "black", marker = "extra == 'dev'", specifier = ">=24.0.0" }, + { name = "chromadb", specifier = ">=0.4.0" }, + { name = "docx2txt", specifier = ">=0.9" }, + { name = "duckduckgo-search", specifier = ">=6.0.0" }, + { name = "fastapi", specifier = ">=0.110.0" }, + { name = "httpx", specifier = ">=0.28.1" }, + { name = "jinja2", specifier = ">=3.1.3" }, + { name = "langchain", specifier = ">=1.0.0" }, + { name = "langchain-chroma", specifier = ">=0.2.0" }, + { name = "langchain-community", specifier = ">=0.3.0" }, + { name = "langchain-openai", specifier = ">=0.3.0" }, + { name = "langchain-text-splitters", specifier = ">=0.3.0" }, + { name = "langgraph", specifier = ">=0.3.5" }, + { name = "lxml", specifier = ">=6.0.2" }, + { name = "markdownify", specifier = ">=1.1.0" }, + { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.8.0" }, + { name = "numpy", specifier = ">=2.2.3" }, + { name = "pandas", specifier = ">=2.2.3" }, + { name = "passlib", extras = ["bcrypt"], specifier = ">=1.7.4" }, + { name = "psycopg", extras = ["binary"], specifier = ">=3.1.0" }, + { name = "pydantic", extras = ["email"], specifier = ">=2.5.0" }, + { name = "pydantic-settings", specifier = ">=2.1.0" }, + { name = "pypdf", specifier = ">=6.12.0" }, + { name = "pypdf2", specifier = ">=3.0.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.4.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=1.0.0" }, + { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=6.0.0" }, + { name = "python-docx", specifier = ">=1.2.0" }, + { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-jose", extras = ["cryptography"], specifier = ">=3.3.0" }, + { name = "python-multipart", specifier = ">=0.0.6" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, + { name = "sentence-transformers", specifier = ">=2.2.2" }, + { name = "sqlalchemy", specifier = ">=2.0.0" }, + { name = "sse-starlette", specifier = ">=1.6.5" }, + { name = "uvicorn", extras = ["standard"], specifier = ">=0.27.1" }, + { name = "watchdog", specifier = ">=3.0.0" }, + { name = "zstandard", specifier = ">=0.25.0" }, +] +provides-extras = ["dev"] + +[[package]] +name = "coverage" +version = "7.10.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/26/d22c300112504f5f9a9fd2297ce33c35f3d353e4aeb987c8419453b2a7c2/coverage-7.10.7.tar.gz", hash = "sha256:f4ab143ab113be368a3e9b795f9cd7906c5ef407d6173fe9675a902e1fffc239", size = 827704, upload-time = "2025-09-21T20:03:56.815Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/e4/eb12450f71b542a53972d19117ea5a5cea1cab3ac9e31b0b5d498df1bd5a/coverage-7.10.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7bb3b9ddb87ef7725056572368040c32775036472d5a033679d1fa6c8dc08417", size = 218290, upload-time = "2025-09-21T20:01:36.455Z" }, + { url = "https://files.pythonhosted.org/packages/37/66/593f9be12fc19fb36711f19a5371af79a718537204d16ea1d36f16bd78d2/coverage-7.10.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:18afb24843cbc175687225cab1138c95d262337f5473512010e46831aa0c2973", size = 218515, upload-time = "2025-09-21T20:01:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/66/80/4c49f7ae09cafdacc73fbc30949ffe77359635c168f4e9ff33c9ebb07838/coverage-7.10.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:399a0b6347bcd3822be369392932884b8216d0944049ae22925631a9b3d4ba4c", size = 250020, upload-time = "2025-09-21T20:01:39.617Z" }, + { url = "https://files.pythonhosted.org/packages/a6/90/a64aaacab3b37a17aaedd83e8000142561a29eb262cede42d94a67f7556b/coverage-7.10.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:314f2c326ded3f4b09be11bc282eb2fc861184bc95748ae67b360ac962770be7", size = 252769, upload-time = "2025-09-21T20:01:41.341Z" }, + { url = "https://files.pythonhosted.org/packages/98/2e/2dda59afd6103b342e096f246ebc5f87a3363b5412609946c120f4e7750d/coverage-7.10.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c41e71c9cfb854789dee6fc51e46743a6d138b1803fab6cb860af43265b42ea6", size = 253901, upload-time = "2025-09-21T20:01:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/53/dc/8d8119c9051d50f3119bb4a75f29f1e4a6ab9415cd1fa8bf22fcc3fb3b5f/coverage-7.10.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc01f57ca26269c2c706e838f6422e2a8788e41b3e3c65e2f41148212e57cd59", size = 250413, upload-time = "2025-09-21T20:01:44.469Z" }, + { url = "https://files.pythonhosted.org/packages/98/b3/edaff9c5d79ee4d4b6d3fe046f2b1d799850425695b789d491a64225d493/coverage-7.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a6442c59a8ac8b85812ce33bc4d05bde3fb22321fa8294e2a5b487c3505f611b", size = 251820, upload-time = "2025-09-21T20:01:45.915Z" }, + { url = "https://files.pythonhosted.org/packages/11/25/9a0728564bb05863f7e513e5a594fe5ffef091b325437f5430e8cfb0d530/coverage-7.10.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:78a384e49f46b80fb4c901d52d92abe098e78768ed829c673fbb53c498bef73a", size = 249941, upload-time = "2025-09-21T20:01:47.296Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fd/ca2650443bfbef5b0e74373aac4df67b08180d2f184b482c41499668e258/coverage-7.10.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5e1e9802121405ede4b0133aa4340ad8186a1d2526de5b7c3eca519db7bb89fb", size = 249519, upload-time = "2025-09-21T20:01:48.73Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/f692f125fb4299b6f963b0745124998ebb8e73ecdfce4ceceb06a8c6bec5/coverage-7.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d41213ea25a86f69efd1575073d34ea11aabe075604ddf3d148ecfec9e1e96a1", size = 251375, upload-time = "2025-09-21T20:01:50.529Z" }, + { url = "https://files.pythonhosted.org/packages/5e/75/61b9bbd6c7d24d896bfeec57acba78e0f8deac68e6baf2d4804f7aae1f88/coverage-7.10.7-cp312-cp312-win32.whl", hash = "sha256:77eb4c747061a6af8d0f7bdb31f1e108d172762ef579166ec84542f711d90256", size = 220699, upload-time = "2025-09-21T20:01:51.941Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f3/3bf7905288b45b075918d372498f1cf845b5b579b723c8fd17168018d5f5/coverage-7.10.7-cp312-cp312-win_amd64.whl", hash = "sha256:f51328ffe987aecf6d09f3cd9d979face89a617eacdaea43e7b3080777f647ba", size = 221512, upload-time = "2025-09-21T20:01:53.481Z" }, + { url = "https://files.pythonhosted.org/packages/5c/44/3e32dbe933979d05cf2dac5e697c8599cfe038aaf51223ab901e208d5a62/coverage-7.10.7-cp312-cp312-win_arm64.whl", hash = "sha256:bda5e34f8a75721c96085903c6f2197dc398c20ffd98df33f866a9c8fd95f4bf", size = 220147, upload-time = "2025-09-21T20:01:55.2Z" }, + { url = "https://files.pythonhosted.org/packages/9a/94/b765c1abcb613d103b64fcf10395f54d69b0ef8be6a0dd9c524384892cc7/coverage-7.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:981a651f543f2854abd3b5fcb3263aac581b18209be49863ba575de6edf4c14d", size = 218320, upload-time = "2025-09-21T20:01:56.629Z" }, + { url = "https://files.pythonhosted.org/packages/72/4f/732fff31c119bb73b35236dd333030f32c4bfe909f445b423e6c7594f9a2/coverage-7.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73ab1601f84dc804f7812dc297e93cd99381162da39c47040a827d4e8dafe63b", size = 218575, upload-time = "2025-09-21T20:01:58.203Z" }, + { url = "https://files.pythonhosted.org/packages/87/02/ae7e0af4b674be47566707777db1aa375474f02a1d64b9323e5813a6cdd5/coverage-7.10.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8b6f03672aa6734e700bbcd65ff050fd19cddfec4b031cc8cf1c6967de5a68e", size = 249568, upload-time = "2025-09-21T20:01:59.748Z" }, + { url = "https://files.pythonhosted.org/packages/a2/77/8c6d22bf61921a59bce5471c2f1f7ac30cd4ac50aadde72b8c48d5727902/coverage-7.10.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10b6ba00ab1132a0ce4428ff68cf50a25efd6840a42cdf4239c9b99aad83be8b", size = 252174, upload-time = "2025-09-21T20:02:01.192Z" }, + { url = "https://files.pythonhosted.org/packages/b1/20/b6ea4f69bbb52dac0aebd62157ba6a9dddbfe664f5af8122dac296c3ee15/coverage-7.10.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c79124f70465a150e89340de5963f936ee97097d2ef76c869708c4248c63ca49", size = 253447, upload-time = "2025-09-21T20:02:02.701Z" }, + { url = "https://files.pythonhosted.org/packages/f9/28/4831523ba483a7f90f7b259d2018fef02cb4d5b90bc7c1505d6e5a84883c/coverage-7.10.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:69212fbccdbd5b0e39eac4067e20a4a5256609e209547d86f740d68ad4f04911", size = 249779, upload-time = "2025-09-21T20:02:04.185Z" }, + { url = "https://files.pythonhosted.org/packages/a7/9f/4331142bc98c10ca6436d2d620c3e165f31e6c58d43479985afce6f3191c/coverage-7.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7ea7c6c9d0d286d04ed3541747e6597cbe4971f22648b68248f7ddcd329207f0", size = 251604, upload-time = "2025-09-21T20:02:06.034Z" }, + { url = "https://files.pythonhosted.org/packages/ce/60/bda83b96602036b77ecf34e6393a3836365481b69f7ed7079ab85048202b/coverage-7.10.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9be91986841a75042b3e3243d0b3cb0b2434252b977baaf0cd56e960fe1e46f", size = 249497, upload-time = "2025-09-21T20:02:07.619Z" }, + { url = "https://files.pythonhosted.org/packages/5f/af/152633ff35b2af63977edd835d8e6430f0caef27d171edf2fc76c270ef31/coverage-7.10.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b281d5eca50189325cfe1f365fafade89b14b4a78d9b40b05ddd1fc7d2a10a9c", size = 249350, upload-time = "2025-09-21T20:02:10.34Z" }, + { url = "https://files.pythonhosted.org/packages/9d/71/d92105d122bd21cebba877228990e1646d862e34a98bb3374d3fece5a794/coverage-7.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:99e4aa63097ab1118e75a848a28e40d68b08a5e19ce587891ab7fd04475e780f", size = 251111, upload-time = "2025-09-21T20:02:12.122Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9e/9fdb08f4bf476c912f0c3ca292e019aab6712c93c9344a1653986c3fd305/coverage-7.10.7-cp313-cp313-win32.whl", hash = "sha256:dc7c389dce432500273eaf48f410b37886be9208b2dd5710aaf7c57fd442c698", size = 220746, upload-time = "2025-09-21T20:02:13.919Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b1/a75fd25df44eab52d1931e89980d1ada46824c7a3210be0d3c88a44aaa99/coverage-7.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:cac0fdca17b036af3881a9d2729a850b76553f3f716ccb0360ad4dbc06b3b843", size = 221541, upload-time = "2025-09-21T20:02:15.57Z" }, + { url = "https://files.pythonhosted.org/packages/14/3a/d720d7c989562a6e9a14b2c9f5f2876bdb38e9367126d118495b89c99c37/coverage-7.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f236edf6e2f9ae8fcd1332da4e791c1b6ba0dc16a2dc94590ceccb482e546", size = 220170, upload-time = "2025-09-21T20:02:17.395Z" }, + { url = "https://files.pythonhosted.org/packages/bb/22/e04514bf2a735d8b0add31d2b4ab636fc02370730787c576bb995390d2d5/coverage-7.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0ec07fd264d0745ee396b666d47cef20875f4ff2375d7c4f58235886cc1ef0c", size = 219029, upload-time = "2025-09-21T20:02:18.936Z" }, + { url = "https://files.pythonhosted.org/packages/11/0b/91128e099035ece15da3445d9015e4b4153a6059403452d324cbb0a575fa/coverage-7.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd5e856ebb7bfb7672b0086846db5afb4567a7b9714b8a0ebafd211ec7ce6a15", size = 219259, upload-time = "2025-09-21T20:02:20.44Z" }, + { url = "https://files.pythonhosted.org/packages/8b/51/66420081e72801536a091a0c8f8c1f88a5c4bf7b9b1bdc6222c7afe6dc9b/coverage-7.10.7-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f57b2a3c8353d3e04acf75b3fed57ba41f5c0646bbf1d10c7c282291c97936b4", size = 260592, upload-time = "2025-09-21T20:02:22.313Z" }, + { url = "https://files.pythonhosted.org/packages/5d/22/9b8d458c2881b22df3db5bb3e7369e63d527d986decb6c11a591ba2364f7/coverage-7.10.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ef2319dd15a0b009667301a3f84452a4dc6fddfd06b0c5c53ea472d3989fbf0", size = 262768, upload-time = "2025-09-21T20:02:24.287Z" }, + { url = "https://files.pythonhosted.org/packages/f7/08/16bee2c433e60913c610ea200b276e8eeef084b0d200bdcff69920bd5828/coverage-7.10.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83082a57783239717ceb0ad584de3c69cf581b2a95ed6bf81ea66034f00401c0", size = 264995, upload-time = "2025-09-21T20:02:26.133Z" }, + { url = "https://files.pythonhosted.org/packages/20/9d/e53eb9771d154859b084b90201e5221bca7674ba449a17c101a5031d4054/coverage-7.10.7-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:50aa94fb1fb9a397eaa19c0d5ec15a5edd03a47bf1a3a6111a16b36e190cff65", size = 259546, upload-time = "2025-09-21T20:02:27.716Z" }, + { url = "https://files.pythonhosted.org/packages/ad/b0/69bc7050f8d4e56a89fb550a1577d5d0d1db2278106f6f626464067b3817/coverage-7.10.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2120043f147bebb41c85b97ac45dd173595ff14f2a584f2963891cbcc3091541", size = 262544, upload-time = "2025-09-21T20:02:29.216Z" }, + { url = "https://files.pythonhosted.org/packages/ef/4b/2514b060dbd1bc0aaf23b852c14bb5818f244c664cb16517feff6bb3a5ab/coverage-7.10.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2fafd773231dd0378fdba66d339f84904a8e57a262f583530f4f156ab83863e6", size = 260308, upload-time = "2025-09-21T20:02:31.226Z" }, + { url = "https://files.pythonhosted.org/packages/54/78/7ba2175007c246d75e496f64c06e94122bdb914790a1285d627a918bd271/coverage-7.10.7-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:0b944ee8459f515f28b851728ad224fa2d068f1513ef6b7ff1efafeb2185f999", size = 258920, upload-time = "2025-09-21T20:02:32.823Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/fac9f7abbc841409b9a410309d73bfa6cfb2e51c3fada738cb607ce174f8/coverage-7.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4b583b97ab2e3efe1b3e75248a9b333bd3f8b0b1b8e5b45578e05e5850dfb2c2", size = 261434, upload-time = "2025-09-21T20:02:34.86Z" }, + { url = "https://files.pythonhosted.org/packages/ee/51/a03bec00d37faaa891b3ff7387192cef20f01604e5283a5fabc95346befa/coverage-7.10.7-cp313-cp313t-win32.whl", hash = "sha256:2a78cd46550081a7909b3329e2266204d584866e8d97b898cd7fb5ac8d888b1a", size = 221403, upload-time = "2025-09-21T20:02:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/53/22/3cf25d614e64bf6d8e59c7c669b20d6d940bb337bdee5900b9ca41c820bb/coverage-7.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:33a5e6396ab684cb43dc7befa386258acb2d7fae7f67330ebb85ba4ea27938eb", size = 222469, upload-time = "2025-09-21T20:02:39.011Z" }, + { url = "https://files.pythonhosted.org/packages/49/a1/00164f6d30d8a01c3c9c48418a7a5be394de5349b421b9ee019f380df2a0/coverage-7.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:86b0e7308289ddde73d863b7683f596d8d21c7d8664ce1dee061d0bcf3fbb4bb", size = 220731, upload-time = "2025-09-21T20:02:40.939Z" }, + { url = "https://files.pythonhosted.org/packages/23/9c/5844ab4ca6a4dd97a1850e030a15ec7d292b5c5cb93082979225126e35dd/coverage-7.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b06f260b16ead11643a5a9f955bd4b5fd76c1a4c6796aeade8520095b75de520", size = 218302, upload-time = "2025-09-21T20:02:42.527Z" }, + { url = "https://files.pythonhosted.org/packages/f0/89/673f6514b0961d1f0e20ddc242e9342f6da21eaba3489901b565c0689f34/coverage-7.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:212f8f2e0612778f09c55dd4872cb1f64a1f2b074393d139278ce902064d5b32", size = 218578, upload-time = "2025-09-21T20:02:44.468Z" }, + { url = "https://files.pythonhosted.org/packages/05/e8/261cae479e85232828fb17ad536765c88dd818c8470aca690b0ac6feeaa3/coverage-7.10.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3445258bcded7d4aa630ab8296dea4d3f15a255588dd535f980c193ab6b95f3f", size = 249629, upload-time = "2025-09-21T20:02:46.503Z" }, + { url = "https://files.pythonhosted.org/packages/82/62/14ed6546d0207e6eda876434e3e8475a3e9adbe32110ce896c9e0c06bb9a/coverage-7.10.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb45474711ba385c46a0bfe696c695a929ae69ac636cda8f532be9e8c93d720a", size = 252162, upload-time = "2025-09-21T20:02:48.689Z" }, + { url = "https://files.pythonhosted.org/packages/ff/49/07f00db9ac6478e4358165a08fb41b469a1b053212e8a00cb02f0d27a05f/coverage-7.10.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:813922f35bd800dca9994c5971883cbc0d291128a5de6b167c7aa697fcf59360", size = 253517, upload-time = "2025-09-21T20:02:50.31Z" }, + { url = "https://files.pythonhosted.org/packages/a2/59/c5201c62dbf165dfbc91460f6dbbaa85a8b82cfa6131ac45d6c1bfb52deb/coverage-7.10.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c1b03552081b2a4423091d6fb3787265b8f86af404cff98d1b5342713bdd69", size = 249632, upload-time = "2025-09-21T20:02:51.971Z" }, + { url = "https://files.pythonhosted.org/packages/07/ae/5920097195291a51fb00b3a70b9bbd2edbfe3c84876a1762bd1ef1565ebc/coverage-7.10.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cc87dd1b6eaf0b848eebb1c86469b9f72a1891cb42ac7adcfbce75eadb13dd14", size = 251520, upload-time = "2025-09-21T20:02:53.858Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3c/a815dde77a2981f5743a60b63df31cb322c944843e57dbd579326625a413/coverage-7.10.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:39508ffda4f343c35f3236fe8d1a6634a51f4581226a1262769d7f970e73bffe", size = 249455, upload-time = "2025-09-21T20:02:55.807Z" }, + { url = "https://files.pythonhosted.org/packages/aa/99/f5cdd8421ea656abefb6c0ce92556709db2265c41e8f9fc6c8ae0f7824c9/coverage-7.10.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:925a1edf3d810537c5a3abe78ec5530160c5f9a26b1f4270b40e62cc79304a1e", size = 249287, upload-time = "2025-09-21T20:02:57.784Z" }, + { url = "https://files.pythonhosted.org/packages/c3/7a/e9a2da6a1fc5d007dd51fca083a663ab930a8c4d149c087732a5dbaa0029/coverage-7.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2c8b9a0636f94c43cd3576811e05b89aa9bc2d0a85137affc544ae5cb0e4bfbd", size = 250946, upload-time = "2025-09-21T20:02:59.431Z" }, + { url = "https://files.pythonhosted.org/packages/ef/5b/0b5799aa30380a949005a353715095d6d1da81927d6dbed5def2200a4e25/coverage-7.10.7-cp314-cp314-win32.whl", hash = "sha256:b7b8288eb7cdd268b0304632da8cb0bb93fadcfec2fe5712f7b9cc8f4d487be2", size = 221009, upload-time = "2025-09-21T20:03:01.324Z" }, + { url = "https://files.pythonhosted.org/packages/da/b0/e802fbb6eb746de006490abc9bb554b708918b6774b722bb3a0e6aa1b7de/coverage-7.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:1ca6db7c8807fb9e755d0379ccc39017ce0a84dcd26d14b5a03b78563776f681", size = 221804, upload-time = "2025-09-21T20:03:03.4Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e8/71d0c8e374e31f39e3389bb0bd19e527d46f00ea8571ec7ec8fd261d8b44/coverage-7.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:097c1591f5af4496226d5783d036bf6fd6cd0cbc132e071b33861de756efb880", size = 220384, upload-time = "2025-09-21T20:03:05.111Z" }, + { url = "https://files.pythonhosted.org/packages/62/09/9a5608d319fa3eba7a2019addeacb8c746fb50872b57a724c9f79f146969/coverage-7.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a62c6ef0d50e6de320c270ff91d9dd0a05e7250cac2a800b7784bae474506e63", size = 219047, upload-time = "2025-09-21T20:03:06.795Z" }, + { url = "https://files.pythonhosted.org/packages/f5/6f/f58d46f33db9f2e3647b2d0764704548c184e6f5e014bef528b7f979ef84/coverage-7.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9fa6e4dd51fe15d8738708a973470f67a855ca50002294852e9571cdbd9433f2", size = 219266, upload-time = "2025-09-21T20:03:08.495Z" }, + { url = "https://files.pythonhosted.org/packages/74/5c/183ffc817ba68e0b443b8c934c8795553eb0c14573813415bd59941ee165/coverage-7.10.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8fb190658865565c549b6b4706856d6a7b09302c797eb2cf8e7fe9dabb043f0d", size = 260767, upload-time = "2025-09-21T20:03:10.172Z" }, + { url = "https://files.pythonhosted.org/packages/0f/48/71a8abe9c1ad7e97548835e3cc1adbf361e743e9d60310c5f75c9e7bf847/coverage-7.10.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:affef7c76a9ef259187ef31599a9260330e0335a3011732c4b9effa01e1cd6e0", size = 262931, upload-time = "2025-09-21T20:03:11.861Z" }, + { url = "https://files.pythonhosted.org/packages/84/fd/193a8fb132acfc0a901f72020e54be5e48021e1575bb327d8ee1097a28fd/coverage-7.10.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e16e07d85ca0cf8bafe5f5d23a0b850064e8e945d5677492b06bbe6f09cc699", size = 265186, upload-time = "2025-09-21T20:03:13.539Z" }, + { url = "https://files.pythonhosted.org/packages/b1/8f/74ecc30607dd95ad50e3034221113ccb1c6d4e8085cc761134782995daae/coverage-7.10.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03ffc58aacdf65d2a82bbeb1ffe4d01ead4017a21bfd0454983b88ca73af94b9", size = 259470, upload-time = "2025-09-21T20:03:15.584Z" }, + { url = "https://files.pythonhosted.org/packages/0f/55/79ff53a769f20d71b07023ea115c9167c0bb56f281320520cf64c5298a96/coverage-7.10.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1b4fd784344d4e52647fd7857b2af5b3fbe6c239b0b5fa63e94eb67320770e0f", size = 262626, upload-time = "2025-09-21T20:03:17.673Z" }, + { url = "https://files.pythonhosted.org/packages/88/e2/dac66c140009b61ac3fc13af673a574b00c16efdf04f9b5c740703e953c0/coverage-7.10.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0ebbaddb2c19b71912c6f2518e791aa8b9f054985a0769bdb3a53ebbc765c6a1", size = 260386, upload-time = "2025-09-21T20:03:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/a2/f1/f48f645e3f33bb9ca8a496bc4a9671b52f2f353146233ebd7c1df6160440/coverage-7.10.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a2d9a3b260cc1d1dbdb1c582e63ddcf5363426a1a68faa0f5da28d8ee3c722a0", size = 258852, upload-time = "2025-09-21T20:03:21.007Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3b/8442618972c51a7affeead957995cfa8323c0c9bcf8fa5a027421f720ff4/coverage-7.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a3cc8638b2480865eaa3926d192e64ce6c51e3d29c849e09d5b4ad95efae5399", size = 261534, upload-time = "2025-09-21T20:03:23.12Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dc/101f3fa3a45146db0cb03f5b4376e24c0aac818309da23e2de0c75295a91/coverage-7.10.7-cp314-cp314t-win32.whl", hash = "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235", size = 221784, upload-time = "2025-09-21T20:03:24.769Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a1/74c51803fc70a8a40d7346660379e144be772bab4ac7bb6e6b905152345c/coverage-7.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d", size = 222905, upload-time = "2025-09-21T20:03:26.93Z" }, + { url = "https://files.pythonhosted.org/packages/12/65/f116a6d2127df30bcafbceef0302d8a64ba87488bf6f73a6d8eebf060873/coverage-7.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a", size = 220922, upload-time = "2025-09-21T20:03:28.672Z" }, + { url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952, upload-time = "2025-09-21T20:03:53.918Z" }, +] + +[[package]] +name = "cryptography" +version = "46.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/9b/e301418629f7bfdf72db9e80ad6ed9d1b83c487c471803eaa6464c511a01/cryptography-46.0.2.tar.gz", hash = "sha256:21b6fc8c71a3f9a604f028a329e5560009cc4a3a828bfea5fcba8eb7647d88fe", size = 749293, upload-time = "2025-10-01T00:29:11.856Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/98/7a8df8c19a335c8028414738490fc3955c0cecbfdd37fcc1b9c3d04bd561/cryptography-46.0.2-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3e32ab7dd1b1ef67b9232c4cf5e2ee4cd517d4316ea910acaaa9c5712a1c663", size = 7261255, upload-time = "2025-10-01T00:27:22.947Z" }, + { url = "https://files.pythonhosted.org/packages/c6/38/b2adb2aa1baa6706adc3eb746691edd6f90a656a9a65c3509e274d15a2b8/cryptography-46.0.2-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1fd1a69086926b623ef8126b4c33d5399ce9e2f3fac07c9c734c2a4ec38b6d02", size = 4297596, upload-time = "2025-10-01T00:27:25.258Z" }, + { url = "https://files.pythonhosted.org/packages/e4/27/0f190ada240003119488ae66c897b5e97149292988f556aef4a6a2a57595/cryptography-46.0.2-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb7fb9cd44c2582aa5990cf61a4183e6f54eea3172e54963787ba47287edd135", size = 4450899, upload-time = "2025-10-01T00:27:27.458Z" }, + { url = "https://files.pythonhosted.org/packages/85/d5/e4744105ab02fdf6bb58ba9a816e23b7a633255987310b4187d6745533db/cryptography-46.0.2-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9066cfd7f146f291869a9898b01df1c9b0e314bfa182cef432043f13fc462c92", size = 4300382, upload-time = "2025-10-01T00:27:29.091Z" }, + { url = "https://files.pythonhosted.org/packages/33/fb/bf9571065c18c04818cb07de90c43fc042c7977c68e5de6876049559c72f/cryptography-46.0.2-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:97e83bf4f2f2c084d8dd792d13841d0a9b241643151686010866bbd076b19659", size = 4017347, upload-time = "2025-10-01T00:27:30.767Z" }, + { url = "https://files.pythonhosted.org/packages/35/72/fc51856b9b16155ca071080e1a3ad0c3a8e86616daf7eb018d9565b99baa/cryptography-46.0.2-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:4a766d2a5d8127364fd936572c6e6757682fc5dfcbdba1632d4554943199f2fa", size = 4983500, upload-time = "2025-10-01T00:27:32.741Z" }, + { url = "https://files.pythonhosted.org/packages/c1/53/0f51e926799025e31746d454ab2e36f8c3f0d41592bc65cb9840368d3275/cryptography-46.0.2-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:fab8f805e9675e61ed8538f192aad70500fa6afb33a8803932999b1049363a08", size = 4482591, upload-time = "2025-10-01T00:27:34.869Z" }, + { url = "https://files.pythonhosted.org/packages/86/96/4302af40b23ab8aa360862251fb8fc450b2a06ff24bc5e261c2007f27014/cryptography-46.0.2-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1e3b6428a3d56043bff0bb85b41c535734204e599c1c0977e1d0f261b02f3ad5", size = 4300019, upload-time = "2025-10-01T00:27:37.029Z" }, + { url = "https://files.pythonhosted.org/packages/9b/59/0be12c7fcc4c5e34fe2b665a75bc20958473047a30d095a7657c218fa9e8/cryptography-46.0.2-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:1a88634851d9b8de8bb53726f4300ab191d3b2f42595e2581a54b26aba71b7cc", size = 4950006, upload-time = "2025-10-01T00:27:40.272Z" }, + { url = "https://files.pythonhosted.org/packages/55/1d/42fda47b0111834b49e31590ae14fd020594d5e4dadd639bce89ad790fba/cryptography-46.0.2-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:be939b99d4e091eec9a2bcf41aaf8f351f312cd19ff74b5c83480f08a8a43e0b", size = 4482088, upload-time = "2025-10-01T00:27:42.668Z" }, + { url = "https://files.pythonhosted.org/packages/17/50/60f583f69aa1602c2bdc7022dae86a0d2b837276182f8c1ec825feb9b874/cryptography-46.0.2-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f13b040649bc18e7eb37936009b24fd31ca095a5c647be8bb6aaf1761142bd1", size = 4425599, upload-time = "2025-10-01T00:27:44.616Z" }, + { url = "https://files.pythonhosted.org/packages/d1/57/d8d4134cd27e6e94cf44adb3f3489f935bde85f3a5508e1b5b43095b917d/cryptography-46.0.2-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bdc25e4e01b261a8fda4e98618f1c9515febcecebc9566ddf4a70c63967043b", size = 4697458, upload-time = "2025-10-01T00:27:46.209Z" }, + { url = "https://files.pythonhosted.org/packages/d1/2b/531e37408573e1da33adfb4c58875013ee8ac7d548d1548967d94a0ae5c4/cryptography-46.0.2-cp311-abi3-win32.whl", hash = "sha256:8b9bf67b11ef9e28f4d78ff88b04ed0929fcd0e4f70bb0f704cfc32a5c6311ee", size = 3056077, upload-time = "2025-10-01T00:27:48.424Z" }, + { url = "https://files.pythonhosted.org/packages/a8/cd/2f83cafd47ed2dc5a3a9c783ff5d764e9e70d3a160e0df9a9dcd639414ce/cryptography-46.0.2-cp311-abi3-win_amd64.whl", hash = "sha256:758cfc7f4c38c5c5274b55a57ef1910107436f4ae842478c4989abbd24bd5acb", size = 3512585, upload-time = "2025-10-01T00:27:50.521Z" }, + { url = "https://files.pythonhosted.org/packages/00/36/676f94e10bfaa5c5b86c469ff46d3e0663c5dc89542f7afbadac241a3ee4/cryptography-46.0.2-cp311-abi3-win_arm64.whl", hash = "sha256:218abd64a2e72f8472c2102febb596793347a3e65fafbb4ad50519969da44470", size = 2927474, upload-time = "2025-10-01T00:27:52.91Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cc/47fc6223a341f26d103cb6da2216805e08a37d3b52bee7f3b2aee8066f95/cryptography-46.0.2-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:bda55e8dbe8533937956c996beaa20266a8eca3570402e52ae52ed60de1faca8", size = 7198626, upload-time = "2025-10-01T00:27:54.8Z" }, + { url = "https://files.pythonhosted.org/packages/93/22/d66a8591207c28bbe4ac7afa25c4656dc19dc0db29a219f9809205639ede/cryptography-46.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e7155c0b004e936d381b15425273aee1cebc94f879c0ce82b0d7fecbf755d53a", size = 4287584, upload-time = "2025-10-01T00:27:57.018Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/fac3ab6302b928e0398c269eddab5978e6c1c50b2b77bb5365ffa8633b37/cryptography-46.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a61c154cc5488272a6c4b86e8d5beff4639cdb173d75325ce464d723cda0052b", size = 4433796, upload-time = "2025-10-01T00:27:58.631Z" }, + { url = "https://files.pythonhosted.org/packages/7d/d8/24392e5d3c58e2d83f98fe5a2322ae343360ec5b5b93fe18bc52e47298f5/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:9ec3f2e2173f36a9679d3b06d3d01121ab9b57c979de1e6a244b98d51fea1b20", size = 4292126, upload-time = "2025-10-01T00:28:00.643Z" }, + { url = "https://files.pythonhosted.org/packages/ed/38/3d9f9359b84c16c49a5a336ee8be8d322072a09fac17e737f3bb11f1ce64/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2fafb6aa24e702bbf74de4cb23bfa2c3beb7ab7683a299062b69724c92e0fa73", size = 3993056, upload-time = "2025-10-01T00:28:02.8Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a3/4c44fce0d49a4703cc94bfbe705adebf7ab36efe978053742957bc7ec324/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:0c7ffe8c9b1fcbb07a26d7c9fa5e857c2fe80d72d7b9e0353dcf1d2180ae60ee", size = 4967604, upload-time = "2025-10-01T00:28:04.783Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c2/49d73218747c8cac16bb8318a5513fde3129e06a018af3bc4dc722aa4a98/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:5840f05518caa86b09d23f8b9405a7b6d5400085aa14a72a98fdf5cf1568c0d2", size = 4465367, upload-time = "2025-10-01T00:28:06.864Z" }, + { url = "https://files.pythonhosted.org/packages/1b/64/9afa7d2ee742f55ca6285a54386ed2778556a4ed8871571cb1c1bfd8db9e/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:27c53b4f6a682a1b645fbf1cd5058c72cf2f5aeba7d74314c36838c7cbc06e0f", size = 4291678, upload-time = "2025-10-01T00:28:08.982Z" }, + { url = "https://files.pythonhosted.org/packages/50/48/1696d5ea9623a7b72ace87608f6899ca3c331709ac7ebf80740abb8ac673/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:512c0250065e0a6b286b2db4bbcc2e67d810acd53eb81733e71314340366279e", size = 4931366, upload-time = "2025-10-01T00:28:10.74Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/9dfc778401a334db3b24435ee0733dd005aefb74afe036e2d154547cb917/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:07c0eb6657c0e9cca5891f4e35081dbf985c8131825e21d99b4f440a8f496f36", size = 4464738, upload-time = "2025-10-01T00:28:12.491Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b1/abcde62072b8f3fd414e191a6238ce55a0050e9738090dc6cded24c12036/cryptography-46.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:48b983089378f50cba258f7f7aa28198c3f6e13e607eaf10472c26320332ca9a", size = 4419305, upload-time = "2025-10-01T00:28:14.145Z" }, + { url = "https://files.pythonhosted.org/packages/c7/1f/3d2228492f9391395ca34c677e8f2571fb5370fe13dc48c1014f8c509864/cryptography-46.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e6f6775eaaa08c0eec73e301f7592f4367ccde5e4e4df8e58320f2ebf161ea2c", size = 4681201, upload-time = "2025-10-01T00:28:15.951Z" }, + { url = "https://files.pythonhosted.org/packages/de/77/b687745804a93a55054f391528fcfc76c3d6bfd082ce9fb62c12f0d29fc1/cryptography-46.0.2-cp314-cp314t-win32.whl", hash = "sha256:e8633996579961f9b5a3008683344c2558d38420029d3c0bc7ff77c17949a4e1", size = 3022492, upload-time = "2025-10-01T00:28:17.643Z" }, + { url = "https://files.pythonhosted.org/packages/60/a5/8d498ef2996e583de0bef1dcc5e70186376f00883ae27bf2133f490adf21/cryptography-46.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:48c01988ecbb32979bb98731f5c2b2f79042a6c58cc9a319c8c2f9987c7f68f9", size = 3496215, upload-time = "2025-10-01T00:28:19.272Z" }, + { url = "https://files.pythonhosted.org/packages/56/db/ee67aaef459a2706bc302b15889a1a8126ebe66877bab1487ae6ad00f33d/cryptography-46.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:8e2ad4d1a5899b7caa3a450e33ee2734be7cc0689010964703a7c4bcc8dd4fd0", size = 2919255, upload-time = "2025-10-01T00:28:21.115Z" }, + { url = "https://files.pythonhosted.org/packages/d5/bb/fa95abcf147a1b0bb94d95f53fbb09da77b24c776c5d87d36f3d94521d2c/cryptography-46.0.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a08e7401a94c002e79dc3bc5231b6558cd4b2280ee525c4673f650a37e2c7685", size = 7248090, upload-time = "2025-10-01T00:28:22.846Z" }, + { url = "https://files.pythonhosted.org/packages/b7/66/f42071ce0e3ffbfa80a88feadb209c779fda92a23fbc1e14f74ebf72ef6b/cryptography-46.0.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d30bc11d35743bf4ddf76674a0a369ec8a21f87aaa09b0661b04c5f6c46e8d7b", size = 4293123, upload-time = "2025-10-01T00:28:25.072Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5d/1fdbd2e5c1ba822828d250e5a966622ef00185e476d1cd2726b6dd135e53/cryptography-46.0.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bca3f0ce67e5a2a2cf524e86f44697c4323a86e0fd7ba857de1c30d52c11ede1", size = 4439524, upload-time = "2025-10-01T00:28:26.808Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c1/5e4989a7d102d4306053770d60f978c7b6b1ea2ff8c06e0265e305b23516/cryptography-46.0.2-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ff798ad7a957a5021dcbab78dfff681f0cf15744d0e6af62bd6746984d9c9e9c", size = 4297264, upload-time = "2025-10-01T00:28:29.327Z" }, + { url = "https://files.pythonhosted.org/packages/28/78/b56f847d220cb1d6d6aef5a390e116ad603ce13a0945a3386a33abc80385/cryptography-46.0.2-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cb5e8daac840e8879407acbe689a174f5ebaf344a062f8918e526824eb5d97af", size = 4011872, upload-time = "2025-10-01T00:28:31.479Z" }, + { url = "https://files.pythonhosted.org/packages/e1/80/2971f214b066b888944f7b57761bf709ee3f2cf805619a18b18cab9b263c/cryptography-46.0.2-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:3f37aa12b2d91e157827d90ce78f6180f0c02319468a0aea86ab5a9566da644b", size = 4978458, upload-time = "2025-10-01T00:28:33.267Z" }, + { url = "https://files.pythonhosted.org/packages/a5/84/0cb0a2beaa4f1cbe63ebec4e97cd7e0e9f835d0ba5ee143ed2523a1e0016/cryptography-46.0.2-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e38f203160a48b93010b07493c15f2babb4e0f2319bbd001885adb3f3696d21", size = 4472195, upload-time = "2025-10-01T00:28:36.039Z" }, + { url = "https://files.pythonhosted.org/packages/30/8b/2b542ddbf78835c7cd67b6fa79e95560023481213a060b92352a61a10efe/cryptography-46.0.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d19f5f48883752b5ab34cff9e2f7e4a7f216296f33714e77d1beb03d108632b6", size = 4296791, upload-time = "2025-10-01T00:28:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/78/12/9065b40201b4f4876e93b9b94d91feb18de9150d60bd842a16a21565007f/cryptography-46.0.2-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:04911b149eae142ccd8c9a68892a70c21613864afb47aba92d8c7ed9cc001023", size = 4939629, upload-time = "2025-10-01T00:28:39.654Z" }, + { url = "https://files.pythonhosted.org/packages/f6/9e/6507dc048c1b1530d372c483dfd34e7709fc542765015425f0442b08547f/cryptography-46.0.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8b16c1ede6a937c291d41176934268e4ccac2c6521c69d3f5961c5a1e11e039e", size = 4471988, upload-time = "2025-10-01T00:28:41.822Z" }, + { url = "https://files.pythonhosted.org/packages/b1/86/d025584a5f7d5c5ec8d3633dbcdce83a0cd579f1141ceada7817a4c26934/cryptography-46.0.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:747b6f4a4a23d5a215aadd1d0b12233b4119c4313df83ab4137631d43672cc90", size = 4422989, upload-time = "2025-10-01T00:28:43.608Z" }, + { url = "https://files.pythonhosted.org/packages/4b/39/536370418b38a15a61bbe413006b79dfc3d2b4b0eafceb5581983f973c15/cryptography-46.0.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6b275e398ab3a7905e168c036aad54b5969d63d3d9099a0a66cc147a3cc983be", size = 4685578, upload-time = "2025-10-01T00:28:45.361Z" }, + { url = "https://files.pythonhosted.org/packages/15/52/ea7e2b1910f547baed566c866fbb86de2402e501a89ecb4871ea7f169a81/cryptography-46.0.2-cp38-abi3-win32.whl", hash = "sha256:0b507c8e033307e37af61cb9f7159b416173bdf5b41d11c4df2e499a1d8e007c", size = 3036711, upload-time = "2025-10-01T00:28:47.096Z" }, + { url = "https://files.pythonhosted.org/packages/71/9e/171f40f9c70a873e73c2efcdbe91e1d4b1777a03398fa1c4af3c56a2477a/cryptography-46.0.2-cp38-abi3-win_amd64.whl", hash = "sha256:f9b2dc7668418fb6f221e4bf701f716e05e8eadb4f1988a2487b11aedf8abe62", size = 3500007, upload-time = "2025-10-01T00:28:48.967Z" }, + { url = "https://files.pythonhosted.org/packages/3e/7c/15ad426257615f9be8caf7f97990cf3dcbb5b8dd7ed7e0db581a1c4759dd/cryptography-46.0.2-cp38-abi3-win_arm64.whl", hash = "sha256:91447f2b17e83c9e0c89f133119d83f94ce6e0fb55dd47da0a959316e6e9cfa1", size = 2918153, upload-time = "2025-10-01T00:28:51.003Z" }, +] + +[[package]] +name = "dataclasses-json" +version = "0.6.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marshmallow" }, + { name = "typing-inspect" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227, upload-time = "2024-06-09T16:20:19.103Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "docx2txt" +version = "0.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613, upload-time = "2025-03-24T20:59:25.21Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025, upload-time = "2025-03-24T20:59:24.394Z" }, +] + +[[package]] +name = "duckduckgo-search" +version = "8.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "lxml" }, + { name = "primp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/10/ef/07791a05751e6cc9de1dd49fb12730259ee109b18e6d097e25e6c32d5617/duckduckgo_search-8.1.1.tar.gz", hash = "sha256:9da91c9eb26a17e016ea1da26235d40404b46b0565ea86d75a9f78cc9441f935", size = 22868, upload-time = "2025-07-06T15:30:59.73Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/72/c027b3b488b1010cf71670032fcf7e681d44b81829d484bb04e31a949a8d/duckduckgo_search-8.1.1-py3-none-any.whl", hash = "sha256:f48adbb06626ee05918f7e0cef3a45639e9939805c4fc179e68c48a12f1b5062", size = 18932, upload-time = "2025-07-06T15:30:58.339Z" }, +] + +[[package]] +name = "durationpy" +version = "0.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/a4/e44218c2b394e31a6dd0d6b095c4e1f32d0be54c2a4b250032d717647bab/durationpy-0.10.tar.gz", hash = "sha256:1fa6893409a6e739c9c72334fc65cca1f355dbdd93405d30f726deb5bde42fba", size = 3335, upload-time = "2025-05-17T13:52:37.26Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/0d/9feae160378a3553fa9a339b0e9c1a048e147a4127210e286ef18b730f03/durationpy-0.10-py3-none-any.whl", hash = "sha256:3b41e1b601234296b4fb368338fdcd3e13e0b4fb5b67345948f4f2bf9868b286", size = 3922, upload-time = "2025-05-17T13:52:36.463Z" }, +] + +[[package]] +name = "ecdsa" +version = "0.19.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/1f/924e3caae75f471eae4b26bd13b698f6af2c44279f67af317439c2f4c46a/ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61", size = 201793, upload-time = "2025-03-13T11:52:43.25Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/a3/460c57f094a4a165c84a1341c373b0a4f5ec6ac244b998d5021aade89b77/ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3", size = 150607, upload-time = "2025-03-13T11:52:41.757Z" }, +] + +[[package]] +name = "email-validator" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, +] + +[[package]] +name = "fastapi" +version = "0.119.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/f9/5c5bcce82a7997cc0eb8c47b7800f862f6b56adc40486ed246e5010d443b/fastapi-0.119.0.tar.gz", hash = "sha256:451082403a2c1f0b99c6bd57c09110ed5463856804c8078d38e5a1f1035dbbb7", size = 336756, upload-time = "2025-10-11T17:13:40.53Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/70/584c4d7cad80f5e833715c0a29962d7c93b4d18eed522a02981a6d1b6ee5/fastapi-0.119.0-py3-none-any.whl", hash = "sha256:90a2e49ed19515320abb864df570dd766be0662c5d577688f1600170f7f73cf2", size = 107095, upload-time = "2025-10-11T17:13:39.048Z" }, +] + +[[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 = "flatbuffers" +version = "25.9.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/1f/3ee70b0a55137442038f2a33469cc5fddd7e0ad2abf83d7497c18a2b6923/flatbuffers-25.9.23.tar.gz", hash = "sha256:676f9fa62750bb50cf531b42a0a2a118ad8f7f797a511eda12881c016f093b12", size = 22067, upload-time = "2025-09-24T05:25:30.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/1b/00a78aa2e8fbd63f9af08c9c19e6deb3d5d66b4dda677a0f61654680ee89/flatbuffers-25.9.23-py2.py3-none-any.whl", hash = "sha256:255538574d6cb6d0a79a17ec8bc0d30985913b87513a01cce8bcdb6b4c44d0e2", size = 30869, upload-time = "2025-09-24T05:25:28.912Z" }, +] + +[[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/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.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 = "google-auth" +version = "2.41.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "pyasn1-modules" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/af/5129ce5b2f9688d2fa49b463e544972a7c82b0fdb50980dafee92e121d9f/google_auth-2.41.1.tar.gz", hash = "sha256:b76b7b1f9e61f0cb7e88870d14f6a94aeef248959ef6992670efee37709cbfd2", size = 292284, upload-time = "2025-09-30T22:51:26.363Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/a4/7319a2a8add4cc352be9e3efeff5e2aacee917c85ca2fa1647e29089983c/google_auth-2.41.1-py2.py3-none-any.whl", hash = "sha256:754843be95575b9a19c604a848a41be03f7f2afd8c019f716dc1f51ee41c639d", size = 221302, upload-time = "2025-09-30T22:51:24.212Z" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.70.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903, upload-time = "2025-04-14T10:17:02.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" }, +] + +[[package]] +name = "greenlet" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" }, + { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" }, + { url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185, upload-time = "2025-08-07T13:45:27.624Z" }, + { url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926, upload-time = "2025-08-07T13:53:15.251Z" }, + { url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839, upload-time = "2025-08-07T13:18:30.281Z" }, + { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" }, + { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" }, + { url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846, upload-time = "2025-11-04T12:42:15.191Z" }, + { url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814, upload-time = "2025-11-04T12:42:17.175Z" }, + { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" }, + { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, + { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" }, + { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" }, + { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, + { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, + { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, + { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759, upload-time = "2025-11-04T12:42:19.395Z" }, + { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288, upload-time = "2025-11-04T12:42:21.174Z" }, + { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, + { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, + { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, + { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" }, + { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, + { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508, upload-time = "2025-11-04T12:42:23.427Z" }, + { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760, upload-time = "2025-11-04T12:42:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, +] + +[[package]] +name = "grpcio" +version = "1.75.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/f7/8963848164c7604efb3a3e6ee457fdb3a469653e19002bd24742473254f8/grpcio-1.75.1.tar.gz", hash = "sha256:3e81d89ece99b9ace23a6916880baca613c03a799925afb2857887efa8b1b3d2", size = 12731327, upload-time = "2025-09-26T09:03:36.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/81/42be79e73a50aaa20af66731c2defeb0e8c9008d9935a64dd8ea8e8c44eb/grpcio-1.75.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:7b888b33cd14085d86176b1628ad2fcbff94cfbbe7809465097aa0132e58b018", size = 5668314, upload-time = "2025-09-26T09:01:55.424Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/3686ed15822fedc58c22f82b3a7403d9faf38d7c33de46d4de6f06e49426/grpcio-1.75.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:8775036efe4ad2085975531d221535329f5dac99b6c2a854a995456098f99546", size = 11476125, upload-time = "2025-09-26T09:01:57.927Z" }, + { url = "https://files.pythonhosted.org/packages/14/85/21c71d674f03345ab183c634ecd889d3330177e27baea8d5d247a89b6442/grpcio-1.75.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb658f703468d7fbb5dcc4037c65391b7dc34f808ac46ed9136c24fc5eeb041d", size = 6246335, upload-time = "2025-09-26T09:02:00.76Z" }, + { url = "https://files.pythonhosted.org/packages/fd/db/3beb661bc56a385ae4fa6b0e70f6b91ac99d47afb726fe76aaff87ebb116/grpcio-1.75.1-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4b7177a1cdb3c51b02b0c0a256b0a72fdab719600a693e0e9037949efffb200b", size = 6916309, upload-time = "2025-09-26T09:02:02.894Z" }, + { url = "https://files.pythonhosted.org/packages/1e/9c/eda9fe57f2b84343d44c1b66cf3831c973ba29b078b16a27d4587a1fdd47/grpcio-1.75.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7d4fa6ccc3ec2e68a04f7b883d354d7fea22a34c44ce535a2f0c0049cf626ddf", size = 6435419, upload-time = "2025-09-26T09:02:05.055Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b8/090c98983e0a9d602e3f919a6e2d4e470a8b489452905f9a0fa472cac059/grpcio-1.75.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d86880ecaeb5b2f0a8afa63824de93adb8ebe4e49d0e51442532f4e08add7d6", size = 7064893, upload-time = "2025-09-26T09:02:07.275Z" }, + { url = "https://files.pythonhosted.org/packages/ec/c0/6d53d4dbbd00f8bd81571f5478d8a95528b716e0eddb4217cc7cb45aae5f/grpcio-1.75.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a8041d2f9e8a742aeae96f4b047ee44e73619f4f9d24565e84d5446c623673b6", size = 8011922, upload-time = "2025-09-26T09:02:09.527Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7c/48455b2d0c5949678d6982c3e31ea4d89df4e16131b03f7d5c590811cbe9/grpcio-1.75.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3652516048bf4c314ce12be37423c79829f46efffb390ad64149a10c6071e8de", size = 7466181, upload-time = "2025-09-26T09:02:12.279Z" }, + { url = "https://files.pythonhosted.org/packages/fd/12/04a0e79081e3170b6124f8cba9b6275871276be06c156ef981033f691880/grpcio-1.75.1-cp312-cp312-win32.whl", hash = "sha256:44b62345d8403975513af88da2f3d5cc76f73ca538ba46596f92a127c2aea945", size = 3938543, upload-time = "2025-09-26T09:02:14.77Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d7/11350d9d7fb5adc73d2b0ebf6ac1cc70135577701e607407fe6739a90021/grpcio-1.75.1-cp312-cp312-win_amd64.whl", hash = "sha256:b1e191c5c465fa777d4cafbaacf0c01e0d5278022082c0abbd2ee1d6454ed94d", size = 4641938, upload-time = "2025-09-26T09:02:16.927Z" }, + { url = "https://files.pythonhosted.org/packages/46/74/bac4ab9f7722164afdf263ae31ba97b8174c667153510322a5eba4194c32/grpcio-1.75.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:3bed22e750d91d53d9e31e0af35a7b0b51367e974e14a4ff229db5b207647884", size = 5672779, upload-time = "2025-09-26T09:02:19.11Z" }, + { url = "https://files.pythonhosted.org/packages/a6/52/d0483cfa667cddaa294e3ab88fd2c2a6e9dc1a1928c0e5911e2e54bd5b50/grpcio-1.75.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:5b8f381eadcd6ecaa143a21e9e80a26424c76a0a9b3d546febe6648f3a36a5ac", size = 11470623, upload-time = "2025-09-26T09:02:22.117Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e4/d1954dce2972e32384db6a30273275e8c8ea5a44b80347f9055589333b3f/grpcio-1.75.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5bf4001d3293e3414d0cf99ff9b1139106e57c3a66dfff0c5f60b2a6286ec133", size = 6248838, upload-time = "2025-09-26T09:02:26.426Z" }, + { url = "https://files.pythonhosted.org/packages/06/43/073363bf63826ba8077c335d797a8d026f129dc0912b69c42feaf8f0cd26/grpcio-1.75.1-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f82ff474103e26351dacfe8d50214e7c9322960d8d07ba7fa1d05ff981c8b2d", size = 6922663, upload-time = "2025-09-26T09:02:28.724Z" }, + { url = "https://files.pythonhosted.org/packages/c2/6f/076ac0df6c359117676cacfa8a377e2abcecec6a6599a15a672d331f6680/grpcio-1.75.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0ee119f4f88d9f75414217823d21d75bfe0e6ed40135b0cbbfc6376bc9f7757d", size = 6436149, upload-time = "2025-09-26T09:02:30.971Z" }, + { url = "https://files.pythonhosted.org/packages/6b/27/1d08824f1d573fcb1fa35ede40d6020e68a04391709939e1c6f4193b445f/grpcio-1.75.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:664eecc3abe6d916fa6cf8dd6b778e62fb264a70f3430a3180995bf2da935446", size = 7067989, upload-time = "2025-09-26T09:02:33.233Z" }, + { url = "https://files.pythonhosted.org/packages/c6/98/98594cf97b8713feb06a8cb04eeef60b4757e3e2fb91aa0d9161da769843/grpcio-1.75.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c32193fa08b2fbebf08fe08e84f8a0aad32d87c3ad42999c65e9449871b1c66e", size = 8010717, upload-time = "2025-09-26T09:02:36.011Z" }, + { url = "https://files.pythonhosted.org/packages/8c/7e/bb80b1bba03c12158f9254762cdf5cced4a9bc2e8ed51ed335915a5a06ef/grpcio-1.75.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5cebe13088b9254f6e615bcf1da9131d46cfa4e88039454aca9cb65f639bd3bc", size = 7463822, upload-time = "2025-09-26T09:02:38.26Z" }, + { url = "https://files.pythonhosted.org/packages/23/1c/1ea57fdc06927eb5640f6750c697f596f26183573069189eeaf6ef86ba2d/grpcio-1.75.1-cp313-cp313-win32.whl", hash = "sha256:4b4c678e7ed50f8ae8b8dbad15a865ee73ce12668b6aaf411bf3258b5bc3f970", size = 3938490, upload-time = "2025-09-26T09:02:40.268Z" }, + { url = "https://files.pythonhosted.org/packages/4b/24/fbb8ff1ccadfbf78ad2401c41aceaf02b0d782c084530d8871ddd69a2d49/grpcio-1.75.1-cp313-cp313-win_amd64.whl", hash = "sha256:5573f51e3f296a1bcf71e7a690c092845fb223072120f4bdb7a5b48e111def66", size = 4642538, upload-time = "2025-09-26T09:02:42.519Z" }, + { url = "https://files.pythonhosted.org/packages/f2/1b/9a0a5cecd24302b9fdbcd55d15ed6267e5f3d5b898ff9ac8cbe17ee76129/grpcio-1.75.1-cp314-cp314-linux_armv7l.whl", hash = "sha256:c05da79068dd96723793bffc8d0e64c45f316248417515f28d22204d9dae51c7", size = 5673319, upload-time = "2025-09-26T09:02:44.742Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ec/9d6959429a83fbf5df8549c591a8a52bb313976f6646b79852c4884e3225/grpcio-1.75.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06373a94fd16ec287116a825161dca179a0402d0c60674ceeec8c9fba344fe66", size = 11480347, upload-time = "2025-09-26T09:02:47.539Z" }, + { url = "https://files.pythonhosted.org/packages/09/7a/26da709e42c4565c3d7bf999a9569da96243ce34a8271a968dee810a7cf1/grpcio-1.75.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4484f4b7287bdaa7a5b3980f3c7224c3c622669405d20f69549f5fb956ad0421", size = 6254706, upload-time = "2025-09-26T09:02:50.4Z" }, + { url = "https://files.pythonhosted.org/packages/f1/08/dcb26a319d3725f199c97e671d904d84ee5680de57d74c566a991cfab632/grpcio-1.75.1-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2720c239c1180eee69f7883c1d4c83fc1a495a2535b5fa322887c70bf02b16e8", size = 6922501, upload-time = "2025-09-26T09:02:52.711Z" }, + { url = "https://files.pythonhosted.org/packages/78/66/044d412c98408a5e23cb348845979a2d17a2e2b6c3c34c1ec91b920f49d0/grpcio-1.75.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:07a554fa31c668cf0e7a188678ceeca3cb8fead29bbe455352e712ec33ca701c", size = 6437492, upload-time = "2025-09-26T09:02:55.542Z" }, + { url = "https://files.pythonhosted.org/packages/4e/9d/5e3e362815152aa1afd8b26ea613effa005962f9da0eec6e0e4527e7a7d1/grpcio-1.75.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3e71a2105210366bfc398eef7f57a664df99194f3520edb88b9c3a7e46ee0d64", size = 7081061, upload-time = "2025-09-26T09:02:58.261Z" }, + { url = "https://files.pythonhosted.org/packages/1e/1a/46615682a19e100f46e31ddba9ebc297c5a5ab9ddb47b35443ffadb8776c/grpcio-1.75.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8679aa8a5b67976776d3c6b0521e99d1c34db8a312a12bcfd78a7085cb9b604e", size = 8010849, upload-time = "2025-09-26T09:03:00.548Z" }, + { url = "https://files.pythonhosted.org/packages/67/8e/3204b94ac30b0f675ab1c06540ab5578660dc8b690db71854d3116f20d00/grpcio-1.75.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:aad1c774f4ebf0696a7f148a56d39a3432550612597331792528895258966dc0", size = 7464478, upload-time = "2025-09-26T09:03:03.096Z" }, + { url = "https://files.pythonhosted.org/packages/b7/97/2d90652b213863b2cf466d9c1260ca7e7b67a16780431b3eb1d0420e3d5b/grpcio-1.75.1-cp314-cp314-win32.whl", hash = "sha256:62ce42d9994446b307649cb2a23335fa8e927f7ab2cbf5fcb844d6acb4d85f9c", size = 4012672, upload-time = "2025-09-26T09:03:05.477Z" }, + { url = "https://files.pythonhosted.org/packages/f9/df/e2e6e9fc1c985cd1a59e6996a05647c720fe8a03b92f5ec2d60d366c531e/grpcio-1.75.1-cp314-cp314-win_amd64.whl", hash = "sha256:f86e92275710bea3000cb79feca1762dc0ad3b27830dd1a74e82ab321d4ee464", size = 4772475, upload-time = "2025-09-26T09:03:07.661Z" }, +] + +[[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.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/74/31/feeddfce1748c4a233ec1aa5b7396161c07ae1aa9b7bdbc9a72c3c7dd768/hf_xet-1.1.10.tar.gz", hash = "sha256:408aef343800a2102374a883f283ff29068055c111f003ff840733d3b715bb97", size = 487910, upload-time = "2025-09-12T20:10:27.12Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/a2/343e6d05de96908366bdc0081f2d8607d61200be2ac802769c4284cc65bd/hf_xet-1.1.10-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:686083aca1a6669bc85c21c0563551cbcdaa5cf7876a91f3d074a030b577231d", size = 2761466, upload-time = "2025-09-12T20:10:22.836Z" }, + { url = "https://files.pythonhosted.org/packages/31/f9/6215f948ac8f17566ee27af6430ea72045e0418ce757260248b483f4183b/hf_xet-1.1.10-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:71081925383b66b24eedff3013f8e6bbd41215c3338be4b94ba75fd75b21513b", size = 2623807, upload-time = "2025-09-12T20:10:21.118Z" }, + { url = "https://files.pythonhosted.org/packages/15/07/86397573efefff941e100367bbda0b21496ffcdb34db7ab51912994c32a2/hf_xet-1.1.10-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6bceb6361c80c1cc42b5a7b4e3efd90e64630bcf11224dcac50ef30a47e435", size = 3186960, upload-time = "2025-09-12T20:10:19.336Z" }, + { url = "https://files.pythonhosted.org/packages/01/a7/0b2e242b918cc30e1f91980f3c4b026ff2eedaf1e2ad96933bca164b2869/hf_xet-1.1.10-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eae7c1fc8a664e54753ffc235e11427ca61f4b0477d757cc4eb9ae374b69f09c", size = 3087167, upload-time = "2025-09-12T20:10:17.255Z" }, + { url = "https://files.pythonhosted.org/packages/4a/25/3e32ab61cc7145b11eee9d745988e2f0f4fafda81b25980eebf97d8cff15/hf_xet-1.1.10-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0a0005fd08f002180f7a12d4e13b22be277725bc23ed0529f8add5c7a6309c06", size = 3248612, upload-time = "2025-09-12T20:10:24.093Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3d/ab7109e607ed321afaa690f557a9ada6d6d164ec852fd6bf9979665dc3d6/hf_xet-1.1.10-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f900481cf6e362a6c549c61ff77468bd59d6dd082f3170a36acfef2eb6a6793f", size = 3353360, upload-time = "2025-09-12T20:10:25.563Z" }, + { url = "https://files.pythonhosted.org/packages/ee/0e/471f0a21db36e71a2f1752767ad77e92d8cde24e974e03d662931b1305ec/hf_xet-1.1.10-cp37-abi3-win_amd64.whl", hash = "sha256:5f54b19cc347c13235ae7ee98b330c26dd65ef1df47e5316ffb1e87713ca7045", size = 2804691, upload-time = "2025-09-12T20:10:28.433Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "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/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 = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.35.3" +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/10/7e/a0a97de7c73671863ca6b3f61fa12518caf35db37825e43d63a70956738c/huggingface_hub-0.35.3.tar.gz", hash = "sha256:350932eaa5cc6a4747efae85126ee220e4ef1b54e29d31c3b45c5612ddf0b32a", size = 461798, upload-time = "2025-09-29T14:29:58.625Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/a0/651f93d154cb72323358bf2bbae3e642bdb5d2f1bfc874d096f7cb159fa0/huggingface_hub-0.35.3-py3-none-any.whl", hash = "sha256:0e3a01829c19d86d03793e4577816fe3bdfc1602ac62c7fb220d593d351224ba", size = 564262, upload-time = "2025-09-29T14:29:55.813Z" }, +] + +[[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 = "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-metadata" +version = "8.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, +] + +[[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 = "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 = "jiter" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c0/a3bb4cc13aced219dd18191ea66e874266bd8aa7b96744e495e1c733aa2d/jiter-0.11.0.tar.gz", hash = "sha256:1d9637eaf8c1d6a63d6562f2a6e5ab3af946c66037eb1b894e8fad75422266e4", size = 167094, upload-time = "2025-09-15T09:20:38.212Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/b5/3009b112b8f673e568ef79af9863d8309a15f0a8cdcc06ed6092051f377e/jiter-0.11.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:2fb7b377688cc3850bbe5c192a6bd493562a0bc50cbc8b047316428fbae00ada", size = 305510, upload-time = "2025-09-15T09:19:25.893Z" }, + { url = "https://files.pythonhosted.org/packages/fe/82/15514244e03b9e71e086bbe2a6de3e4616b48f07d5f834200c873956fb8c/jiter-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1b7cbe3f25bd0d8abb468ba4302a5d45617ee61b2a7a638f63fee1dc086be99", size = 316521, upload-time = "2025-09-15T09:19:27.525Z" }, + { url = "https://files.pythonhosted.org/packages/92/94/7a2e905f40ad2d6d660e00b68d818f9e29fb87ffe82774f06191e93cbe4a/jiter-0.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0a7f0ec81d5b7588c5cade1eb1925b91436ae6726dc2df2348524aeabad5de6", size = 338214, upload-time = "2025-09-15T09:19:28.727Z" }, + { url = "https://files.pythonhosted.org/packages/a8/9c/5791ed5bdc76f12110158d3316a7a3ec0b1413d018b41c5ed399549d3ad5/jiter-0.11.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07630bb46ea2a6b9c6ed986c6e17e35b26148cce2c535454b26ee3f0e8dcaba1", size = 361280, upload-time = "2025-09-15T09:19:30.013Z" }, + { url = "https://files.pythonhosted.org/packages/d4/7f/b7d82d77ff0d2cb06424141000176b53a9e6b16a1125525bb51ea4990c2e/jiter-0.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7764f27d28cd4a9cbc61704dfcd80c903ce3aad106a37902d3270cd6673d17f4", size = 487895, upload-time = "2025-09-15T09:19:31.424Z" }, + { url = "https://files.pythonhosted.org/packages/42/44/10a1475d46f1fc1fd5cc2e82c58e7bca0ce5852208e0fa5df2f949353321/jiter-0.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d4a6c4a737d486f77f842aeb22807edecb4a9417e6700c7b981e16d34ba7c72", size = 378421, upload-time = "2025-09-15T09:19:32.746Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5f/0dc34563d8164d31d07bc09d141d3da08157a68dcd1f9b886fa4e917805b/jiter-0.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf408d2a0abd919b60de8c2e7bc5eeab72d4dafd18784152acc7c9adc3291591", size = 347932, upload-time = "2025-09-15T09:19:34.612Z" }, + { url = "https://files.pythonhosted.org/packages/f7/de/b68f32a4fcb7b4a682b37c73a0e5dae32180140cd1caf11aef6ad40ddbf2/jiter-0.11.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cdef53eda7d18e799625023e1e250dbc18fbc275153039b873ec74d7e8883e09", size = 386959, upload-time = "2025-09-15T09:19:35.994Z" }, + { url = "https://files.pythonhosted.org/packages/76/0a/c08c92e713b6e28972a846a81ce374883dac2f78ec6f39a0dad9f2339c3a/jiter-0.11.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:53933a38ef7b551dd9c7f1064f9d7bb235bb3168d0fa5f14f0798d1b7ea0d9c5", size = 517187, upload-time = "2025-09-15T09:19:37.426Z" }, + { url = "https://files.pythonhosted.org/packages/89/b5/4a283bec43b15aad54fcae18d951f06a2ec3f78db5708d3b59a48e9c3fbd/jiter-0.11.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:11840d2324c9ab5162fc1abba23bc922124fedcff0d7b7f85fffa291e2f69206", size = 509461, upload-time = "2025-09-15T09:19:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/34/a5/f8bad793010534ea73c985caaeef8cc22dfb1fedb15220ecdf15c623c07a/jiter-0.11.0-cp312-cp312-win32.whl", hash = "sha256:4f01a744d24a5f2bb4a11657a1b27b61dc038ae2e674621a74020406e08f749b", size = 206664, upload-time = "2025-09-15T09:19:40.096Z" }, + { url = "https://files.pythonhosted.org/packages/ed/42/5823ec2b1469395a160b4bf5f14326b4a098f3b6898fbd327366789fa5d3/jiter-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:29fff31190ab3a26de026da2f187814f4b9c6695361e20a9ac2123e4d4378a4c", size = 203520, upload-time = "2025-09-15T09:19:41.798Z" }, + { url = "https://files.pythonhosted.org/packages/97/c4/d530e514d0f4f29b2b68145e7b389cbc7cac7f9c8c23df43b04d3d10fa3e/jiter-0.11.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4441a91b80a80249f9a6452c14b2c24708f139f64de959943dfeaa6cb915e8eb", size = 305021, upload-time = "2025-09-15T09:19:43.523Z" }, + { url = "https://files.pythonhosted.org/packages/7a/77/796a19c567c5734cbfc736a6f987affc0d5f240af8e12063c0fb93990ffa/jiter-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ff85fc6d2a431251ad82dbd1ea953affb5a60376b62e7d6809c5cd058bb39471", size = 314384, upload-time = "2025-09-15T09:19:44.849Z" }, + { url = "https://files.pythonhosted.org/packages/14/9c/824334de0b037b91b6f3fa9fe5a191c83977c7ec4abe17795d3cb6d174cf/jiter-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5e86126d64706fd28dfc46f910d496923c6f95b395138c02d0e252947f452bd", size = 337389, upload-time = "2025-09-15T09:19:46.094Z" }, + { url = "https://files.pythonhosted.org/packages/a2/95/ed4feab69e6cf9b2176ea29d4ef9d01a01db210a3a2c8a31a44ecdc68c38/jiter-0.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad8bd82165961867a10f52010590ce0b7a8c53da5ddd8bbb62fef68c181b921", size = 360519, upload-time = "2025-09-15T09:19:47.494Z" }, + { url = "https://files.pythonhosted.org/packages/b5/0c/2ad00f38d3e583caba3909d95b7da1c3a7cd82c0aa81ff4317a8016fb581/jiter-0.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b42c2cd74273455ce439fd9528db0c6e84b5623cb74572305bdd9f2f2961d3df", size = 487198, upload-time = "2025-09-15T09:19:49.116Z" }, + { url = "https://files.pythonhosted.org/packages/ea/8b/919b64cf3499b79bdfba6036da7b0cac5d62d5c75a28fb45bad7819e22f0/jiter-0.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0062dab98172dd0599fcdbf90214d0dcde070b1ff38a00cc1b90e111f071982", size = 377835, upload-time = "2025-09-15T09:19:50.468Z" }, + { url = "https://files.pythonhosted.org/packages/29/7f/8ebe15b6e0a8026b0d286c083b553779b4dd63db35b43a3f171b544de91d/jiter-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb948402821bc76d1f6ef0f9e19b816f9b09f8577844ba7140f0b6afe994bc64", size = 347655, upload-time = "2025-09-15T09:19:51.726Z" }, + { url = "https://files.pythonhosted.org/packages/8e/64/332127cef7e94ac75719dda07b9a472af6158ba819088d87f17f3226a769/jiter-0.11.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25a5b1110cca7329fd0daf5060faa1234be5c11e988948e4f1a1923b6a457fe1", size = 386135, upload-time = "2025-09-15T09:19:53.075Z" }, + { url = "https://files.pythonhosted.org/packages/20/c8/557b63527442f84c14774159948262a9d4fabb0d61166f11568f22fc60d2/jiter-0.11.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:bf11807e802a214daf6c485037778843fadd3e2ec29377ae17e0706ec1a25758", size = 516063, upload-time = "2025-09-15T09:19:54.447Z" }, + { url = "https://files.pythonhosted.org/packages/86/13/4164c819df4a43cdc8047f9a42880f0ceef5afeb22e8b9675c0528ebdccd/jiter-0.11.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:dbb57da40631c267861dd0090461222060960012d70fd6e4c799b0f62d0ba166", size = 508139, upload-time = "2025-09-15T09:19:55.764Z" }, + { url = "https://files.pythonhosted.org/packages/fa/70/6e06929b401b331d41ddb4afb9f91cd1168218e3371972f0afa51c9f3c31/jiter-0.11.0-cp313-cp313-win32.whl", hash = "sha256:8e36924dad32c48d3c5e188d169e71dc6e84d6cb8dedefea089de5739d1d2f80", size = 206369, upload-time = "2025-09-15T09:19:57.048Z" }, + { url = "https://files.pythonhosted.org/packages/f4/0d/8185b8e15de6dce24f6afae63380e16377dd75686d56007baa4f29723ea1/jiter-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:452d13e4fd59698408087235259cebe67d9d49173b4dacb3e8d35ce4acf385d6", size = 202538, upload-time = "2025-09-15T09:19:58.35Z" }, + { url = "https://files.pythonhosted.org/packages/13/3a/d61707803260d59520721fa326babfae25e9573a88d8b7b9cb54c5423a59/jiter-0.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:089f9df9f69532d1339e83142438668f52c97cd22ee2d1195551c2b1a9e6cf33", size = 313737, upload-time = "2025-09-15T09:19:59.638Z" }, + { url = "https://files.pythonhosted.org/packages/cd/cc/c9f0eec5d00f2a1da89f6bdfac12b8afdf8d5ad974184863c75060026457/jiter-0.11.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29ed1fe69a8c69bf0f2a962d8d706c7b89b50f1332cd6b9fbda014f60bd03a03", size = 346183, upload-time = "2025-09-15T09:20:01.442Z" }, + { url = "https://files.pythonhosted.org/packages/a6/87/fc632776344e7aabbab05a95a0075476f418c5d29ab0f2eec672b7a1f0ac/jiter-0.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a4d71d7ea6ea8786291423fe209acf6f8d398a0759d03e7f24094acb8ab686ba", size = 204225, upload-time = "2025-09-15T09:20:03.102Z" }, + { url = "https://files.pythonhosted.org/packages/ee/3b/e7f45be7d3969bdf2e3cd4b816a7a1d272507cd0edd2d6dc4b07514f2d9a/jiter-0.11.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9a6dff27eca70930bdbe4cbb7c1a4ba8526e13b63dc808c0670083d2d51a4a72", size = 304414, upload-time = "2025-09-15T09:20:04.357Z" }, + { url = "https://files.pythonhosted.org/packages/06/32/13e8e0d152631fcc1907ceb4943711471be70496d14888ec6e92034e2caf/jiter-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ae2a7593a62132c7d4c2abbee80bbbb94fdc6d157e2c6cc966250c564ef774", size = 314223, upload-time = "2025-09-15T09:20:05.631Z" }, + { url = "https://files.pythonhosted.org/packages/0c/7e/abedd5b5a20ca083f778d96bba0d2366567fcecb0e6e34ff42640d5d7a18/jiter-0.11.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b13a431dba4b059e9e43019d3022346d009baf5066c24dcdea321a303cde9f0", size = 337306, upload-time = "2025-09-15T09:20:06.917Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e2/30d59bdc1204c86aa975ec72c48c482fee6633120ee9c3ab755e4dfefea8/jiter-0.11.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:af62e84ca3889604ebb645df3b0a3f3bcf6b92babbff642bd214616f57abb93a", size = 360565, upload-time = "2025-09-15T09:20:08.283Z" }, + { url = "https://files.pythonhosted.org/packages/fe/88/567288e0d2ed9fa8f7a3b425fdaf2cb82b998633c24fe0d98f5417321aa8/jiter-0.11.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6f3b32bb723246e6b351aecace52aba78adb8eeb4b2391630322dc30ff6c773", size = 486465, upload-time = "2025-09-15T09:20:09.613Z" }, + { url = "https://files.pythonhosted.org/packages/18/6e/7b72d09273214cadd15970e91dd5ed9634bee605176107db21e1e4205eb1/jiter-0.11.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:adcab442f4a099a358a7f562eaa54ed6456fb866e922c6545a717be51dbed7d7", size = 377581, upload-time = "2025-09-15T09:20:10.884Z" }, + { url = "https://files.pythonhosted.org/packages/58/52/4db456319f9d14deed325f70102577492e9d7e87cf7097bda9769a1fcacb/jiter-0.11.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9967c2ab338ee2b2c0102fd379ec2693c496abf71ffd47e4d791d1f593b68e2", size = 347102, upload-time = "2025-09-15T09:20:12.175Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b4/433d5703c38b26083aec7a733eb5be96f9c6085d0e270a87ca6482cbf049/jiter-0.11.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e7d0bed3b187af8b47a981d9742ddfc1d9b252a7235471ad6078e7e4e5fe75c2", size = 386477, upload-time = "2025-09-15T09:20:13.428Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7a/a60bfd9c55b55b07c5c441c5085f06420b6d493ce9db28d069cc5b45d9f3/jiter-0.11.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:f6fe0283e903ebc55f1a6cc569b8c1f3bf4abd026fed85e3ff8598a9e6f982f0", size = 516004, upload-time = "2025-09-15T09:20:14.848Z" }, + { url = "https://files.pythonhosted.org/packages/2e/46/f8363e5ecc179b4ed0ca6cb0a6d3bfc266078578c71ff30642ea2ce2f203/jiter-0.11.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5821e3d66606b29ae5b497230b304f1376f38137d69e35f8d2bd5f310ff73", size = 507855, upload-time = "2025-09-15T09:20:16.176Z" }, + { url = "https://files.pythonhosted.org/packages/90/33/396083357d51d7ff0f9805852c288af47480d30dd31d8abc74909b020761/jiter-0.11.0-cp314-cp314-win32.whl", hash = "sha256:c2d13ba7567ca8799f17c76ed56b1d49be30df996eb7fa33e46b62800562a5e2", size = 205802, upload-time = "2025-09-15T09:20:17.661Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ab/eb06ca556b2551d41de7d03bf2ee24285fa3d0c58c5f8d95c64c9c3281b1/jiter-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fb4790497369d134a07fc763cc88888c46f734abdd66f9fdf7865038bf3a8f40", size = 313405, upload-time = "2025-09-15T09:20:18.918Z" }, + { url = "https://files.pythonhosted.org/packages/af/22/7ab7b4ec3a1c1f03aef376af11d23b05abcca3fb31fbca1e7557053b1ba2/jiter-0.11.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e2bbf24f16ba5ad4441a9845e40e4ea0cb9eed00e76ba94050664ef53ef4406", size = 347102, upload-time = "2025-09-15T09:20:20.16Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpointer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" }, +] + +[[package]] +name = "jsonpointer" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "kubernetes" +version = "34.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "durationpy" }, + { name = "google-auth" }, + { name = "python-dateutil" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "requests-oauthlib" }, + { name = "six" }, + { name = "urllib3" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/55/3f880ef65f559cbed44a9aa20d3bdbc219a2c3a3bac4a30a513029b03ee9/kubernetes-34.1.0.tar.gz", hash = "sha256:8fe8edb0b5d290a2f3ac06596b23f87c658977d46b5f8df9d0f4ea83d0003912", size = 1083771, upload-time = "2025-09-29T20:23:49.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/ec/65f7d563aa4a62dd58777e8f6aa882f15db53b14eb29aba0c28a20f7eb26/kubernetes-34.1.0-py2.py3-none-any.whl", hash = "sha256:bffba2272534e224e6a7a74d582deb0b545b7c9879d2cd9e4aae9481d1f2cc2a", size = 2008380, upload-time = "2025-09-29T20:23:47.684Z" }, +] + +[[package]] +name = "langchain" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/d6/bdf9ea27a92ed4685497c2659b5c7f703ba63bac4bd92351ca09bab3b924/langchain-1.0.2.tar.gz", hash = "sha256:22f814c7b4f5f76e945c35924ff288f6dfbe33747db2a029162ef1d4f8566493", size = 473869, upload-time = "2025-10-21T21:08:26.44Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/06/0e03587da37173c29a58bf17312793c2453df9ca2912e9adfe869c120437/langchain-1.0.2-py3-none-any.whl", hash = "sha256:e0c5647ea47cde7feb9534f56f4496c7f86a45084ad9bd152e7b19739f210ead", size = 107831, upload-time = "2025-10-21T21:08:25.009Z" }, +] + +[[package]] +name = "langchain-chroma" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "chromadb" }, + { name = "langchain-core" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6c/b5/1dfb361793b217c7e8e791edebf5ecbbcc7fed2e9fd998b452c32c701c1f/langchain_chroma-1.0.0.tar.gz", hash = "sha256:ee82c6fbd0c94e5e9942e3b9302f69deea6c58c0e957ff16de6066d896d7a34a", size = 217313, upload-time = "2025-10-17T15:18:54.557Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/fd/36d8d37a257d7f5961cea9ef0e1a9616a4b4fc259cad2cbf02416de90215/langchain_chroma-1.0.0-py3-none-any.whl", hash = "sha256:b7adb991090f066f8d5e746a2d338de3116b192cec3990deef3052b7ea07324c", size = 12458, upload-time = "2025-10-17T15:18:53.325Z" }, +] + +[[package]] +name = "langchain-community" +version = "0.3.31" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "dataclasses-json" }, + { name = "httpx-sse" }, + { name = "langchain" }, + { name = "langchain-core" }, + { name = "langsmith" }, + { name = "numpy" }, + { name = "pydantic-settings" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sqlalchemy" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/49/2ff5354273809e9811392bc24bcffda545a196070666aef27bc6aacf1c21/langchain_community-0.3.31.tar.gz", hash = "sha256:250e4c1041539130f6d6ac6f9386cb018354eafccd917b01a4cff1950b80fd81", size = 33241237, upload-time = "2025-10-07T20:17:57.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl", hash = "sha256:1c727e3ebbacd4d891b07bd440647668001cea3e39cbe732499ad655ec5cb569", size = 2532920, upload-time = "2025-10-07T20:17:54.91Z" }, +] + +[[package]] +name = "langchain-core" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpatch" }, + { name = "langchain-protocol" }, + { name = "langsmith" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "uuid-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/59/de/679a53472c25860837e32c0442c962fa86e95317a36460e2c9d5c91b17c2/langchain_core-1.4.0.tar.gz", hash = "sha256:1dc341eed802ed9c117c0df3923c991e5e9e226571e5725c194eeb5bd93d1a7f", size = 920260, upload-time = "2026-05-11T18:42:35.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/1a/86c38c27b81913a1c6c12448cab55defb5a1097c7dc9a4cea83f55477a2d/langchain_core-1.4.0-py3-none-any.whl", hash = "sha256:23cbbdb46e38ddd1dd5247e6167e96013eae74bea4c5949c550809970a9e565c", size = 548120, upload-time = "2026-05-11T18:42:33.992Z" }, +] + +[[package]] +name = "langchain-openai" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "openai" }, + { name = "tiktoken" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/50/eaa53ac18f63b3e92e6c3a30269714cff477af5a568f486254779a9973f1/langchain_openai-1.0.1.tar.gz", hash = "sha256:78aff09a631fccca08a64f5fc669b325d0f5821490acce024e5da4cf0a08e0d0", size = 1025305, upload-time = "2025-10-21T15:45:06.095Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/c0/06d74093e3e798eb464ef76f53d031235b87feccdadbbf6f7b8409043e4d/langchain_openai-1.0.1-py3-none-any.whl", hash = "sha256:9b61309a7268e7c1c614c554cfd66401519e7434aaefc52de7e251887aceb5f7", size = 81898, upload-time = "2025-10-21T15:45:04.957Z" }, +] + +[[package]] +name = "langchain-protocol" +version = "0.0.15" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4f/24/9777489d6fbbee64af0c8f96d4f840239c408cf694f3394672807dafc490/langchain_protocol-0.0.15.tar.gz", hash = "sha256:9ab2d11ee73944754f10e037e717098d3a6796f0e58afa9cadda6154e7655ade", size = 5862, upload-time = "2026-05-01T22:30:04.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/7a/9c97a7b9cbe4c5dc6a44cdb1545450c28f0c8ce89b9c1f0ee7fbad896263/langchain_protocol-0.0.15-py3-none-any.whl", hash = "sha256:461eb794358f83d5e42635a5797799ffec7b4702314e34edf73ac21e75d3ef79", size = 6982, upload-time = "2026-05-01T22:30:03.877Z" }, +] + +[[package]] +name = "langchain-text-splitters" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/9f/6c545900fefb7b00ddfa3f16b80d61338a0ec68c31c5451eeeab99082760/langchain_text_splitters-1.1.2.tar.gz", hash = "sha256:782a723db0a4746ac91e251c7c1d57fd23636e4f38ed733074e28d7a86f41627", size = 293580, upload-time = "2026-04-16T14:20:39.162Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/26/1ef06f56198d631296d646a6223de35bcc6cf9795ceb2442816bc963b84c/langchain_text_splitters-1.1.2-py3-none-any.whl", hash = "sha256:a2de0d799ff31886429fd6e2e0032df275b60ec817c19059a7b46181cc1c2f10", size = 35903, upload-time = "2026-04-16T14:20:38.243Z" }, +] + +[[package]] +name = "langgraph" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, + { name = "langgraph-prebuilt" }, + { name = "langgraph-sdk" }, + { name = "pydantic" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/7c/a0f4211f751b8b37aae2d88c6243ceb14027ca9ebf00ac8f3b210657af6a/langgraph-1.0.1.tar.gz", hash = "sha256:4985b32ceabb046a802621660836355dfcf2402c5876675dc353db684aa8f563", size = 480245, upload-time = "2025-10-20T18:51:59.839Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/3c/acc0956a0da96b25a2c5c1a85168eacf1253639a04ed391d7a7bcaae5d6c/langgraph-1.0.1-py3-none-any.whl", hash = "sha256:892f04f64f4889abc80140265cc6bd57823dd8e327a5eef4968875f2cd9013bd", size = 155415, upload-time = "2025-10-20T18:51:58.321Z" }, +] + +[[package]] +name = "langgraph-checkpoint" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "ormsgpack" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/83/6404f6ed23a91d7bc63d7df902d144548434237d017820ceaa8d014035f2/langgraph_checkpoint-2.1.2.tar.gz", hash = "sha256:112e9d067a6eff8937caf198421b1ffba8d9207193f14ac6f89930c1260c06f9", size = 142420, upload-time = "2025-10-07T17:45:17.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/f2/06bf5addf8ee664291e1b9ffa1f28fc9d97e59806dc7de5aea9844cbf335/langgraph_checkpoint-2.1.2-py3-none-any.whl", hash = "sha256:911ebffb069fd01775d4b5184c04aaafc2962fcdf50cf49d524cd4367c4d0c60", size = 45763, upload-time = "2025-10-07T17:45:16.19Z" }, +] + +[[package]] +name = "langgraph-prebuilt" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/b6/2bcb992acf67713a3557e51c1955854672ec6c1abe6ba51173a87eb8d825/langgraph_prebuilt-1.0.1.tar.gz", hash = "sha256:ecbfb9024d9d7ed9652dde24eef894650aaab96bf79228e862c503e2a060b469", size = 119918, upload-time = "2025-10-20T18:49:55.991Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/47/9ffd10882403020ea866e381de7f8e504a78f606a914af7f8244456c7783/langgraph_prebuilt-1.0.1-py3-none-any.whl", hash = "sha256:8c02e023538f7ef6ad5ed76219ba1ab4f6de0e31b749e4d278f57a8a95eec9f7", size = 28458, upload-time = "2025-10-20T18:49:54.723Z" }, +] + +[[package]] +name = "langgraph-sdk" +version = "0.2.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/d8/40e01190a73c564a4744e29a6c902f78d34d43dad9b652a363a92a67059c/langgraph_sdk-0.2.9.tar.gz", hash = "sha256:b3bd04c6be4fa382996cd2be8fbc1e7cc94857d2bc6b6f4599a7f2a245975303", size = 99802, upload-time = "2025-09-20T18:49:14.734Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/05/b2d34e16638241e6f27a6946d28160d4b8b641383787646d41a3727e0896/langgraph_sdk-0.2.9-py3-none-any.whl", hash = "sha256:fbf302edadbf0fb343596f91c597794e936ef68eebc0d3e1d358b6f9f72a1429", size = 56752, upload-time = "2025-09-20T18:49:13.346Z" }, +] + +[[package]] +name = "langsmith" +version = "0.4.34" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "requests-toolbelt" }, + { name = "zstandard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/5d/38887a18b68aa7acbac040c1fad2f2217c55d3eef7784d0412261fe37513/langsmith-0.4.34.tar.gz", hash = "sha256:5b90c0b49ab03f78331005df1591abd86b41afceda6ac7144ad7d23693c62f31", size = 964392, upload-time = "2025-10-09T23:34:26.359Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/a4/db5903757d710c4c401e7a87f6ba53a8242c580e8c1df5869b7acb949b2d/langsmith-0.4.34-py3-none-any.whl", hash = "sha256:3b83b2544f99bb8f6fca2681ee80fe6a44b0578c29e809e5a4e72fdee4db9146", size = 386981, upload-time = "2025-10-09T23:34:24.386Z" }, +] + +[[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/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" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markdownify" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/1b/6f2697b51eaca81f08852fd2734745af15718fea10222a1d40f8a239c4ea/markdownify-1.2.0.tar.gz", hash = "sha256:f6c367c54eb24ee953921804dfe6d6575c5e5b42c643955e7242034435de634c", size = 18771, upload-time = "2025-08-09T17:44:15.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/e2/7af643acb4cae0741dffffaa7f3f7c9e7ab4046724543ba1777c401d821c/markdownify-1.2.0-py3-none-any.whl", hash = "sha256:48e150a1c4993d4d50f282f725c0111bd9eb25645d41fa2f543708fd44161351", size = 15561, upload-time = "2025-08-09T17:44:14.074Z" }, +] + +[[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/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 = "marshmallow" +version = "3.26.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/5e53d26b42ab75491cda89b871dab9e97c840bf12c63ec58a1919710cd06/marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6", size = 221825, upload-time = "2025-02-03T15:32:25.093Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/75/51952c7b2d3873b44a0028b1bd26a25078c18f92f256608e8d1dc61b39fd/marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c", size = 50878, upload-time = "2025-02-03T15:32:22.295Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mmh3" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/af/f28c2c2f51f31abb4725f9a64bc7863d5f491f6539bd26aee2a1d21a649e/mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8", size = 33582, upload-time = "2025-07-29T07:43:48.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/6a/d5aa7edb5c08e0bd24286c7d08341a0446f9a2fbbb97d96a8a6dd81935ee/mmh3-5.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:384eda9361a7bf83a85e09447e1feafe081034af9dd428893701b959230d84be", size = 56141, upload-time = "2025-07-29T07:42:13.456Z" }, + { url = "https://files.pythonhosted.org/packages/08/49/131d0fae6447bc4a7299ebdb1a6fb9d08c9f8dcf97d75ea93e8152ddf7ab/mmh3-5.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c9da0d568569cc87315cb063486d761e38458b8ad513fedd3dc9263e1b81bcd", size = 40681, upload-time = "2025-07-29T07:42:14.306Z" }, + { url = "https://files.pythonhosted.org/packages/8f/6f/9221445a6bcc962b7f5ff3ba18ad55bba624bacdc7aa3fc0a518db7da8ec/mmh3-5.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86d1be5d63232e6eb93c50881aea55ff06eb86d8e08f9b5417c8c9b10db9db96", size = 40062, upload-time = "2025-07-29T07:42:15.08Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d4/6bb2d0fef81401e0bb4c297d1eb568b767de4ce6fc00890bc14d7b51ecc4/mmh3-5.2.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bf7bee43e17e81671c447e9c83499f53d99bf440bc6d9dc26a841e21acfbe094", size = 97333, upload-time = "2025-07-29T07:42:16.436Z" }, + { url = "https://files.pythonhosted.org/packages/44/e0/ccf0daff8134efbb4fbc10a945ab53302e358c4b016ada9bf97a6bdd50c1/mmh3-5.2.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7aa18cdb58983ee660c9c400b46272e14fa253c675ed963d3812487f8ca42037", size = 103310, upload-time = "2025-07-29T07:42:17.796Z" }, + { url = "https://files.pythonhosted.org/packages/02/63/1965cb08a46533faca0e420e06aff8bbaf9690a6f0ac6ae6e5b2e4544687/mmh3-5.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9d032488fcec32d22be6542d1a836f00247f40f320844dbb361393b5b22773", size = 106178, upload-time = "2025-07-29T07:42:19.281Z" }, + { url = "https://files.pythonhosted.org/packages/c2/41/c883ad8e2c234013f27f92061200afc11554ea55edd1bcf5e1accd803a85/mmh3-5.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1861fb6b1d0453ed7293200139c0a9011eeb1376632e048e3766945b13313c5", size = 113035, upload-time = "2025-07-29T07:42:20.356Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/1ccade8b1fa625d634a18bab7bf08a87457e09d5ec8cf83ca07cbea9d400/mmh3-5.2.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:99bb6a4d809aa4e528ddfe2c85dd5239b78b9dd14be62cca0329db78505e7b50", size = 120784, upload-time = "2025-07-29T07:42:21.377Z" }, + { url = "https://files.pythonhosted.org/packages/77/1c/919d9171fcbdcdab242e06394464ccf546f7d0f3b31e0d1e3a630398782e/mmh3-5.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1f8d8b627799f4e2fcc7c034fed8f5f24dc7724ff52f69838a3d6d15f1ad4765", size = 99137, upload-time = "2025-07-29T07:42:22.344Z" }, + { url = "https://files.pythonhosted.org/packages/66/8a/1eebef5bd6633d36281d9fc83cf2e9ba1ba0e1a77dff92aacab83001cee4/mmh3-5.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b5995088dd7023d2d9f310a0c67de5a2b2e06a570ecfd00f9ff4ab94a67cde43", size = 98664, upload-time = "2025-07-29T07:42:23.269Z" }, + { url = "https://files.pythonhosted.org/packages/13/41/a5d981563e2ee682b21fb65e29cc0f517a6734a02b581359edd67f9d0360/mmh3-5.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1a5f4d2e59d6bba8ef01b013c472741835ad961e7c28f50c82b27c57748744a4", size = 106459, upload-time = "2025-07-29T07:42:24.238Z" }, + { url = "https://files.pythonhosted.org/packages/24/31/342494cd6ab792d81e083680875a2c50fa0c5df475ebf0b67784f13e4647/mmh3-5.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fd6e6c3d90660d085f7e73710eab6f5545d4854b81b0135a3526e797009dbda3", size = 110038, upload-time = "2025-07-29T07:42:25.629Z" }, + { url = "https://files.pythonhosted.org/packages/28/44/efda282170a46bb4f19c3e2b90536513b1d821c414c28469a227ca5a1789/mmh3-5.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c4a2f3d83879e3de2eb8cbf562e71563a8ed15ee9b9c2e77ca5d9f73072ac15c", size = 97545, upload-time = "2025-07-29T07:42:27.04Z" }, + { url = "https://files.pythonhosted.org/packages/68/8f/534ae319c6e05d714f437e7206f78c17e66daca88164dff70286b0e8ea0c/mmh3-5.2.0-cp312-cp312-win32.whl", hash = "sha256:2421b9d665a0b1ad724ec7332fb5a98d075f50bc51a6ff854f3a1882bd650d49", size = 40805, upload-time = "2025-07-29T07:42:28.032Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f6/f6abdcfefcedab3c964868048cfe472764ed358c2bf6819a70dd4ed4ed3a/mmh3-5.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:72d80005b7634a3a2220f81fbeb94775ebd12794623bb2e1451701ea732b4aa3", size = 41597, upload-time = "2025-07-29T07:42:28.894Z" }, + { url = "https://files.pythonhosted.org/packages/15/fd/f7420e8cbce45c259c770cac5718badf907b302d3a99ec587ba5ce030237/mmh3-5.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:3d6bfd9662a20c054bc216f861fa330c2dac7c81e7fb8307b5e32ab5b9b4d2e0", size = 39350, upload-time = "2025-07-29T07:42:29.794Z" }, + { url = "https://files.pythonhosted.org/packages/d8/fa/27f6ab93995ef6ad9f940e96593c5dd24744d61a7389532b0fec03745607/mmh3-5.2.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:e79c00eba78f7258e5b354eccd4d7907d60317ced924ea4a5f2e9d83f5453065", size = 40874, upload-time = "2025-07-29T07:42:30.662Z" }, + { url = "https://files.pythonhosted.org/packages/11/9c/03d13bcb6a03438bc8cac3d2e50f80908d159b31a4367c2e1a7a077ded32/mmh3-5.2.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:956127e663d05edbeec54df38885d943dfa27406594c411139690485128525de", size = 42012, upload-time = "2025-07-29T07:42:31.539Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/0865d9765408a7d504f1789944e678f74e0888b96a766d578cb80b040999/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c3dca4cb5b946ee91b3d6bb700d137b1cd85c20827f89fdf9c16258253489044", size = 39197, upload-time = "2025-07-29T07:42:32.374Z" }, + { url = "https://files.pythonhosted.org/packages/3e/12/76c3207bd186f98b908b6706c2317abb73756d23a4e68ea2bc94825b9015/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e651e17bfde5840e9e4174b01e9e080ce49277b70d424308b36a7969d0d1af73", size = 39840, upload-time = "2025-07-29T07:42:33.227Z" }, + { url = "https://files.pythonhosted.org/packages/5d/0d/574b6cce5555c9f2b31ea189ad44986755eb14e8862db28c8b834b8b64dc/mmh3-5.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:9f64bf06f4bf623325fda3a6d02d36cd69199b9ace99b04bb2d7fd9f89688504", size = 40644, upload-time = "2025-07-29T07:42:34.099Z" }, + { url = "https://files.pythonhosted.org/packages/52/82/3731f8640b79c46707f53ed72034a58baad400be908c87b0088f1f89f986/mmh3-5.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ddc63328889bcaee77b743309e5c7d2d52cee0d7d577837c91b6e7cc9e755e0b", size = 56153, upload-time = "2025-07-29T07:42:35.031Z" }, + { url = "https://files.pythonhosted.org/packages/4f/34/e02dca1d4727fd9fdeaff9e2ad6983e1552804ce1d92cc796e5b052159bb/mmh3-5.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb0fdc451fb6d86d81ab8f23d881b8d6e37fc373a2deae1c02d27002d2ad7a05", size = 40684, upload-time = "2025-07-29T07:42:35.914Z" }, + { url = "https://files.pythonhosted.org/packages/8f/36/3dee40767356e104967e6ed6d102ba47b0b1ce2a89432239b95a94de1b89/mmh3-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b29044e1ffdb84fe164d0a7ea05c7316afea93c00f8ed9449cf357c36fc4f814", size = 40057, upload-time = "2025-07-29T07:42:36.755Z" }, + { url = "https://files.pythonhosted.org/packages/31/58/228c402fccf76eb39a0a01b8fc470fecf21965584e66453b477050ee0e99/mmh3-5.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:58981d6ea9646dbbf9e59a30890cbf9f610df0e4a57dbfe09215116fd90b0093", size = 97344, upload-time = "2025-07-29T07:42:37.675Z" }, + { url = "https://files.pythonhosted.org/packages/34/82/fc5ce89006389a6426ef28e326fc065b0fbaaed230373b62d14c889f47ea/mmh3-5.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e5634565367b6d98dc4aa2983703526ef556b3688ba3065edb4b9b90ede1c54", size = 103325, upload-time = "2025-07-29T07:42:38.591Z" }, + { url = "https://files.pythonhosted.org/packages/09/8c/261e85777c6aee1ebd53f2f17e210e7481d5b0846cd0b4a5c45f1e3761b8/mmh3-5.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0271ac12415afd3171ab9a3c7cbfc71dee2c68760a7dc9d05bf8ed6ddfa3a7a", size = 106240, upload-time = "2025-07-29T07:42:39.563Z" }, + { url = "https://files.pythonhosted.org/packages/70/73/2f76b3ad8a3d431824e9934403df36c0ddacc7831acf82114bce3c4309c8/mmh3-5.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:45b590e31bc552c6f8e2150ff1ad0c28dd151e9f87589e7eaf508fbdd8e8e908", size = 113060, upload-time = "2025-07-29T07:42:40.585Z" }, + { url = "https://files.pythonhosted.org/packages/9f/b9/7ea61a34e90e50a79a9d87aa1c0b8139a7eaf4125782b34b7d7383472633/mmh3-5.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bdde97310d59604f2a9119322f61b31546748499a21b44f6715e8ced9308a6c5", size = 120781, upload-time = "2025-07-29T07:42:41.618Z" }, + { url = "https://files.pythonhosted.org/packages/0f/5b/ae1a717db98c7894a37aeedbd94b3f99e6472a836488f36b6849d003485b/mmh3-5.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc9c5f280438cf1c1a8f9abb87dc8ce9630a964120cfb5dd50d1e7ce79690c7a", size = 99174, upload-time = "2025-07-29T07:42:42.587Z" }, + { url = "https://files.pythonhosted.org/packages/e3/de/000cce1d799fceebb6d4487ae29175dd8e81b48e314cba7b4da90bcf55d7/mmh3-5.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c903e71fd8debb35ad2a4184c1316b3cb22f64ce517b4e6747f25b0a34e41266", size = 98734, upload-time = "2025-07-29T07:42:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/79/19/0dc364391a792b72fbb22becfdeacc5add85cc043cd16986e82152141883/mmh3-5.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:eed4bba7ff8a0d37106ba931ab03bdd3915fbb025bcf4e1f0aa02bc8114960c5", size = 106493, upload-time = "2025-07-29T07:42:45.07Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b1/bc8c28e4d6e807bbb051fefe78e1156d7f104b89948742ad310612ce240d/mmh3-5.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1fdb36b940e9261aff0b5177c5b74a36936b902f473180f6c15bde26143681a9", size = 110089, upload-time = "2025-07-29T07:42:46.122Z" }, + { url = "https://files.pythonhosted.org/packages/3b/a2/d20f3f5c95e9c511806686c70d0a15479cc3941c5f322061697af1c1ff70/mmh3-5.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7303aab41e97adcf010a09efd8f1403e719e59b7705d5e3cfed3dd7571589290", size = 97571, upload-time = "2025-07-29T07:42:47.18Z" }, + { url = "https://files.pythonhosted.org/packages/7b/23/665296fce4f33488deec39a750ffd245cfc07aafb0e3ef37835f91775d14/mmh3-5.2.0-cp313-cp313-win32.whl", hash = "sha256:03e08c6ebaf666ec1e3d6ea657a2d363bb01effd1a9acfe41f9197decaef0051", size = 40806, upload-time = "2025-07-29T07:42:48.166Z" }, + { url = "https://files.pythonhosted.org/packages/59/b0/92e7103f3b20646e255b699e2d0327ce53a3f250e44367a99dc8be0b7c7a/mmh3-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:7fddccd4113e7b736706e17a239a696332360cbaddf25ae75b57ba1acce65081", size = 41600, upload-time = "2025-07-29T07:42:49.371Z" }, + { url = "https://files.pythonhosted.org/packages/99/22/0b2bd679a84574647de538c5b07ccaa435dbccc37815067fe15b90fe8dad/mmh3-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa0c966ee727aad5406d516375593c5f058c766b21236ab8985693934bb5085b", size = 39349, upload-time = "2025-07-29T07:42:50.268Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ca/a20db059a8a47048aaf550da14a145b56e9c7386fb8280d3ce2962dcebf7/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e5015f0bb6eb50008bed2d4b1ce0f2a294698a926111e4bb202c0987b4f89078", size = 39209, upload-time = "2025-07-29T07:42:51.559Z" }, + { url = "https://files.pythonhosted.org/packages/98/dd/e5094799d55c7482d814b979a0fd608027d0af1b274bfb4c3ea3e950bfd5/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0f3ed828d709f5b82d8bfe14f8856120718ec4bd44a5b26102c3030a1e12501", size = 39843, upload-time = "2025-07-29T07:42:52.536Z" }, + { url = "https://files.pythonhosted.org/packages/f4/6b/7844d7f832c85400e7cc89a1348e4e1fdd38c5a38415bb5726bbb8fcdb6c/mmh3-5.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:f35727c5118aba95f0397e18a1a5b8405425581bfe53e821f0fb444cbdc2bc9b", size = 40648, upload-time = "2025-07-29T07:42:53.392Z" }, + { url = "https://files.pythonhosted.org/packages/1f/bf/71f791f48a21ff3190ba5225807cbe4f7223360e96862c376e6e3fb7efa7/mmh3-5.2.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bc244802ccab5220008cb712ca1508cb6a12f0eb64ad62997156410579a1770", size = 56164, upload-time = "2025-07-29T07:42:54.267Z" }, + { url = "https://files.pythonhosted.org/packages/70/1f/f87e3d34d83032b4f3f0f528c6d95a98290fcacf019da61343a49dccfd51/mmh3-5.2.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ff3d50dc3fe8a98059f99b445dfb62792b5d006c5e0b8f03c6de2813b8376110", size = 40692, upload-time = "2025-07-29T07:42:55.234Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e2/db849eaed07117086f3452feca8c839d30d38b830ac59fe1ce65af8be5ad/mmh3-5.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:37a358cc881fe796e099c1db6ce07ff757f088827b4e8467ac52b7a7ffdca647", size = 40068, upload-time = "2025-07-29T07:42:56.158Z" }, + { url = "https://files.pythonhosted.org/packages/df/6b/209af927207af77425b044e32f77f49105a0b05d82ff88af6971d8da4e19/mmh3-5.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b9a87025121d1c448f24f27ff53a5fe7b6ef980574b4a4f11acaabe702420d63", size = 97367, upload-time = "2025-07-29T07:42:57.037Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e0/78adf4104c425606a9ce33fb351f790c76a6c2314969c4a517d1ffc92196/mmh3-5.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ba55d6ca32eeef8b2625e1e4bfc3b3db52bc63014bd7e5df8cc11bf2b036b12", size = 103306, upload-time = "2025-07-29T07:42:58.522Z" }, + { url = "https://files.pythonhosted.org/packages/a3/79/c2b89f91b962658b890104745b1b6c9ce38d50a889f000b469b91eeb1b9e/mmh3-5.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9ff37ba9f15637e424c2ab57a1a590c52897c845b768e4e0a4958084ec87f22", size = 106312, upload-time = "2025-07-29T07:42:59.552Z" }, + { url = "https://files.pythonhosted.org/packages/4b/14/659d4095528b1a209be90934778c5ffe312177d51e365ddcbca2cac2ec7c/mmh3-5.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a094319ec0db52a04af9fdc391b4d39a1bc72bc8424b47c4411afb05413a44b5", size = 113135, upload-time = "2025-07-29T07:43:00.745Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/cd7734a779389a8a467b5c89a48ff476d6f2576e78216a37551a97e9e42a/mmh3-5.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5584061fd3da584659b13587f26c6cad25a096246a481636d64375d0c1f6c07", size = 120775, upload-time = "2025-07-29T07:43:02.124Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ca/8256e3b96944408940de3f9291d7e38a283b5761fe9614d4808fcf27bd62/mmh3-5.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecbfc0437ddfdced5e7822d1ce4855c9c64f46819d0fdc4482c53f56c707b935", size = 99178, upload-time = "2025-07-29T07:43:03.182Z" }, + { url = "https://files.pythonhosted.org/packages/8a/32/39e2b3cf06b6e2eb042c984dab8680841ac2a0d3ca6e0bea30db1f27b565/mmh3-5.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7b986d506a8e8ea345791897ba5d8ba0d9d8820cd4fc3e52dbe6de19388de2e7", size = 98738, upload-time = "2025-07-29T07:43:04.207Z" }, + { url = "https://files.pythonhosted.org/packages/61/d3/7bbc8e0e8cf65ebbe1b893ffa0467b7ecd1bd07c3bbf6c9db4308ada22ec/mmh3-5.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:38d899a156549da8ef6a9f1d6f7ef231228d29f8f69bce2ee12f5fba6d6fd7c5", size = 106510, upload-time = "2025-07-29T07:43:05.656Z" }, + { url = "https://files.pythonhosted.org/packages/10/99/b97e53724b52374e2f3859046f0eb2425192da356cb19784d64bc17bb1cf/mmh3-5.2.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d86651fa45799530885ba4dab3d21144486ed15285e8784181a0ab37a4552384", size = 110053, upload-time = "2025-07-29T07:43:07.204Z" }, + { url = "https://files.pythonhosted.org/packages/ac/62/3688c7d975ed195155671df68788c83fed6f7909b6ec4951724c6860cb97/mmh3-5.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c463d7c1c4cfc9d751efeaadd936bbba07b5b0ed81a012b3a9f5a12f0872bd6e", size = 97546, upload-time = "2025-07-29T07:43:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/ca/3b/c6153250f03f71a8b7634cded82939546cdfba02e32f124ff51d52c6f991/mmh3-5.2.0-cp314-cp314-win32.whl", hash = "sha256:bb4fe46bdc6104fbc28db7a6bacb115ee6368ff993366bbd8a2a7f0076e6f0c0", size = 41422, upload-time = "2025-07-29T07:43:09.216Z" }, + { url = "https://files.pythonhosted.org/packages/74/01/a27d98bab083a435c4c07e9d1d720d4c8a578bf4c270bae373760b1022be/mmh3-5.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c7f0b342fd06044bedd0b6e72177ddc0076f54fd89ee239447f8b271d919d9b", size = 42135, upload-time = "2025-07-29T07:43:10.183Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c9/dbba5507e95429b8b380e2ba091eff5c20a70a59560934dff0ad8392b8c8/mmh3-5.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:3193752fc05ea72366c2b63ff24b9a190f422e32d75fdeae71087c08fff26115", size = 39879, upload-time = "2025-07-29T07:43:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d1/c8c0ef839c17258b9de41b84f663574fabcf8ac2007b7416575e0f65ff6e/mmh3-5.2.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:69fc339d7202bea69ef9bd7c39bfdf9fdabc8e6822a01eba62fb43233c1b3932", size = 57696, upload-time = "2025-07-29T07:43:11.989Z" }, + { url = "https://files.pythonhosted.org/packages/2f/55/95e2b9ff201e89f9fe37036037ab61a6c941942b25cdb7b6a9df9b931993/mmh3-5.2.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:12da42c0a55c9d86ab566395324213c319c73ecb0c239fad4726324212b9441c", size = 41421, upload-time = "2025-07-29T07:43:13.269Z" }, + { url = "https://files.pythonhosted.org/packages/77/79/9be23ad0b7001a4b22752e7693be232428ecc0a35068a4ff5c2f14ef8b20/mmh3-5.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f7f9034c7cf05ddfaac8d7a2e63a3c97a840d4615d0a0e65ba8bdf6f8576e3be", size = 40853, upload-time = "2025-07-29T07:43:14.888Z" }, + { url = "https://files.pythonhosted.org/packages/ac/1b/96b32058eda1c1dee8264900c37c359a7325c1f11f5ff14fd2be8e24eff9/mmh3-5.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11730eeb16dfcf9674fdea9bb6b8e6dd9b40813b7eb839bc35113649eef38aeb", size = 109694, upload-time = "2025-07-29T07:43:15.816Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/a2ae44cd7dad697b6dea48390cbc977b1e5ca58fda09628cbcb2275af064/mmh3-5.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:932a6eec1d2e2c3c9e630d10f7128d80e70e2d47fe6b8c7ea5e1afbd98733e65", size = 117438, upload-time = "2025-07-29T07:43:16.865Z" }, + { url = "https://files.pythonhosted.org/packages/a0/08/bfb75451c83f05224a28afeaf3950c7b793c0b71440d571f8e819cfb149a/mmh3-5.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca975c51c5028947bbcfc24966517aac06a01d6c921e30f7c5383c195f87991", size = 120409, upload-time = "2025-07-29T07:43:18.207Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ea/8b118b69b2ff8df568f742387d1a159bc654a0f78741b31437dd047ea28e/mmh3-5.2.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b0b58215befe0f0e120b828f7645e97719bbba9f23b69e268ed0ac7adde8645", size = 125909, upload-time = "2025-07-29T07:43:19.39Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/168cc0b6a30650032e351a3b89b8a47382da541993a03af91e1ba2501234/mmh3-5.2.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29c2b9ce61886809d0492a274a5a53047742dea0f703f9c4d5d223c3ea6377d3", size = 135331, upload-time = "2025-07-29T07:43:20.435Z" }, + { url = "https://files.pythonhosted.org/packages/31/05/e3a9849b1c18a7934c64e831492c99e67daebe84a8c2f2c39a7096a830e3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a367d4741ac0103f8198c82f429bccb9359f543ca542b06a51f4f0332e8de279", size = 110085, upload-time = "2025-07-29T07:43:21.92Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d5/a96bcc306e3404601418b2a9a370baec92af84204528ba659fdfe34c242f/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5a5dba98e514fb26241868f6eb90a7f7ca0e039aed779342965ce24ea32ba513", size = 111195, upload-time = "2025-07-29T07:43:23.066Z" }, + { url = "https://files.pythonhosted.org/packages/af/29/0fd49801fec5bff37198684e0849b58e0dab3a2a68382a357cfffb0fafc3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:941603bfd75a46023807511c1ac2f1b0f39cccc393c15039969806063b27e6db", size = 116919, upload-time = "2025-07-29T07:43:24.178Z" }, + { url = "https://files.pythonhosted.org/packages/2d/04/4f3c32b0a2ed762edca45d8b46568fc3668e34f00fb1e0a3b5451ec1281c/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:132dd943451a7c7546978863d2f5a64977928410782e1a87d583cb60eb89e667", size = 123160, upload-time = "2025-07-29T07:43:25.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/76/3d29eaa38821730633d6a240d36fa8ad2807e9dfd432c12e1a472ed211eb/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f698733a8a494466432d611a8f0d1e026f5286dee051beea4b3c3146817e35d5", size = 110206, upload-time = "2025-07-29T07:43:26.699Z" }, + { url = "https://files.pythonhosted.org/packages/44/1c/ccf35892684d3a408202e296e56843743e0b4fb1629e59432ea88cdb3909/mmh3-5.2.0-cp314-cp314t-win32.whl", hash = "sha256:6d541038b3fc360ec538fc116de87462627944765a6750308118f8b509a8eec7", size = 41970, upload-time = "2025-07-29T07:43:27.666Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/b9e4f1e5adb5e21eb104588fcee2cd1eaa8308255173481427d5ecc4284e/mmh3-5.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e912b19cf2378f2967d0c08e86ff4c6c360129887f678e27e4dde970d21b3f4d", size = 43063, upload-time = "2025-07-29T07:43:28.582Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0e61d9a4e29c8679356795a40e48f647b4aad58d71bfc969f0f8f56fb912/mmh3-5.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e7884931fe5e788163e7b3c511614130c2c59feffdc21112290a194487efb2e9", size = 40455, upload-time = "2025-07-29T07:43:29.563Z" }, +] + +[[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 = "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/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 = "mypy" +version = "1.18.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "pathspec" }, + { 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/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 = "networkx" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, +] + +[[package]] +name = "numpy" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/5d/bb7fc075b762c96329147799e1bcc9176ab07ca6375ea976c475482ad5b3/numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf", size = 20957014, upload-time = "2025-09-09T15:56:29.966Z" }, + { url = "https://files.pythonhosted.org/packages/6b/0e/c6211bb92af26517acd52125a237a92afe9c3124c6a68d3b9f81b62a0568/numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25", size = 14185220, upload-time = "2025-09-09T15:56:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/22/f2/07bb754eb2ede9073f4054f7c0286b0d9d2e23982e090a80d478b26d35ca/numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe", size = 5113918, upload-time = "2025-09-09T15:56:34.175Z" }, + { url = "https://files.pythonhosted.org/packages/81/0a/afa51697e9fb74642f231ea36aca80fa17c8fb89f7a82abd5174023c3960/numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b", size = 6647922, upload-time = "2025-09-09T15:56:36.149Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f5/122d9cdb3f51c520d150fef6e87df9279e33d19a9611a87c0d2cf78a89f4/numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8", size = 14281991, upload-time = "2025-09-09T15:56:40.548Z" }, + { url = "https://files.pythonhosted.org/packages/51/64/7de3c91e821a2debf77c92962ea3fe6ac2bc45d0778c1cbe15d4fce2fd94/numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20", size = 16641643, upload-time = "2025-09-09T15:56:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/30/e4/961a5fa681502cd0d68907818b69f67542695b74e3ceaa513918103b7e80/numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea", size = 16056787, upload-time = "2025-09-09T15:56:46.141Z" }, + { url = "https://files.pythonhosted.org/packages/99/26/92c912b966e47fbbdf2ad556cb17e3a3088e2e1292b9833be1dfa5361a1a/numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7", size = 18579598, upload-time = "2025-09-09T15:56:49.844Z" }, + { url = "https://files.pythonhosted.org/packages/17/b6/fc8f82cb3520768718834f310c37d96380d9dc61bfdaf05fe5c0b7653e01/numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf", size = 6320800, upload-time = "2025-09-09T15:56:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/32/ee/de999f2625b80d043d6d2d628c07d0d5555a677a3cf78fdf868d409b8766/numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb", size = 12786615, upload-time = "2025-09-09T15:56:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/49/6e/b479032f8a43559c383acb20816644f5f91c88f633d9271ee84f3b3a996c/numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5", size = 10195936, upload-time = "2025-09-09T15:56:56.541Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b9/984c2b1ee61a8b803bf63582b4ac4242cf76e2dbd663efeafcb620cc0ccb/numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf", size = 20949588, upload-time = "2025-09-09T15:56:59.087Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e4/07970e3bed0b1384d22af1e9912527ecbeb47d3b26e9b6a3bced068b3bea/numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7", size = 14177802, upload-time = "2025-09-09T15:57:01.73Z" }, + { url = "https://files.pythonhosted.org/packages/35/c7/477a83887f9de61f1203bad89cf208b7c19cc9fef0cebef65d5a1a0619f2/numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6", size = 5106537, upload-time = "2025-09-09T15:57:03.765Z" }, + { url = "https://files.pythonhosted.org/packages/52/47/93b953bd5866a6f6986344d045a207d3f1cfbad99db29f534ea9cee5108c/numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7", size = 6640743, upload-time = "2025-09-09T15:57:07.921Z" }, + { url = "https://files.pythonhosted.org/packages/23/83/377f84aaeb800b64c0ef4de58b08769e782edcefa4fea712910b6f0afd3c/numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c", size = 14278881, upload-time = "2025-09-09T15:57:11.349Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a5/bf3db6e66c4b160d6ea10b534c381a1955dfab34cb1017ea93aa33c70ed3/numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93", size = 16636301, upload-time = "2025-09-09T15:57:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/a2/59/1287924242eb4fa3f9b3a2c30400f2e17eb2707020d1c5e3086fe7330717/numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae", size = 16053645, upload-time = "2025-09-09T15:57:16.534Z" }, + { url = "https://files.pythonhosted.org/packages/e6/93/b3d47ed882027c35e94ac2320c37e452a549f582a5e801f2d34b56973c97/numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86", size = 18578179, upload-time = "2025-09-09T15:57:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/487a2bccbf7cc9d4bfc5f0f197761a5ef27ba870f1e3bbb9afc4bbe3fcc2/numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8", size = 6312250, upload-time = "2025-09-09T15:57:21.296Z" }, + { url = "https://files.pythonhosted.org/packages/1b/b5/263ebbbbcede85028f30047eab3d58028d7ebe389d6493fc95ae66c636ab/numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf", size = 12783269, upload-time = "2025-09-09T15:57:23.034Z" }, + { url = "https://files.pythonhosted.org/packages/fa/75/67b8ca554bbeaaeb3fac2e8bce46967a5a06544c9108ec0cf5cece559b6c/numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5", size = 10195314, upload-time = "2025-09-09T15:57:25.045Z" }, + { url = "https://files.pythonhosted.org/packages/11/d0/0d1ddec56b162042ddfafeeb293bac672de9b0cfd688383590090963720a/numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc", size = 21048025, upload-time = "2025-09-09T15:57:27.257Z" }, + { url = "https://files.pythonhosted.org/packages/36/9e/1996ca6b6d00415b6acbdd3c42f7f03ea256e2c3f158f80bd7436a8a19f3/numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc", size = 14301053, upload-time = "2025-09-09T15:57:30.077Z" }, + { url = "https://files.pythonhosted.org/packages/05/24/43da09aa764c68694b76e84b3d3f0c44cb7c18cdc1ba80e48b0ac1d2cd39/numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b", size = 5229444, upload-time = "2025-09-09T15:57:32.733Z" }, + { url = "https://files.pythonhosted.org/packages/bc/14/50ffb0f22f7218ef8af28dd089f79f68289a7a05a208db9a2c5dcbe123c1/numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19", size = 6738039, upload-time = "2025-09-09T15:57:34.328Z" }, + { url = "https://files.pythonhosted.org/packages/55/52/af46ac0795e09657d45a7f4db961917314377edecf66db0e39fa7ab5c3d3/numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30", size = 14352314, upload-time = "2025-09-09T15:57:36.255Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b1/dc226b4c90eb9f07a3fff95c2f0db3268e2e54e5cce97c4ac91518aee71b/numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e", size = 16701722, upload-time = "2025-09-09T15:57:38.622Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9d/9d8d358f2eb5eced14dba99f110d83b5cd9a4460895230f3b396ad19a323/numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3", size = 16132755, upload-time = "2025-09-09T15:57:41.16Z" }, + { url = "https://files.pythonhosted.org/packages/b6/27/b3922660c45513f9377b3fb42240bec63f203c71416093476ec9aa0719dc/numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea", size = 18651560, upload-time = "2025-09-09T15:57:43.459Z" }, + { url = "https://files.pythonhosted.org/packages/5b/8e/3ab61a730bdbbc201bb245a71102aa609f0008b9ed15255500a99cd7f780/numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd", size = 6442776, upload-time = "2025-09-09T15:57:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3a/e22b766b11f6030dc2decdeff5c2fb1610768055603f9f3be88b6d192fb2/numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d", size = 12927281, upload-time = "2025-09-09T15:57:47.492Z" }, + { url = "https://files.pythonhosted.org/packages/7b/42/c2e2bc48c5e9b2a83423f99733950fbefd86f165b468a3d85d52b30bf782/numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1", size = 10265275, upload-time = "2025-09-09T15:57:49.647Z" }, + { url = "https://files.pythonhosted.org/packages/6b/01/342ad585ad82419b99bcf7cebe99e61da6bedb89e213c5fd71acc467faee/numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593", size = 20951527, upload-time = "2025-09-09T15:57:52.006Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d8/204e0d73fc1b7a9ee80ab1fe1983dd33a4d64a4e30a05364b0208e9a241a/numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652", size = 14186159, upload-time = "2025-09-09T15:57:54.407Z" }, + { url = "https://files.pythonhosted.org/packages/22/af/f11c916d08f3a18fb8ba81ab72b5b74a6e42ead4c2846d270eb19845bf74/numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7", size = 5114624, upload-time = "2025-09-09T15:57:56.5Z" }, + { url = "https://files.pythonhosted.org/packages/fb/11/0ed919c8381ac9d2ffacd63fd1f0c34d27e99cab650f0eb6f110e6ae4858/numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a", size = 6642627, upload-time = "2025-09-09T15:57:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/ee/83/deb5f77cb0f7ba6cb52b91ed388b47f8f3c2e9930d4665c600408d9b90b9/numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe", size = 14296926, upload-time = "2025-09-09T15:58:00.035Z" }, + { url = "https://files.pythonhosted.org/packages/77/cc/70e59dcb84f2b005d4f306310ff0a892518cc0c8000a33d0e6faf7ca8d80/numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421", size = 16638958, upload-time = "2025-09-09T15:58:02.738Z" }, + { url = "https://files.pythonhosted.org/packages/b6/5a/b2ab6c18b4257e099587d5b7f903317bd7115333ad8d4ec4874278eafa61/numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021", size = 16071920, upload-time = "2025-09-09T15:58:05.029Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f1/8b3fdc44324a259298520dd82147ff648979bed085feeacc1250ef1656c0/numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf", size = 18577076, upload-time = "2025-09-09T15:58:07.745Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a1/b87a284fb15a42e9274e7fcea0dad259d12ddbf07c1595b26883151ca3b4/numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0", size = 6366952, upload-time = "2025-09-09T15:58:10.096Z" }, + { url = "https://files.pythonhosted.org/packages/70/5f/1816f4d08f3b8f66576d8433a66f8fa35a5acfb3bbd0bf6c31183b003f3d/numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8", size = 12919322, upload-time = "2025-09-09T15:58:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/8c/de/072420342e46a8ea41c324a555fa90fcc11637583fb8df722936aed1736d/numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe", size = 10478630, upload-time = "2025-09-09T15:58:14.64Z" }, + { url = "https://files.pythonhosted.org/packages/d5/df/ee2f1c0a9de7347f14da5dd3cd3c3b034d1b8607ccb6883d7dd5c035d631/numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00", size = 21047987, upload-time = "2025-09-09T15:58:16.889Z" }, + { url = "https://files.pythonhosted.org/packages/d6/92/9453bdc5a4e9e69cf4358463f25e8260e2ffc126d52e10038b9077815989/numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a", size = 14301076, upload-time = "2025-09-09T15:58:20.343Z" }, + { url = "https://files.pythonhosted.org/packages/13/77/1447b9eb500f028bb44253105bd67534af60499588a5149a94f18f2ca917/numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d", size = 5229491, upload-time = "2025-09-09T15:58:22.481Z" }, + { url = "https://files.pythonhosted.org/packages/3d/f9/d72221b6ca205f9736cb4b2ce3b002f6e45cd67cd6a6d1c8af11a2f0b649/numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a", size = 6737913, upload-time = "2025-09-09T15:58:24.569Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5f/d12834711962ad9c46af72f79bb31e73e416ee49d17f4c797f72c96b6ca5/numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54", size = 14352811, upload-time = "2025-09-09T15:58:26.416Z" }, + { url = "https://files.pythonhosted.org/packages/a1/0d/fdbec6629d97fd1bebed56cd742884e4eead593611bbe1abc3eb40d304b2/numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e", size = 16702689, upload-time = "2025-09-09T15:58:28.831Z" }, + { url = "https://files.pythonhosted.org/packages/9b/09/0a35196dc5575adde1eb97ddfbc3e1687a814f905377621d18ca9bc2b7dd/numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097", size = 16133855, upload-time = "2025-09-09T15:58:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ca/c9de3ea397d576f1b6753eaa906d4cdef1bf97589a6d9825a349b4729cc2/numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970", size = 18652520, upload-time = "2025-09-09T15:58:33.762Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c2/e5ed830e08cd0196351db55db82f65bc0ab05da6ef2b72a836dcf1936d2f/numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5", size = 6515371, upload-time = "2025-09-09T15:58:36.04Z" }, + { url = "https://files.pythonhosted.org/packages/47/c7/b0f6b5b67f6788a0725f744496badbb604d226bf233ba716683ebb47b570/numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f", size = 13112576, upload-time = "2025-09-09T15:58:37.927Z" }, + { url = "https://files.pythonhosted.org/packages/06/b9/33bba5ff6fb679aa0b1f8a07e853f002a6b04b9394db3069a1270a7784ca/numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b", size = 10545953, upload-time = "2025-09-09T15:58:40.576Z" }, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cusparse-cu12" }, + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/5b/4e4fff7bad39adf89f735f2bc87248c81db71205b62bcc0d5ca5b606b3c3/nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf27ccf4238253e0b826bce3ff5fa532d65fc42322c8bfdfaf28024c0fbe039", size = 322364134, upload-time = "2025-06-03T21:58:04.013Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, +] + +[[package]] +name = "oauthlib" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, +] + +[[package]] +name = "onnxruntime" +version = "1.23.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/00/3c/4b4f56b5df4596d1d95aafe13cbc987d050a89364ff5b2f90308376901fb/onnxruntime-1.23.1-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:564d6add1688efdb0720cf2158b50314fc35b744ad2623155ee3b805c381d9ce", size = 17194708, upload-time = "2025-10-08T04:25:27.188Z" }, + { url = "https://files.pythonhosted.org/packages/b4/97/05529b97142c1a09bde2caefea4fd29f71329b9275b52bacdbc2c4f9e964/onnxruntime-1.23.1-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:3864c39307714eff1753149215ad86324a9372e3172a0275d5b16ffd296574bf", size = 19152841, upload-time = "2025-10-08T04:24:24.157Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b9/1232fd295fa9c818aa2a7883d87a2f864fb5edee56ec757c6e857fdd1863/onnxruntime-1.23.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e6b6b5ea80a96924f67fe1e5519f6c6f9cd716fdb5a4fd1ecb4f2b0971e8d00", size = 15223749, upload-time = "2025-10-08T04:24:08.088Z" }, + { url = "https://files.pythonhosted.org/packages/c4/b0/4663a333a82c77f159e48fe8639b1f03e4a05036625be9129c20c4d71d12/onnxruntime-1.23.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:576502dad714ffe5f3b4e1918c5b3368766b222063c585e5fd88415c063e4c80", size = 17378483, upload-time = "2025-10-08T04:24:50.712Z" }, + { url = "https://files.pythonhosted.org/packages/7c/60/8100d98690cbf1de03e08d1f3eff33ff00c652806c7130658a48a8f60584/onnxruntime-1.23.1-cp312-cp312-win_amd64.whl", hash = "sha256:1b89b7c4d4c00a67debc2b0a1484d7f51b23fef85fbd80ac83ed2d17b2161bd6", size = 13467773, upload-time = "2025-10-08T04:25:17.097Z" }, + { url = "https://files.pythonhosted.org/packages/99/cc/0316dfd705407a78e4bf096aaa09b2de6b97676e3e028e1183b450c2ebd1/onnxruntime-1.23.1-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:a5402841ff0a400739d2c0423f4f3e3a0ed62673af4323237bb5f5052fccf6cf", size = 17194641, upload-time = "2025-10-08T04:24:16.389Z" }, + { url = "https://files.pythonhosted.org/packages/48/32/7f0a3b21ea9282120fcc274f5227a3390661bdf9019e5ca2da5608f0112d/onnxruntime-1.23.1-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:7059296745fceafcac57badf0386e394185e20c27aa536ec705288c4cde19c8d", size = 19152562, upload-time = "2025-10-08T04:24:26.876Z" }, + { url = "https://files.pythonhosted.org/packages/c4/4a/f9ce32f39fac4465bae693591c6ff9f999635b6ed53171b50b6c4812d613/onnxruntime-1.23.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc8f92157234c3cfba23016576f73deb99aba165a6fc1f2fe4a37d0c524ad3ad", size = 15221548, upload-time = "2025-10-08T04:24:10.878Z" }, + { url = "https://files.pythonhosted.org/packages/e4/30/8a85c09c42a99d97e9445441a4607eacc9db9d40cf9484de6818cab8d154/onnxruntime-1.23.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce3ea70499aabc7c8b9407b3680b12473dba9322e3dfde0fe11ff8061c44a226", size = 17378269, upload-time = "2025-10-08T04:24:53.098Z" }, + { url = "https://files.pythonhosted.org/packages/af/2e/1b95ca7b33f0c345fb454f3187a301791e2a2aa2455ef0cf9e7cb0ab6036/onnxruntime-1.23.1-cp313-cp313-win_amd64.whl", hash = "sha256:371202e1468d5159e78518236cb22f7bbd170e29b31ee77722070a20f8a733ce", size = 13468418, upload-time = "2025-10-08T04:25:19.724Z" }, + { url = "https://files.pythonhosted.org/packages/60/1f/439d9ed8527734a60bf4efba05fbb228dfd9eba7a9ff6c39a29ad92a914d/onnxruntime-1.23.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16217416cb88aadcd6a86f8e7c6c22ff951b65f9f695faef9c1ff94052ba1c36", size = 15225857, upload-time = "2025-10-08T04:24:13.676Z" }, + { url = "https://files.pythonhosted.org/packages/42/03/127876e85542a1ce27cc2d50206d5aba0ccb034b00ab28407839aee272c8/onnxruntime-1.23.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:38eae2d803de3c08265a5b38211bcec315b19a7ca5867468029cca06fd217a6b", size = 17389605, upload-time = "2025-10-08T04:24:55.865Z" }, +] + +[[package]] +name = "openai" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/90/8f26554d24d63ed4f94d33c24271559863223a67e624f4d2e65ba8e48dca/openai-2.3.0.tar.gz", hash = "sha256:8d213ee5aaf91737faea2d7fc1cd608657a5367a18966372a3756ceaabfbd812", size = 589616, upload-time = "2025-10-10T01:12:50.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/5b/4be258ff072ed8ee15f6bfd8d5a1a4618aa4704b127c0c5959212ad177d6/openai-2.3.0-py3-none-any.whl", hash = "sha256:a7aa83be6f7b0ab2e4d4d7bcaf36e3d790874c0167380c5d0afd0ed99a86bd7b", size = 999768, upload-time = "2025-10-10T01:12:48.647Z" }, +] + +[[package]] +name = "opentelemetry-api" +version = "1.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/04/05040d7ce33a907a2a02257e601992f0cdf11c73b33f13c4492bf6c3d6d5/opentelemetry_api-1.37.0.tar.gz", hash = "sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7", size = 64923, upload-time = "2025-09-11T10:29:01.662Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/48/28ed9e55dcf2f453128df738210a980e09f4e468a456fa3c763dbc8be70a/opentelemetry_api-1.37.0-py3-none-any.whl", hash = "sha256:accf2024d3e89faec14302213bc39550ec0f4095d1cf5ca688e1bfb1c8612f47", size = 65732, upload-time = "2025-09-11T10:28:41.826Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-common" +version = "1.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-proto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/6c/10018cbcc1e6fff23aac67d7fd977c3d692dbe5f9ef9bb4db5c1268726cc/opentelemetry_exporter_otlp_proto_common-1.37.0.tar.gz", hash = "sha256:c87a1bdd9f41fdc408d9cc9367bb53f8d2602829659f2b90be9f9d79d0bfe62c", size = 20430, upload-time = "2025-09-11T10:29:03.605Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/13/b4ef09837409a777f3c0af2a5b4ba9b7af34872bc43609dda0c209e4060d/opentelemetry_exporter_otlp_proto_common-1.37.0-py3-none-any.whl", hash = "sha256:53038428449c559b0c564b8d718df3314da387109c4d36bd1b94c9a641b0292e", size = 18359, upload-time = "2025-09-11T10:28:44.939Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-grpc" +version = "1.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "grpcio" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/11/4ad0979d0bb13ae5a845214e97c8d42da43980034c30d6f72d8e0ebe580e/opentelemetry_exporter_otlp_proto_grpc-1.37.0.tar.gz", hash = "sha256:f55bcb9fc848ce05ad3dd954058bc7b126624d22c4d9e958da24d8537763bec5", size = 24465, upload-time = "2025-09-11T10:29:04.172Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/17/46630b74751031a658706bef23ac99cdc2953cd3b2d28ec90590a0766b3e/opentelemetry_exporter_otlp_proto_grpc-1.37.0-py3-none-any.whl", hash = "sha256:aee5104835bf7993b7ddaaf380b6467472abaedb1f1dbfcc54a52a7d781a3890", size = 19305, upload-time = "2025-09-11T10:28:45.776Z" }, +] + +[[package]] +name = "opentelemetry-proto" +version = "1.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/ea/a75f36b463a36f3c5a10c0b5292c58b31dbdde74f6f905d3d0ab2313987b/opentelemetry_proto-1.37.0.tar.gz", hash = "sha256:30f5c494faf66f77faeaefa35ed4443c5edb3b0aa46dad073ed7210e1a789538", size = 46151, upload-time = "2025-09-11T10:29:11.04Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/25/f89ea66c59bd7687e218361826c969443c4fa15dfe89733f3bf1e2a9e971/opentelemetry_proto-1.37.0-py3-none-any.whl", hash = "sha256:8ed8c066ae8828bbf0c39229979bdf583a126981142378a9cbe9d6fd5701c6e2", size = 72534, upload-time = "2025-09-11T10:28:56.831Z" }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/62/2e0ca80d7fe94f0b193135375da92c640d15fe81f636658d2acf373086bc/opentelemetry_sdk-1.37.0.tar.gz", hash = "sha256:cc8e089c10953ded765b5ab5669b198bbe0af1b3f89f1007d19acd32dc46dda5", size = 170404, upload-time = "2025-09-11T10:29:11.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/62/9f4ad6a54126fb00f7ed4bb5034964c6e4f00fcd5a905e115bd22707e20d/opentelemetry_sdk-1.37.0-py3-none-any.whl", hash = "sha256:8f3c3c22063e52475c5dbced7209495c2c16723d016d39287dfc215d1771257c", size = 131941, upload-time = "2025-09-11T10:28:57.83Z" }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.58b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/1b/90701d91e6300d9f2fb352153fb1721ed99ed1f6ea14fa992c756016e63a/opentelemetry_semantic_conventions-0.58b0.tar.gz", hash = "sha256:6bd46f51264279c433755767bb44ad00f1c9e2367e1b42af563372c5a6fa0c25", size = 129867, upload-time = "2025-09-11T10:29:12.597Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/90/68152b7465f50285d3ce2481b3aec2f82822e3f52e5152eeeaf516bab841/opentelemetry_semantic_conventions-0.58b0-py3-none-any.whl", hash = "sha256:5564905ab1458b96684db1340232729fce3b5375a06e140e8904c78e4f815b28", size = 207954, upload-time = "2025-09-11T10:28:59.218Z" }, +] + +[[package]] +name = "orjson" +version = "3.11.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/4d/8df5f83256a809c22c4d6792ce8d43bb503be0fb7a8e4da9025754b09658/orjson-3.11.3.tar.gz", hash = "sha256:1c0603b1d2ffcd43a411d64797a19556ef76958aef1c182f22dc30860152a98a", size = 5482394, upload-time = "2025-08-26T17:46:43.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/b0/a7edab2a00cdcb2688e1c943401cb3236323e7bfd2839815c6131a3742f4/orjson-3.11.3-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8c752089db84333e36d754c4baf19c0e1437012242048439c7e80eb0e6426e3b", size = 238259, upload-time = "2025-08-26T17:45:15.093Z" }, + { url = "https://files.pythonhosted.org/packages/e1/c6/ff4865a9cc398a07a83342713b5932e4dc3cb4bf4bc04e8f83dedfc0d736/orjson-3.11.3-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:9b8761b6cf04a856eb544acdd82fc594b978f12ac3602d6374a7edb9d86fd2c2", size = 127633, upload-time = "2025-08-26T17:45:16.417Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e6/e00bea2d9472f44fe8794f523e548ce0ad51eb9693cf538a753a27b8bda4/orjson-3.11.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b13974dc8ac6ba22feaa867fc19135a3e01a134b4f7c9c28162fed4d615008a", size = 123061, upload-time = "2025-08-26T17:45:17.673Z" }, + { url = "https://files.pythonhosted.org/packages/54/31/9fbb78b8e1eb3ac605467cb846e1c08d0588506028b37f4ee21f978a51d4/orjson-3.11.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f83abab5bacb76d9c821fd5c07728ff224ed0e52d7a71b7b3de822f3df04e15c", size = 127956, upload-time = "2025-08-26T17:45:19.172Z" }, + { url = "https://files.pythonhosted.org/packages/36/88/b0604c22af1eed9f98d709a96302006915cfd724a7ebd27d6dd11c22d80b/orjson-3.11.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6fbaf48a744b94091a56c62897b27c31ee2da93d826aa5b207131a1e13d4064", size = 130790, upload-time = "2025-08-26T17:45:20.586Z" }, + { url = "https://files.pythonhosted.org/packages/0e/9d/1c1238ae9fffbfed51ba1e507731b3faaf6b846126a47e9649222b0fd06f/orjson-3.11.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc779b4f4bba2847d0d2940081a7b6f7b5877e05408ffbb74fa1faf4a136c424", size = 132385, upload-time = "2025-08-26T17:45:22.036Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b5/c06f1b090a1c875f337e21dd71943bc9d84087f7cdf8c6e9086902c34e42/orjson-3.11.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd4b909ce4c50faa2192da6bb684d9848d4510b736b0611b6ab4020ea6fd2d23", size = 135305, upload-time = "2025-08-26T17:45:23.4Z" }, + { url = "https://files.pythonhosted.org/packages/a0/26/5f028c7d81ad2ebbf84414ba6d6c9cac03f22f5cd0d01eb40fb2d6a06b07/orjson-3.11.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:524b765ad888dc5518bbce12c77c2e83dee1ed6b0992c1790cc5fb49bb4b6667", size = 132875, upload-time = "2025-08-26T17:45:25.182Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d4/b8df70d9cfb56e385bf39b4e915298f9ae6c61454c8154a0f5fd7efcd42e/orjson-3.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:84fd82870b97ae3cdcea9d8746e592b6d40e1e4d4527835fc520c588d2ded04f", size = 130940, upload-time = "2025-08-26T17:45:27.209Z" }, + { url = "https://files.pythonhosted.org/packages/da/5e/afe6a052ebc1a4741c792dd96e9f65bf3939d2094e8b356503b68d48f9f5/orjson-3.11.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbecb9709111be913ae6879b07bafd4b0785b44c1eb5cac8ac76da048b3885a1", size = 403852, upload-time = "2025-08-26T17:45:28.478Z" }, + { url = "https://files.pythonhosted.org/packages/f8/90/7bbabafeb2ce65915e9247f14a56b29c9334003536009ef5b122783fe67e/orjson-3.11.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9dba358d55aee552bd868de348f4736ca5a4086d9a62e2bfbbeeb5629fe8b0cc", size = 146293, upload-time = "2025-08-26T17:45:29.86Z" }, + { url = "https://files.pythonhosted.org/packages/27/b3/2d703946447da8b093350570644a663df69448c9d9330e5f1d9cce997f20/orjson-3.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eabcf2e84f1d7105f84580e03012270c7e97ecb1fb1618bda395061b2a84a049", size = 135470, upload-time = "2025-08-26T17:45:31.243Z" }, + { url = "https://files.pythonhosted.org/packages/38/70/b14dcfae7aff0e379b0119c8a812f8396678919c431efccc8e8a0263e4d9/orjson-3.11.3-cp312-cp312-win32.whl", hash = "sha256:3782d2c60b8116772aea8d9b7905221437fdf53e7277282e8d8b07c220f96cca", size = 136248, upload-time = "2025-08-26T17:45:32.567Z" }, + { url = "https://files.pythonhosted.org/packages/35/b8/9e3127d65de7fff243f7f3e53f59a531bf6bb295ebe5db024c2503cc0726/orjson-3.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:79b44319268af2eaa3e315b92298de9a0067ade6e6003ddaef72f8e0bedb94f1", size = 131437, upload-time = "2025-08-26T17:45:34.949Z" }, + { url = "https://files.pythonhosted.org/packages/51/92/a946e737d4d8a7fd84a606aba96220043dcc7d6988b9e7551f7f6d5ba5ad/orjson-3.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:0e92a4e83341ef79d835ca21b8bd13e27c859e4e9e4d7b63defc6e58462a3710", size = 125978, upload-time = "2025-08-26T17:45:36.422Z" }, + { url = "https://files.pythonhosted.org/packages/fc/79/8932b27293ad35919571f77cb3693b5906cf14f206ef17546052a241fdf6/orjson-3.11.3-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:af40c6612fd2a4b00de648aa26d18186cd1322330bd3a3cc52f87c699e995810", size = 238127, upload-time = "2025-08-26T17:45:38.146Z" }, + { url = "https://files.pythonhosted.org/packages/1c/82/cb93cd8cf132cd7643b30b6c5a56a26c4e780c7a145db6f83de977b540ce/orjson-3.11.3-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:9f1587f26c235894c09e8b5b7636a38091a9e6e7fe4531937534749c04face43", size = 127494, upload-time = "2025-08-26T17:45:39.57Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/2d9eb181a9b6bb71463a78882bcac1027fd29cf62c38a40cc02fc11d3495/orjson-3.11.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61dcdad16da5bb486d7227a37a2e789c429397793a6955227cedbd7252eb5a27", size = 123017, upload-time = "2025-08-26T17:45:40.876Z" }, + { url = "https://files.pythonhosted.org/packages/b4/14/a0e971e72d03b509190232356d54c0f34507a05050bd026b8db2bf2c192c/orjson-3.11.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11c6d71478e2cbea0a709e8a06365fa63da81da6498a53e4c4f065881d21ae8f", size = 127898, upload-time = "2025-08-26T17:45:42.188Z" }, + { url = "https://files.pythonhosted.org/packages/8e/af/dc74536722b03d65e17042cc30ae586161093e5b1f29bccda24765a6ae47/orjson-3.11.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff94112e0098470b665cb0ed06efb187154b63649403b8d5e9aedeb482b4548c", size = 130742, upload-time = "2025-08-26T17:45:43.511Z" }, + { url = "https://files.pythonhosted.org/packages/62/e6/7a3b63b6677bce089fe939353cda24a7679825c43a24e49f757805fc0d8a/orjson-3.11.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b756575aaa2a855a75192f356bbda11a89169830e1439cfb1a3e1a6dde7be", size = 132377, upload-time = "2025-08-26T17:45:45.525Z" }, + { url = "https://files.pythonhosted.org/packages/fc/cd/ce2ab93e2e7eaf518f0fd15e3068b8c43216c8a44ed82ac2b79ce5cef72d/orjson-3.11.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9416cc19a349c167ef76135b2fe40d03cea93680428efee8771f3e9fb66079d", size = 135313, upload-time = "2025-08-26T17:45:46.821Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/f98355eff0bd1a38454209bbc73372ce351ba29933cb3e2eba16c04b9448/orjson-3.11.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b822caf5b9752bc6f246eb08124c3d12bf2175b66ab74bac2ef3bbf9221ce1b2", size = 132908, upload-time = "2025-08-26T17:45:48.126Z" }, + { url = "https://files.pythonhosted.org/packages/eb/92/8f5182d7bc2a1bed46ed960b61a39af8389f0ad476120cd99e67182bfb6d/orjson-3.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:414f71e3bdd5573893bf5ecdf35c32b213ed20aa15536fe2f588f946c318824f", size = 130905, upload-time = "2025-08-26T17:45:49.414Z" }, + { url = "https://files.pythonhosted.org/packages/1a/60/c41ca753ce9ffe3d0f67b9b4c093bdd6e5fdb1bc53064f992f66bb99954d/orjson-3.11.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:828e3149ad8815dc14468f36ab2a4b819237c155ee1370341b91ea4c8672d2ee", size = 403812, upload-time = "2025-08-26T17:45:51.085Z" }, + { url = "https://files.pythonhosted.org/packages/dd/13/e4a4f16d71ce1868860db59092e78782c67082a8f1dc06a3788aef2b41bc/orjson-3.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac9e05f25627ffc714c21f8dfe3a579445a5c392a9c8ae7ba1d0e9fb5333f56e", size = 146277, upload-time = "2025-08-26T17:45:52.851Z" }, + { url = "https://files.pythonhosted.org/packages/8d/8b/bafb7f0afef9344754a3a0597a12442f1b85a048b82108ef2c956f53babd/orjson-3.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e44fbe4000bd321d9f3b648ae46e0196d21577cf66ae684a96ff90b1f7c93633", size = 135418, upload-time = "2025-08-26T17:45:54.806Z" }, + { url = "https://files.pythonhosted.org/packages/60/d4/bae8e4f26afb2c23bea69d2f6d566132584d1c3a5fe89ee8c17b718cab67/orjson-3.11.3-cp313-cp313-win32.whl", hash = "sha256:2039b7847ba3eec1f5886e75e6763a16e18c68a63efc4b029ddf994821e2e66b", size = 136216, upload-time = "2025-08-26T17:45:57.182Z" }, + { url = "https://files.pythonhosted.org/packages/88/76/224985d9f127e121c8cad882cea55f0ebe39f97925de040b75ccd4b33999/orjson-3.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:29be5ac4164aa8bdcba5fa0700a3c9c316b411d8ed9d39ef8a882541bd452fae", size = 131362, upload-time = "2025-08-26T17:45:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cf/0dce7a0be94bd36d1346be5067ed65ded6adb795fdbe3abd234c8d576d01/orjson-3.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:18bd1435cb1f2857ceb59cfb7de6f92593ef7b831ccd1b9bfb28ca530e539dce", size = 125989, upload-time = "2025-08-26T17:45:59.95Z" }, + { url = "https://files.pythonhosted.org/packages/ef/77/d3b1fef1fc6aaeed4cbf3be2b480114035f4df8fa1a99d2dac1d40d6e924/orjson-3.11.3-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cf4b81227ec86935568c7edd78352a92e97af8da7bd70bdfdaa0d2e0011a1ab4", size = 238115, upload-time = "2025-08-26T17:46:01.669Z" }, + { url = "https://files.pythonhosted.org/packages/e4/6d/468d21d49bb12f900052edcfbf52c292022d0a323d7828dc6376e6319703/orjson-3.11.3-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:bc8bc85b81b6ac9fc4dae393a8c159b817f4c2c9dee5d12b773bddb3b95fc07e", size = 127493, upload-time = "2025-08-26T17:46:03.466Z" }, + { url = "https://files.pythonhosted.org/packages/67/46/1e2588700d354aacdf9e12cc2d98131fb8ac6f31ca65997bef3863edb8ff/orjson-3.11.3-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:88dcfc514cfd1b0de038443c7b3e6a9797ffb1b3674ef1fd14f701a13397f82d", size = 122998, upload-time = "2025-08-26T17:46:04.803Z" }, + { url = "https://files.pythonhosted.org/packages/3b/94/11137c9b6adb3779f1b34fd98be51608a14b430dbc02c6d41134fbba484c/orjson-3.11.3-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d61cd543d69715d5fc0a690c7c6f8dcc307bc23abef9738957981885f5f38229", size = 132915, upload-time = "2025-08-26T17:46:06.237Z" }, + { url = "https://files.pythonhosted.org/packages/10/61/dccedcf9e9bcaac09fdabe9eaee0311ca92115699500efbd31950d878833/orjson-3.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2b7b153ed90ababadbef5c3eb39549f9476890d339cf47af563aea7e07db2451", size = 130907, upload-time = "2025-08-26T17:46:07.581Z" }, + { url = "https://files.pythonhosted.org/packages/0e/fd/0e935539aa7b08b3ca0f817d73034f7eb506792aae5ecc3b7c6e679cdf5f/orjson-3.11.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:7909ae2460f5f494fecbcd10613beafe40381fd0316e35d6acb5f3a05bfda167", size = 403852, upload-time = "2025-08-26T17:46:08.982Z" }, + { url = "https://files.pythonhosted.org/packages/4a/2b/50ae1a5505cd1043379132fdb2adb8a05f37b3e1ebffe94a5073321966fd/orjson-3.11.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2030c01cbf77bc67bee7eef1e7e31ecf28649353987775e3583062c752da0077", size = 146309, upload-time = "2025-08-26T17:46:10.576Z" }, + { url = "https://files.pythonhosted.org/packages/cd/1d/a473c158e380ef6f32753b5f39a69028b25ec5be331c2049a2201bde2e19/orjson-3.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0169ebd1cbd94b26c7a7ad282cf5c2744fce054133f959e02eb5265deae1872", size = 135424, upload-time = "2025-08-26T17:46:12.386Z" }, + { url = "https://files.pythonhosted.org/packages/da/09/17d9d2b60592890ff7382e591aa1d9afb202a266b180c3d4049b1ec70e4a/orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d", size = 136266, upload-time = "2025-08-26T17:46:13.853Z" }, + { url = "https://files.pythonhosted.org/packages/15/58/358f6846410a6b4958b74734727e582ed971e13d335d6c7ce3e47730493e/orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804", size = 131351, upload-time = "2025-08-26T17:46:15.27Z" }, + { url = "https://files.pythonhosted.org/packages/28/01/d6b274a0635be0468d4dbd9cafe80c47105937a0d42434e805e67cd2ed8b/orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc", size = 125985, upload-time = "2025-08-26T17:46:16.67Z" }, +] + +[[package]] +name = "ormsgpack" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/f8/224c342c0e03e131aaa1a1f19aa2244e167001783a433f4eed10eedd834b/ormsgpack-1.11.0.tar.gz", hash = "sha256:7c9988e78fedba3292541eb3bb274fa63044ef4da2ddb47259ea70c05dee4206", size = 49357, upload-time = "2025-10-08T17:29:15.621Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/16/2805ebfb3d2cbb6c661b5fae053960fc90a2611d0d93e2207e753e836117/ormsgpack-1.11.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:3434d0c8d67de27d9010222de07fb6810fb9af3bb7372354ffa19257ac0eb83b", size = 368474, upload-time = "2025-10-08T17:28:27.532Z" }, + { url = "https://files.pythonhosted.org/packages/6f/39/6afae47822dca0ce4465d894c0bbb860a850ce29c157882dbdf77a5dd26e/ormsgpack-1.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2da5bd097e8dbfa4eb0d4ccfe79acd6f538dee4493579e2debfe4fc8f4ca89b", size = 195321, upload-time = "2025-10-08T17:28:28.573Z" }, + { url = "https://files.pythonhosted.org/packages/f6/54/11eda6b59f696d2f16de469bfbe539c9f469c4b9eef5a513996b5879c6e9/ormsgpack-1.11.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fdbaa0a5a8606a486960b60c24f2d5235d30ac7a8b98eeaea9854bffef14dc3d", size = 206036, upload-time = "2025-10-08T17:28:29.785Z" }, + { url = "https://files.pythonhosted.org/packages/1e/86/890430f704f84c4699ddad61c595d171ea2fd77a51fbc106f83981e83939/ormsgpack-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3682f24f800c1837017ee90ce321086b2cbaef88db7d4cdbbda1582aa6508159", size = 207615, upload-time = "2025-10-08T17:28:31.076Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b9/77383e16c991c0ecb772205b966fc68d9c519e0b5f9c3913283cbed30ffe/ormsgpack-1.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fcca21202bb05ccbf3e0e92f560ee59b9331182e4c09c965a28155efbb134993", size = 377195, upload-time = "2025-10-08T17:28:32.436Z" }, + { url = "https://files.pythonhosted.org/packages/20/e2/15f9f045d4947f3c8a5e0535259fddf027b17b1215367488b3565c573b9d/ormsgpack-1.11.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c30e5c4655ba46152d722ec7468e8302195e6db362ec1ae2c206bc64f6030e43", size = 470960, upload-time = "2025-10-08T17:28:33.556Z" }, + { url = "https://files.pythonhosted.org/packages/b8/61/403ce188c4c495bc99dff921a0ad3d9d352dd6d3c4b629f3638b7f0cf79b/ormsgpack-1.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7138a341f9e2c08c59368f03d3be25e8b87b3baaf10d30fb1f6f6b52f3d47944", size = 381174, upload-time = "2025-10-08T17:28:34.781Z" }, + { url = "https://files.pythonhosted.org/packages/14/a8/94c94bc48c68da4374870a851eea03fc5a45eb041182ad4c5ed9acfc05a4/ormsgpack-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:d4bd8589b78a11026d47f4edf13c1ceab9088bb12451f34396afe6497db28a27", size = 112314, upload-time = "2025-10-08T17:28:36.259Z" }, + { url = "https://files.pythonhosted.org/packages/19/d0/aa4cf04f04e4cc180ce7a8d8ddb5a7f3af883329cbc59645d94d3ba157a5/ormsgpack-1.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:e5e746a1223e70f111d4001dab9585ac8639eee8979ca0c8db37f646bf2961da", size = 106072, upload-time = "2025-10-08T17:28:37.518Z" }, + { url = "https://files.pythonhosted.org/packages/8b/35/e34722edb701d053cf2240f55974f17b7dbfd11fdef72bd2f1835bcebf26/ormsgpack-1.11.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e7b36ab7b45cb95217ae1f05f1318b14a3e5ef73cb00804c0f06233f81a14e8", size = 368502, upload-time = "2025-10-08T17:28:38.547Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6a/c2fc369a79d6aba2aa28c8763856c95337ac7fcc0b2742185cd19397212a/ormsgpack-1.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43402d67e03a9a35cc147c8c03f0c377cad016624479e1ee5b879b8425551484", size = 195344, upload-time = "2025-10-08T17:28:39.554Z" }, + { url = "https://files.pythonhosted.org/packages/8b/6a/0f8e24b7489885534c1a93bdba7c7c434b9b8638713a68098867db9f254c/ormsgpack-1.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:64fd992f932764d6306b70ddc755c1bc3405c4c6a69f77a36acf7af1c8f5ada4", size = 206045, upload-time = "2025-10-08T17:28:40.561Z" }, + { url = "https://files.pythonhosted.org/packages/99/71/8b460ba264f3c6f82ef5b1920335720094e2bd943057964ce5287d6df83a/ormsgpack-1.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0362fb7fe4a29c046c8ea799303079a09372653a1ce5a5a588f3bbb8088368d0", size = 207641, upload-time = "2025-10-08T17:28:41.736Z" }, + { url = "https://files.pythonhosted.org/packages/50/cf/f369446abaf65972424ed2651f2df2b7b5c3b735c93fc7fa6cfb81e34419/ormsgpack-1.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:de2f7a65a9d178ed57be49eba3d0fc9b833c32beaa19dbd4ba56014d3c20b152", size = 377211, upload-time = "2025-10-08T17:28:43.12Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3f/948bb0047ce0f37c2efc3b9bb2bcfdccc61c63e0b9ce8088d4903ba39dcf/ormsgpack-1.11.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f38cfae95461466055af966fc922d06db4e1654966385cda2828653096db34da", size = 470973, upload-time = "2025-10-08T17:28:44.465Z" }, + { url = "https://files.pythonhosted.org/packages/31/a4/92a8114d1d017c14aaa403445060f345df9130ca532d538094f38e535988/ormsgpack-1.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c88396189d238f183cea7831b07a305ab5c90d6d29b53288ae11200bd956357b", size = 381161, upload-time = "2025-10-08T17:28:46.063Z" }, + { url = "https://files.pythonhosted.org/packages/d0/64/5b76447da654798bfcfdfd64ea29447ff2b7f33fe19d0e911a83ad5107fc/ormsgpack-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:5403d1a945dd7c81044cebeca3f00a28a0f4248b33242a5d2d82111628043725", size = 112321, upload-time = "2025-10-08T17:28:47.393Z" }, + { url = "https://files.pythonhosted.org/packages/46/5e/89900d06db9ab81e7ec1fd56a07c62dfbdcda398c435718f4252e1dc52a0/ormsgpack-1.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:c57357b8d43b49722b876edf317bdad9e6d52071b523fdd7394c30cd1c67d5a0", size = 106084, upload-time = "2025-10-08T17:28:48.305Z" }, + { url = "https://files.pythonhosted.org/packages/4c/0b/c659e8657085c8c13f6a0224789f422620cef506e26573b5434defe68483/ormsgpack-1.11.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d390907d90fd0c908211592c485054d7a80990697ef4dff4e436ac18e1aab98a", size = 368497, upload-time = "2025-10-08T17:28:49.297Z" }, + { url = "https://files.pythonhosted.org/packages/1b/0e/451e5848c7ed56bd287e8a2b5cb5926e54466f60936e05aec6cb299f9143/ormsgpack-1.11.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6153c2e92e789509098e04c9aa116b16673bd88ec78fbe0031deeb34ab642d10", size = 195385, upload-time = "2025-10-08T17:28:50.314Z" }, + { url = "https://files.pythonhosted.org/packages/4c/28/90f78cbbe494959f2439c2ec571f08cd3464c05a6a380b0d621c622122a9/ormsgpack-1.11.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2b2c2a065a94d742212b2018e1fecd8f8d72f3c50b53a97d1f407418093446d", size = 206114, upload-time = "2025-10-08T17:28:51.336Z" }, + { url = "https://files.pythonhosted.org/packages/fb/db/34163f4c0923bea32dafe42cd878dcc66795a3e85669bc4b01c1e2b92a7b/ormsgpack-1.11.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:110e65b5340f3d7ef8b0009deae3c6b169437e6b43ad5a57fd1748085d29d2ac", size = 207679, upload-time = "2025-10-08T17:28:53.627Z" }, + { url = "https://files.pythonhosted.org/packages/b6/14/04ee741249b16f380a9b4a0cc19d4134d0b7c74bab27a2117da09e525eb9/ormsgpack-1.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c27e186fca96ab34662723e65b420919910acbbc50fc8e1a44e08f26268cb0e0", size = 377237, upload-time = "2025-10-08T17:28:56.12Z" }, + { url = "https://files.pythonhosted.org/packages/89/ff/53e588a6aaa833237471caec679582c2950f0e7e1a8ba28c1511b465c1f4/ormsgpack-1.11.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d56b1f877c13d499052d37a3db2378a97d5e1588d264f5040b3412aee23d742c", size = 471021, upload-time = "2025-10-08T17:28:57.299Z" }, + { url = "https://files.pythonhosted.org/packages/a6/f9/f20a6d9ef2be04da3aad05e8f5699957e9a30c6d5c043a10a296afa7e890/ormsgpack-1.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c88e28cd567c0a3269f624b4ade28142d5e502c8e826115093c572007af5be0a", size = 381205, upload-time = "2025-10-08T17:28:58.872Z" }, + { url = "https://files.pythonhosted.org/packages/f8/64/96c07d084b479ac8b7821a77ffc8d3f29d8b5c95ebfdf8db1c03dff02762/ormsgpack-1.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:8811160573dc0a65f62f7e0792c4ca6b7108dfa50771edb93f9b84e2d45a08ae", size = 112374, upload-time = "2025-10-08T17:29:00Z" }, + { url = "https://files.pythonhosted.org/packages/88/a5/5dcc18b818d50213a3cadfe336bb6163a102677d9ce87f3d2f1a1bee0f8c/ormsgpack-1.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:23e30a8d3c17484cf74e75e6134322255bd08bc2b5b295cc9c442f4bae5f3c2d", size = 106056, upload-time = "2025-10-08T17:29:01.29Z" }, + { url = "https://files.pythonhosted.org/packages/19/2b/776d1b411d2be50f77a6e6e94a25825cca55dcacfe7415fd691a144db71b/ormsgpack-1.11.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2905816502adfaf8386a01dd85f936cd378d243f4f5ee2ff46f67f6298dc90d5", size = 368661, upload-time = "2025-10-08T17:29:02.382Z" }, + { url = "https://files.pythonhosted.org/packages/a9/0c/81a19e6115b15764db3d241788f9fac093122878aaabf872cc545b0c4650/ormsgpack-1.11.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c04402fb9a0a9b9f18fbafd6d5f8398ee99b3ec619fb63952d3a954bc9d47daa", size = 195539, upload-time = "2025-10-08T17:29:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/97/86/e5b50247a61caec5718122feb2719ea9d451d30ac0516c288c1dbc6408e8/ormsgpack-1.11.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a025ec07ac52056ecfd9e57b5cbc6fff163f62cb9805012b56cda599157f8ef2", size = 207718, upload-time = "2025-10-08T17:29:04.545Z" }, +] + +[[package]] +name = "overrides" +version = "7.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pandas" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, + { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, + { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, + { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" }, + { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" }, + { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" }, + { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" }, + { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" }, + { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" }, + { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" }, + { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" }, + { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" }, + { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" }, + { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" }, + { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, + { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, + { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, + { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, + { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, + { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, + { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, + { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, + { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, + { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, + { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, + { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, + { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, + { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, +] + +[[package]] +name = "passlib" +version = "1.7.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/06/9da9ee59a67fae7761aab3ccc84fa4f3f33f125b370f1ccdb915bf967c11/passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04", size = 689844, upload-time = "2020-10-08T19:00:52.121Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1", size = 525554, upload-time = "2020-10-08T19:00:49.856Z" }, +] + +[package.optional-dependencies] +bcrypt = [ + { name = "bcrypt" }, +] + +[[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 = "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/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" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, +] + +[[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 = "posthog" +version = "5.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "backoff" }, + { name = "distro" }, + { name = "python-dateutil" }, + { name = "requests" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/20/60ae67bb9d82f00427946218d49e2e7e80fb41c15dc5019482289ec9ce8d/posthog-5.4.0.tar.gz", hash = "sha256:701669261b8d07cdde0276e5bc096b87f9e200e3b9589c5ebff14df658c5893c", size = 88076, upload-time = "2025-06-20T23:19:23.485Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/98/e480cab9a08d1c09b1c59a93dade92c1bb7544826684ff2acbfd10fcfbd4/posthog-5.4.0-py3-none-any.whl", hash = "sha256:284dfa302f64353484420b52d4ad81ff5c2c2d1d607c4e2db602ac72761831bd", size = 105364, upload-time = "2025-06-20T23:19:22.001Z" }, +] + +[[package]] +name = "primp" +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/0b/a87556189da4de1fc6360ca1aa05e8335509633f836cdd06dd17f0743300/primp-0.15.0.tar.gz", hash = "sha256:1af8ea4b15f57571ff7fc5e282a82c5eb69bc695e19b8ddeeda324397965b30a", size = 113022, upload-time = "2025-04-17T11:41:05.315Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/5a/146ac964b99ea7657ad67eb66f770be6577dfe9200cb28f9a95baffd6c3f/primp-0.15.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1b281f4ca41a0c6612d4c6e68b96e28acfe786d226a427cd944baa8d7acd644f", size = 3178914, upload-time = "2025-04-17T11:40:59.558Z" }, + { url = "https://files.pythonhosted.org/packages/bc/8a/cc2321e32db3ce64d6e32950d5bcbea01861db97bfb20b5394affc45b387/primp-0.15.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:489cbab55cd793ceb8f90bb7423c6ea64ebb53208ffcf7a044138e3c66d77299", size = 2955079, upload-time = "2025-04-17T11:40:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/c3/7b/cbd5d999a07ff2a21465975d4eb477ae6f69765e8fe8c9087dab250180d8/primp-0.15.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b45c23f94016215f62d2334552224236217aaeb716871ce0e4dcfa08eb161", size = 3281018, upload-time = "2025-04-17T11:40:55.308Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6e/a6221c612e61303aec2bcac3f0a02e8b67aee8c0db7bdc174aeb8010f975/primp-0.15.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e985a9cba2e3f96a323722e5440aa9eccaac3178e74b884778e926b5249df080", size = 3255229, upload-time = "2025-04-17T11:40:47.811Z" }, + { url = "https://files.pythonhosted.org/packages/3b/54/bfeef5aca613dc660a69d0760a26c6b8747d8fdb5a7f20cb2cee53c9862f/primp-0.15.0-cp38-abi3-manylinux_2_34_armv7l.whl", hash = "sha256:6b84a6ffa083e34668ff0037221d399c24d939b5629cd38223af860de9e17a83", size = 3014522, upload-time = "2025-04-17T11:40:50.191Z" }, + { url = "https://files.pythonhosted.org/packages/ac/96/84078e09f16a1dad208f2fe0f8a81be2cf36e024675b0f9eec0c2f6e2182/primp-0.15.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:592f6079646bdf5abbbfc3b0a28dac8de943f8907a250ce09398cda5eaebd260", size = 3418567, upload-time = "2025-04-17T11:41:01.595Z" }, + { url = "https://files.pythonhosted.org/packages/6c/80/8a7a9587d3eb85be3d0b64319f2f690c90eb7953e3f73a9ddd9e46c8dc42/primp-0.15.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5a728e5a05f37db6189eb413d22c78bd143fa59dd6a8a26dacd43332b3971fe8", size = 3606279, upload-time = "2025-04-17T11:41:03.61Z" }, + { url = "https://files.pythonhosted.org/packages/0c/dd/f0183ed0145e58cf9d286c1b2c14f63ccee987a4ff79ac85acc31b5d86bd/primp-0.15.0-cp38-abi3-win_amd64.whl", hash = "sha256:aeb6bd20b06dfc92cfe4436939c18de88a58c640752cf7f30d9e4ae893cdec32", size = 3149967, upload-time = "2025-04-17T11:41:07.067Z" }, +] + +[[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/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 = "protobuf" +version = "6.32.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/a4/cc17347aa2897568beece2e674674359f911d6fe21b0b8d6268cd42727ac/protobuf-6.32.1.tar.gz", hash = "sha256:ee2469e4a021474ab9baafea6cd070e5bf27c7d29433504ddea1a4ee5850f68d", size = 440635, upload-time = "2025-09-11T21:38:42.935Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/98/645183ea03ab3995d29086b8bf4f7562ebd3d10c9a4b14ee3f20d47cfe50/protobuf-6.32.1-cp310-abi3-win32.whl", hash = "sha256:a8a32a84bc9f2aad712041b8b366190f71dde248926da517bde9e832e4412085", size = 424411, upload-time = "2025-09-11T21:38:27.427Z" }, + { url = "https://files.pythonhosted.org/packages/8c/f3/6f58f841f6ebafe076cebeae33fc336e900619d34b1c93e4b5c97a81fdfa/protobuf-6.32.1-cp310-abi3-win_amd64.whl", hash = "sha256:b00a7d8c25fa471f16bc8153d0e53d6c9e827f0953f3c09aaa4331c718cae5e1", size = 435738, upload-time = "2025-09-11T21:38:30.959Z" }, + { url = "https://files.pythonhosted.org/packages/10/56/a8a3f4e7190837139e68c7002ec749190a163af3e330f65d90309145a210/protobuf-6.32.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d8c7e6eb619ffdf105ee4ab76af5a68b60a9d0f66da3ea12d1640e6d8dab7281", size = 426454, upload-time = "2025-09-11T21:38:34.076Z" }, + { url = "https://files.pythonhosted.org/packages/3f/be/8dd0a927c559b37d7a6c8ab79034fd167dcc1f851595f2e641ad62be8643/protobuf-6.32.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:2f5b80a49e1eb7b86d85fcd23fe92df154b9730a725c3b38c4e43b9d77018bf4", size = 322874, upload-time = "2025-09-11T21:38:35.509Z" }, + { url = "https://files.pythonhosted.org/packages/5c/f6/88d77011b605ef979aace37b7703e4eefad066f7e84d935e5a696515c2dd/protobuf-6.32.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:b1864818300c297265c83a4982fd3169f97122c299f56a56e2445c3698d34710", size = 322013, upload-time = "2025-09-11T21:38:37.017Z" }, + { url = "https://files.pythonhosted.org/packages/97/b7/15cc7d93443d6c6a84626ae3258a91f4c6ac8c0edd5df35ea7658f71b79c/protobuf-6.32.1-py3-none-any.whl", hash = "sha256:2601b779fc7d32a866c6b4404f9d42a3f67c5b9f3f15b4db3cccabe06b95c346", size = 169289, upload-time = "2025-09-11T21:38:41.234Z" }, +] + +[[package]] +name = "psycopg" +version = "3.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/db/2f/cb91e5502ec9de1de6f1b76cfbf69531932725361168bb06963620c77e2e/psycopg-3.3.4.tar.gz", hash = "sha256:e21207764952cff81b6b8bdacad9a3939f2793367fdac2987b3aac36a651b5bc", size = 165799, upload-time = "2026-05-01T23:31:55.179Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/e0/7b3dee031daae7743609ce3c746565d4a3ed7c2c186479eb48e34e838c64/psycopg-3.3.4-py3-none-any.whl", hash = "sha256:b6bbc25ccf05c8fad3b061d9db2ef0909a555171b84b07f29458a447253d679a", size = 213001, upload-time = "2026-05-01T23:20:50.816Z" }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.3.4" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/7d/03818e13ba7f36de93573c93ee3482006d3dfa8b0f8d28df511bad0a1a92/psycopg_binary-3.3.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5ab28a2a7649df3b72e6b674b4c190e448e8e77cf496a65bd846472048de2089", size = 4591122, upload-time = "2026-05-01T23:27:56.162Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b9/11b341edf8d54e2694726b273fe9652b254d989f4f63e3ac6816ad6b55f4/psycopg_binary-3.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6402a9d8146cf4b3974ded3fd28a971e83dc6a0333eb7822524a3aa20b546578", size = 4669943, upload-time = "2026-05-01T23:28:04.522Z" }, + { url = "https://files.pythonhosted.org/packages/8b/18/4665bacd65e7865b4372fcd8abb8b9186ada4b0025f8c2ca691b364a556c/psycopg_binary-3.3.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:580ae30a5f95ccd90008ec697d3ed6a4a2047a516407ad904283fa42086936e9", size = 5469697, upload-time = "2026-05-01T23:28:11.337Z" }, + { url = "https://files.pythonhosted.org/packages/7c/b1/b83136c6e510593d9b0c759ba5384337bc4ad82d19fda675adc4b2703c84/psycopg_binary-3.3.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7510c37550f91a187e3660a8cc50d4b760f8c3b8b2f89ebc5698cd2c7f2c85d", size = 5152995, upload-time = "2026-05-01T23:28:20.529Z" }, + { url = "https://files.pythonhosted.org/packages/67/8d/a9821e2a648afe6091989929982a3b0f00b2631a859cb81379728f08fb75/psycopg_binary-3.3.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77df19583501ea288eaf15ac0fe7ad01e6d8091a91d5c41df5c718f307d8e31b", size = 6738180, upload-time = "2026-05-01T23:28:30.654Z" }, + { url = "https://files.pythonhosted.org/packages/7e/58/2e349e8d23905dc2317b80ac65f48fb6f821a4777a4e994a60da91c4850f/psycopg_binary-3.3.4-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:018fbed325936da502feb546642c982dcc4b9ffdea32dfef78dbf3b7f7ad4070", size = 4978828, upload-time = "2026-05-01T23:28:37.277Z" }, + { url = "https://files.pythonhosted.org/packages/45/48/57b00d03b4721878326122a1f1e6b0a90b85bcaec56b5b2f8ea6cfa45235/psycopg_binary-3.3.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:17a21953a9e5ff3a16dab692625a3676e2f101db5e40072f39dbee2250194d68", size = 4509757, upload-time = "2026-05-01T23:28:43.078Z" }, + { url = "https://files.pythonhosted.org/packages/25/37/33b47d8c007df69aec500df5889767c4d313748e8e9e27a2fef8a6dabcee/psycopg_binary-3.3.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:eb05ee1c2b817d27c537333224c9e83c7afb86fe7296ba970990068baf819b16", size = 4190546, upload-time = "2026-05-01T23:28:50.016Z" }, + { url = "https://files.pythonhosted.org/packages/ca/c6/32b0835dbc2122617902b649d76a91c1e75406e76bf3d595b0c3bb5ffad6/psycopg_binary-3.3.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:773d573e11f437ce0bdb95b7c18dc58390494f96d43f8b45b9760436114f7652", size = 3926197, upload-time = "2026-05-01T23:28:55.55Z" }, + { url = "https://files.pythonhosted.org/packages/cd/68/d190ef0c0c5b16ded07831dabc8ddd412f4cdab07ec6e30ed38d9bda0e1f/psycopg_binary-3.3.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:71e55ccbdfae79a2ed9c6369c3008a3025817ff9d7e27b32a2d84e2a4267e66e", size = 4236627, upload-time = "2026-05-01T23:29:05.336Z" }, + { url = "https://files.pythonhosted.org/packages/25/8f/81dcbc2e8454b74d14881275ea45f00791052dac531a9fa8be1730d1685b/psycopg_binary-3.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:494ca54901be8cf9eb7e02c25b731f2317c378efa44f43e8f9bd0e1184ae7be4", size = 3560782, upload-time = "2026-05-01T23:29:11.967Z" }, + { url = "https://files.pythonhosted.org/packages/09/43/13e9c406fbbf354580476e248a16b64802a376873ebe6339e30bb655572d/psycopg_binary-3.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbd1d4ed566895ad2d3bf4ddfd8bae90026930ddf29df3b9d91d32c8c47866a7", size = 4590377, upload-time = "2026-05-01T23:29:18.782Z" }, + { url = "https://files.pythonhosted.org/packages/22/be/2923cd7c3683e7afdecf4f10796a18de02f5c5ddc0969aa2ad0a8cdd3bbd/psycopg_binary-3.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75a9067e236f9b9ae3535b66fe99bddb33d39c0de10112e49b9ab11eee53dc31", size = 4669023, upload-time = "2026-05-01T23:29:25.884Z" }, + { url = "https://files.pythonhosted.org/packages/96/a0/2c913d6fe13d6a8bd13597d36739bf47af063ad9399e402cfecab16f3c1e/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:b56b603ebcea8aa10b46228b8410ba7f13e7c2ee54389d4d9be0927fd8ce2a70", size = 5467423, upload-time = "2026-05-01T23:29:33.416Z" }, + { url = "https://files.pythonhosted.org/packages/e7/38/205d10bc1ad0df4a21c5c51659126bd3ea0ef98fcad1e852f78c249bb9c3/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c677c4ad433cb7150c8cd304a0769ae3bcfbe5ea0676eb53faa7b1443b16d0d3", size = 5151137, upload-time = "2026-05-01T23:29:42.013Z" }, + { url = "https://files.pythonhosted.org/packages/36/fc/f0381ddcd45eff3bb70dbca6823a996048d7f507b2ec3fc92c6fabc0fe87/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26df2717e59c0473e4465a97dfb1b7afebaa479277870fd5784d1436470db47c", size = 6736671, upload-time = "2026-05-01T23:29:51.626Z" }, + { url = "https://files.pythonhosted.org/packages/95/40/fa545ae152c24327651e5624e4902121e808270be36c10b12e9939be09bc/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dc1f79fd16bb1f3f4421417a514607539f17804d95c7ed617265369d1981cae", size = 4979601, upload-time = "2026-05-01T23:29:56.961Z" }, + { url = "https://files.pythonhosted.org/packages/86/e4/2f8a47ee97f90cd2b933d0463081d35631ff419de2b8c984a5f369857de0/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:136f199a407b5348b9b857c504aff60c77622a28482e7195839ce1b51238c4cc", size = 4510513, upload-time = "2026-05-01T23:30:07.243Z" }, + { url = "https://files.pythonhosted.org/packages/0e/0e/94e842ff4a7f98ed162580ca2e8b8864b28c1e0350f2443f8ee47f821167/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b6f5a29e9c775b9f12a1a717aa7a2c80f9e1db6f27ba44a5b59c80ac61d2ffcf", size = 4187243, upload-time = "2026-05-01T23:30:15.352Z" }, + { url = "https://files.pythonhosted.org/packages/d0/83/fc6c174b672e29b7de996ea77b6cbddf46c891751c3355f6974292baa6b4/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ee17a2cf4943cde261adfad1bbc5bf38d6b3776d7afff74c7cabcbeaeb08c260", size = 3927347, upload-time = "2026-05-01T23:30:21.186Z" }, + { url = "https://files.pythonhosted.org/packages/e9/65/768364d4a97a15b1a7f47ba52688c1686f22941d8332a8398cefc468e25f/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c4ab71be17bdca30cb34c34c4e1496e2f5d6f20c199c12bad226070b22ef9bf", size = 4236393, upload-time = "2026-05-01T23:30:26.211Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3b/218efbc9e645becd80cdf651acda05f85cfe546b7a9c0458c7cbc8fe1f74/psycopg_binary-3.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:dbfdb9b6cc79f31104a7b162a2b921b765fcc62af6c00540a167a8de47e4ed38", size = 3564592, upload-time = "2026-05-01T23:30:31.764Z" }, + { url = "https://files.pythonhosted.org/packages/48/a6/828c9185701dab71b234c2a76c38a08b098ebfec5020716b4e93807492b5/psycopg_binary-3.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:28b7398fdd19db3232c884fb24550bdfe951221f510e195e233299e4c9b78f97", size = 4607292, upload-time = "2026-05-01T23:30:38.962Z" }, + { url = "https://files.pythonhosted.org/packages/92/58/5b40dbc9d839045c9dae956960e4fb6d20bcabe6c59a2aa34fc3a371913f/psycopg_binary-3.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1fbaa292a3c8bb61b45df1ad3da1908ccee7cb889db9425e3557d9e34e2a4829", size = 4687023, upload-time = "2026-05-01T23:30:47.227Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/793f0ac107a9003b48441d0d1f9f616d96e0f37458dd8dc12528ceff55fb/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94596f9e7633ee3f6440711d43bb70aa31cc0a46a900ab8b4201a366ace5c9e7", size = 5486985, upload-time = "2026-05-01T23:30:55.517Z" }, + { url = "https://files.pythonhosted.org/packages/8f/26/42e8533497e2592334f68ec529cf5f840f7fa4e99575a4bb61aa184dbfbf/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8c0056529e68dbe9184cd4019a1f3d8f3a4ead2f6fc7a5afcf27d3314edd1277", size = 5168745, upload-time = "2026-05-01T23:31:01.904Z" }, + { url = "https://files.pythonhosted.org/packages/15/af/b7151776cc08d5935d45c833ec818a9beb417cf7c08239af1aafbdae78ee/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c09aad7051326e7603c14e50636db9c01f78272dc54b3accff03d46370461e6", size = 6761486, upload-time = "2026-05-01T23:31:14.511Z" }, + { url = "https://files.pythonhosted.org/packages/d0/ed/c92533b9124712d592cbf1cd6c76da933a2e0acea81dfe1fbe7e735f0cff/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:514404ed543efd620c85602b747df2a23cf1241b4067199e1a66f2d2757aaa41", size = 4997427, upload-time = "2026-05-01T23:31:20.901Z" }, + { url = "https://files.pythonhosted.org/packages/a2/23/ccadfd0de416aa188356daa199453af24087b042e296088706d190ae0295/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:46893c26858be12cc49ca4226ed6a60b4bfccadd946b3bebb783a60b38788228", size = 4533549, upload-time = "2026-05-01T23:31:26.204Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a0/c8f43cee36386f7bc891ab41a9d31ea07cf9826038e732da79f26b1e5f34/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:df1d567fc430f6df15c9fcf67d87685fc49bdb325adc0db5af1adfb2f44eb5c9", size = 4210256, upload-time = "2026-05-01T23:31:33.884Z" }, + { url = "https://files.pythonhosted.org/packages/4e/2c/c1547871be3790676e8868b38655496422f94f0978dfb66b74bdba2f1676/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:6b9016b1714da4dd5ecaaa75b82098aa5a0b87854ce9b092e21c27c4ae23e014", size = 3946204, upload-time = "2026-05-01T23:31:39.626Z" }, + { url = "https://files.pythonhosted.org/packages/c4/b1/f6670f00fa7ea601584623f6c11602ab92117d83eaff885e0210f6de7418/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:47c656a8a7ba6eb0cff1801a4caaa9c8bdc12d03080e273aff1c8ac39971a77e", size = 4255811, upload-time = "2026-05-01T23:31:44.986Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e6/5fff07a70d1f945ed90ae131c3bd76cab32beff7c58c6db15ad5820b6d1f/psycopg_binary-3.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:c37e024c07308cd06cf3ec51bfd0e7f6157585a4d84d1bce4a7f5f7913719bf8", size = 3666849, upload-time = "2026-05-01T23:31:51.165Z" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + +[[package]] +name = "pybase64" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/14/43297a7b7f0c1bf0c00b596f754ee3ac946128c64d21047ccf9c9bbc5165/pybase64-1.4.2.tar.gz", hash = "sha256:46cdefd283ed9643315d952fe44de80dc9b9a811ce6e3ec97fd1827af97692d0", size = 137246, upload-time = "2025-07-27T13:08:57.808Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/6d/11ede991e800797b9f5ebd528013b34eee5652df93de61ffb24503393fa5/pybase64-1.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2c75d1388855b5a1015b65096d7dbcc708e7de3245dcbedeb872ec05a09326", size = 38326, upload-time = "2025-07-27T13:03:09.065Z" }, + { url = "https://files.pythonhosted.org/packages/fe/84/87f1f565f42e2397e2aaa2477c86419f5173c3699881c42325c090982f0a/pybase64-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b621a972a01841368fdb9dedc55fd3c6e0c7217d0505ba3b1ebe95e7ef1b493", size = 31661, upload-time = "2025-07-27T13:03:10.295Z" }, + { url = "https://files.pythonhosted.org/packages/cb/2a/a24c810e7a61d2cc6f73fe9ee4872a03030887fa8654150901b15f376f65/pybase64-1.4.2-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f48c32ac6a16cbf57a5a96a073fef6ff7e3526f623cd49faa112b7f9980bafba", size = 68192, upload-time = "2025-07-27T13:03:11.467Z" }, + { url = "https://files.pythonhosted.org/packages/ee/87/d9baf98cbfc37b8657290ad4421f3a3c36aa0eafe4872c5859cfb52f3448/pybase64-1.4.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ace8b23093a6bb862477080d9059b784096ab2f97541e8bfc40d42f062875149", size = 71587, upload-time = "2025-07-27T13:03:12.719Z" }, + { url = "https://files.pythonhosted.org/packages/0b/89/3df043cc56ef3b91b7aa0c26ae822a2d7ec8da0b0fd7c309c879b0eb5988/pybase64-1.4.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1772c7532a7fb6301baea3dd3e010148dbf70cd1136a83c2f5f91bdc94822145", size = 59910, upload-time = "2025-07-27T13:03:14.266Z" }, + { url = "https://files.pythonhosted.org/packages/75/4f/6641e9edf37aeb4d4524dc7ba2168eff8d96c90e77f6283c2be3400ab380/pybase64-1.4.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:f86f7faddcba5cbfea475f8ab96567834c28bf09ca6c7c3d66ee445adac80d8f", size = 56701, upload-time = "2025-07-27T13:03:15.6Z" }, + { url = "https://files.pythonhosted.org/packages/2d/7f/20d8ac1046f12420a0954a45a13033e75f98aade36eecd00c64e3549b071/pybase64-1.4.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0b8c8e275b5294089f314814b4a50174ab90af79d6a4850f6ae11261ff6a7372", size = 59288, upload-time = "2025-07-27T13:03:16.823Z" }, + { url = "https://files.pythonhosted.org/packages/17/ea/9c0ca570e3e50b3c6c3442e280c83b321a0464c86a9db1f982a4ff531550/pybase64-1.4.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:864d85a0470c615807ae8b97d724d068b940a2d10ac13a5f1b9e75a3ce441758", size = 60267, upload-time = "2025-07-27T13:03:18.132Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46894929d71ccedebbfb0284173b0fea96bc029cd262654ba8451a7035d6/pybase64-1.4.2-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:47254d97ed2d8351e30ecfdb9e2414547f66ba73f8a09f932c9378ff75cd10c5", size = 54801, upload-time = "2025-07-27T13:03:19.669Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/02c95218ea964f0b2469717c2c69b48e63f4ca9f18af01a5b2a29e4c1216/pybase64-1.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:264b65ecc4f0ee73f3298ab83bbd8008f7f9578361b8df5b448f985d8c63e02a", size = 58599, upload-time = "2025-07-27T13:03:20.951Z" }, + { url = "https://files.pythonhosted.org/packages/15/45/ccc21004930789b8fb439d43e3212a6c260ccddb2bf450c39a20db093f33/pybase64-1.4.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbcc2b30cd740c16c9699f596f22c7a9e643591311ae72b1e776f2d539e9dd9d", size = 52388, upload-time = "2025-07-27T13:03:23.064Z" }, + { url = "https://files.pythonhosted.org/packages/c4/45/22e46e549710c4c237d77785b6fb1bc4c44c288a5c44237ba9daf5c34b82/pybase64-1.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cda9f79c22d51ee4508f5a43b673565f1d26af4330c99f114e37e3186fdd3607", size = 68802, upload-time = "2025-07-27T13:03:24.673Z" }, + { url = "https://files.pythonhosted.org/packages/55/0c/232c6261b81296e5593549b36e6e7884a5da008776d12665923446322c36/pybase64-1.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0c91c6d2a7232e2a1cd10b3b75a8bb657defacd4295a1e5e80455df2dfc84d4f", size = 57841, upload-time = "2025-07-27T13:03:25.948Z" }, + { url = "https://files.pythonhosted.org/packages/20/8a/b35a615ae6f04550d696bb179c414538b3b477999435fdd4ad75b76139e4/pybase64-1.4.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:a370dea7b1cee2a36a4d5445d4e09cc243816c5bc8def61f602db5a6f5438e52", size = 54320, upload-time = "2025-07-27T13:03:27.495Z" }, + { url = "https://files.pythonhosted.org/packages/d3/a9/8bd4f9bcc53689f1b457ecefed1eaa080e4949d65a62c31a38b7253d5226/pybase64-1.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9aa4de83f02e462a6f4e066811c71d6af31b52d7484de635582d0e3ec3d6cc3e", size = 56482, upload-time = "2025-07-27T13:03:28.942Z" }, + { url = "https://files.pythonhosted.org/packages/75/e5/4a7735b54a1191f61c3f5c2952212c85c2d6b06eb5fb3671c7603395f70c/pybase64-1.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83a1c2f9ed00fee8f064d548c8654a480741131f280e5750bb32475b7ec8ee38", size = 70959, upload-time = "2025-07-27T13:03:30.171Z" }, + { url = "https://files.pythonhosted.org/packages/d3/67/e2b6cb32c782e12304d467418e70da0212567f42bd4d3b5eb1fdf64920ad/pybase64-1.4.2-cp312-cp312-win32.whl", hash = "sha256:a6e5688b18d558e8c6b8701cc8560836c4bbeba61d33c836b4dba56b19423716", size = 33683, upload-time = "2025-07-27T13:03:31.775Z" }, + { url = "https://files.pythonhosted.org/packages/4f/bc/d5c277496063a09707486180f17abbdbdebbf2f5c4441b20b11d3cb7dc7c/pybase64-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:c995d21b8bd08aa179cd7dd4db0695c185486ecc72da1e8f6c37ec86cadb8182", size = 35817, upload-time = "2025-07-27T13:03:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/e6/69/e4be18ae685acff0ae77f75d4586590f29d2cd187bf603290cf1d635cad4/pybase64-1.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:e254b9258c40509c2ea063a7784f6994988f3f26099d6e08704e3c15dfed9a55", size = 30900, upload-time = "2025-07-27T13:03:34.499Z" }, + { url = "https://files.pythonhosted.org/packages/f4/56/5337f27a8b8d2d6693f46f7b36bae47895e5820bfa259b0072574a4e1057/pybase64-1.4.2-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:0f331aa59549de21f690b6ccc79360ffed1155c3cfbc852eb5c097c0b8565a2b", size = 33888, upload-time = "2025-07-27T13:03:35.698Z" }, + { url = "https://files.pythonhosted.org/packages/4c/09/f3f4b11fc9beda7e8625e29fb0f549958fcbb34fea3914e1c1d95116e344/pybase64-1.4.2-cp313-cp313-android_21_x86_64.whl", hash = "sha256:9dad20bf1f3ed9e6fe566c4c9d07d9a6c04f5a280daebd2082ffb8620b0a880d", size = 40796, upload-time = "2025-07-27T13:03:36.927Z" }, + { url = "https://files.pythonhosted.org/packages/e3/ff/470768f0fe6de0aa302a8cb1bdf2f9f5cffc3f69e60466153be68bc953aa/pybase64-1.4.2-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:69d3f0445b0faeef7bb7f93bf8c18d850785e2a77f12835f49e524cc54af04e7", size = 30914, upload-time = "2025-07-27T13:03:38.475Z" }, + { url = "https://files.pythonhosted.org/packages/75/6b/d328736662665e0892409dc410353ebef175b1be5eb6bab1dad579efa6df/pybase64-1.4.2-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2372b257b1f4dd512f317fb27e77d313afd137334de64c87de8374027aacd88a", size = 31380, upload-time = "2025-07-27T13:03:39.7Z" }, + { url = "https://files.pythonhosted.org/packages/ca/96/7ff718f87c67f4147c181b73d0928897cefa17dc75d7abc6e37730d5908f/pybase64-1.4.2-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:fb794502b4b1ec91c4ca5d283ae71aef65e3de7721057bd9e2b3ec79f7a62d7d", size = 38230, upload-time = "2025-07-27T13:03:41.637Z" }, + { url = "https://files.pythonhosted.org/packages/4d/58/a3307b048d799ff596a3c7c574fcba66f9b6b8c899a3c00a698124ca7ad5/pybase64-1.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d5c532b03fd14a5040d6cf6571299a05616f925369c72ddf6fe2fb643eb36fed", size = 38319, upload-time = "2025-07-27T13:03:42.847Z" }, + { url = "https://files.pythonhosted.org/packages/08/a7/0bda06341b0a2c830d348c6e1c4d348caaae86c53dc9a046e943467a05e9/pybase64-1.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f699514dc1d5689ca9cf378139e0214051922732f9adec9404bc680a8bef7c0", size = 31655, upload-time = "2025-07-27T13:03:44.426Z" }, + { url = "https://files.pythonhosted.org/packages/87/df/e1d6e8479e0c5113c2c63c7b44886935ce839c2d99884c7304ca9e86547c/pybase64-1.4.2-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:cd3e8713cbd32c8c6aa935feaf15c7670e2b7e8bfe51c24dc556811ebd293a29", size = 68232, upload-time = "2025-07-27T13:03:45.729Z" }, + { url = "https://files.pythonhosted.org/packages/71/ab/db4dbdfccb9ca874d6ce34a0784761471885d96730de85cee3d300381529/pybase64-1.4.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d377d48acf53abf4b926c2a7a24a19deb092f366a04ffd856bf4b3aa330b025d", size = 71608, upload-time = "2025-07-27T13:03:47.01Z" }, + { url = "https://files.pythonhosted.org/packages/11/e9/508df958563951045d728bbfbd3be77465f9231cf805cb7ccaf6951fc9f1/pybase64-1.4.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d83c076e78d619b9e1dd674e2bf5fb9001aeb3e0b494b80a6c8f6d4120e38cd9", size = 59912, upload-time = "2025-07-27T13:03:48.277Z" }, + { url = "https://files.pythonhosted.org/packages/f2/58/7f2cef1ceccc682088958448d56727369de83fa6b29148478f4d2acd107a/pybase64-1.4.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:ab9cdb6a8176a5cb967f53e6ad60e40c83caaa1ae31c5e1b29e5c8f507f17538", size = 56413, upload-time = "2025-07-27T13:03:49.908Z" }, + { url = "https://files.pythonhosted.org/packages/08/7c/7e0af5c5728fa7e2eb082d88eca7c6bd17429be819d58518e74919d42e66/pybase64-1.4.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:adf0c103ad559dbfb9fe69edfd26a15c65d9c991a5ab0a25b04770f9eb0b9484", size = 59311, upload-time = "2025-07-27T13:03:51.238Z" }, + { url = "https://files.pythonhosted.org/packages/03/8b/09825d0f37e45b9a3f546e5f990b6cf2dd838e54ea74122c2464646e0c77/pybase64-1.4.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:0d03ef2f253d97ce0685d3624bf5e552d716b86cacb8a6c971333ba4b827e1fc", size = 60282, upload-time = "2025-07-27T13:03:52.56Z" }, + { url = "https://files.pythonhosted.org/packages/9c/3f/3711d2413f969bfd5b9cc19bc6b24abae361b7673ff37bcb90c43e199316/pybase64-1.4.2-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:e565abf906efee76ae4be1aef5df4aed0fda1639bc0d7732a3dafef76cb6fc35", size = 54845, upload-time = "2025-07-27T13:03:54.167Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3c/4c7ce1ae4d828c2bb56d144322f81bffbaaac8597d35407c3d7cbb0ff98f/pybase64-1.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3c6a5f15fd03f232fc6f295cce3684f7bb08da6c6d5b12cc771f81c9f125cc6", size = 58615, upload-time = "2025-07-27T13:03:55.494Z" }, + { url = "https://files.pythonhosted.org/packages/f5/8f/c2fc03bf4ed038358620065c75968a30184d5d3512d09d3ef9cc3bd48592/pybase64-1.4.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bad9e3db16f448728138737bbd1af9dc2398efd593a8bdd73748cc02cd33f9c6", size = 52434, upload-time = "2025-07-27T13:03:56.808Z" }, + { url = "https://files.pythonhosted.org/packages/e2/0a/757d6df0a60327c893cfae903e15419914dd792092dc8cc5c9523d40bc9b/pybase64-1.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2683ef271328365c31afee0ed8fa29356fb8fb7c10606794656aa9ffb95e92be", size = 68824, upload-time = "2025-07-27T13:03:58.735Z" }, + { url = "https://files.pythonhosted.org/packages/a0/14/84abe2ed8c29014239be1cfab45dfebe5a5ca779b177b8b6f779bd8b69da/pybase64-1.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:265b20089cd470079114c09bb74b101b3bfc3c94ad6b4231706cf9eff877d570", size = 57898, upload-time = "2025-07-27T13:04:00.379Z" }, + { url = "https://files.pythonhosted.org/packages/7e/c6/d193031f90c864f7b59fa6d1d1b5af41f0f5db35439988a8b9f2d1b32a13/pybase64-1.4.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e53173badead10ef8b839aa5506eecf0067c7b75ad16d9bf39bc7144631f8e67", size = 54319, upload-time = "2025-07-27T13:04:01.742Z" }, + { url = "https://files.pythonhosted.org/packages/cb/37/ec0c7a610ff8f994ee6e0c5d5d66b6b6310388b96ebb347b03ae39870fdf/pybase64-1.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5823b8dcf74da7da0f761ed60c961e8928a6524e520411ad05fe7f9f47d55b40", size = 56472, upload-time = "2025-07-27T13:04:03.089Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5a/e585b74f85cedd261d271e4c2ef333c5cfce7e80750771808f56fee66b98/pybase64-1.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1237f66c54357d325390da60aa5e21c6918fbcd1bf527acb9c1f4188c62cb7d5", size = 70966, upload-time = "2025-07-27T13:04:04.361Z" }, + { url = "https://files.pythonhosted.org/packages/ad/20/1b2fdd98b4ba36008419668c813025758214c543e362c66c49214ecd1127/pybase64-1.4.2-cp313-cp313-win32.whl", hash = "sha256:b0b851eb4f801d16040047f6889cca5e9dfa102b3e33f68934d12511245cef86", size = 33681, upload-time = "2025-07-27T13:04:06.126Z" }, + { url = "https://files.pythonhosted.org/packages/ff/64/3df4067d169c047054889f34b5a946cbe3785bca43404b93c962a5461a41/pybase64-1.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:19541c6e26d17d9522c02680fe242206ae05df659c82a657aabadf209cd4c6c7", size = 35822, upload-time = "2025-07-27T13:04:07.752Z" }, + { url = "https://files.pythonhosted.org/packages/d1/fd/db505188adf812e60ee923f196f9deddd8a1895b2b29b37f5db94afc3b1c/pybase64-1.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:77a191863d576c0a5dd81f8a568a5ca15597cc980ae809dce62c717c8d42d8aa", size = 30899, upload-time = "2025-07-27T13:04:09.062Z" }, + { url = "https://files.pythonhosted.org/packages/d9/27/5f5fecd206ec1e06e1608a380af18dcb76a6ab08ade6597a3251502dcdb2/pybase64-1.4.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2e194bbabe3fdf9e47ba9f3e157394efe0849eb226df76432126239b3f44992c", size = 38677, upload-time = "2025-07-27T13:04:10.334Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0f/abe4b5a28529ef5f74e8348fa6a9ef27d7d75fbd98103d7664cf485b7d8f/pybase64-1.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:39aef1dadf4a004f11dd09e703abaf6528a87c8dbd39c448bb8aebdc0a08c1be", size = 32066, upload-time = "2025-07-27T13:04:11.641Z" }, + { url = "https://files.pythonhosted.org/packages/ac/7e/ea0ce6a7155cada5526017ec588b6d6185adea4bf9331565272f4ef583c2/pybase64-1.4.2-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:91cb920c7143e36ec8217031282c8651da3b2206d70343f068fac0e7f073b7f9", size = 72300, upload-time = "2025-07-27T13:04:12.969Z" }, + { url = "https://files.pythonhosted.org/packages/45/2d/e64c7a056c9ec48dfe130d1295e47a8c2b19c3984488fc08e5eaa1e86c88/pybase64-1.4.2-cp313-cp313t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6958631143fb9e71f9842000da042ec2f6686506b6706e2dfda29e97925f6aa0", size = 75520, upload-time = "2025-07-27T13:04:14.374Z" }, + { url = "https://files.pythonhosted.org/packages/43/e0/e5f93b2e1cb0751a22713c4baa6c6eaf5f307385e369180486c8316ed21e/pybase64-1.4.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:dc35f14141ef3f1ac70d963950a278a2593af66fe5a1c7a208e185ca6278fa25", size = 65384, upload-time = "2025-07-27T13:04:16.204Z" }, + { url = "https://files.pythonhosted.org/packages/ff/23/8c645a1113ad88a1c6a3d0e825e93ef8b74ad3175148767853a0a4d7626e/pybase64-1.4.2-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:5d949d2d677859c3a8507e1b21432a039d2b995e0bd3fe307052b6ded80f207a", size = 60471, upload-time = "2025-07-27T13:04:17.947Z" }, + { url = "https://files.pythonhosted.org/packages/8b/81/edd0f7d8b0526b91730a0dd4ce6b4c8be2136cd69d424afe36235d2d2a06/pybase64-1.4.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:09caacdd3e15fe7253a67781edd10a6a918befab0052a2a3c215fe5d1f150269", size = 63945, upload-time = "2025-07-27T13:04:19.383Z" }, + { url = "https://files.pythonhosted.org/packages/a5/a5/edc224cd821fd65100b7af7c7e16b8f699916f8c0226c9c97bbae5a75e71/pybase64-1.4.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:e44b0e793b23f28ea0f15a9754bd0c960102a2ac4bccb8fafdedbd4cc4d235c0", size = 64858, upload-time = "2025-07-27T13:04:20.807Z" }, + { url = "https://files.pythonhosted.org/packages/11/3b/92853f968f1af7e42b7e54d21bdd319097b367e7dffa2ca20787361df74c/pybase64-1.4.2-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:849f274d0bcb90fc6f642c39274082724d108e41b15f3a17864282bd41fc71d5", size = 58557, upload-time = "2025-07-27T13:04:22.229Z" }, + { url = "https://files.pythonhosted.org/packages/76/09/0ec6bd2b2303b0ea5c6da7535edc9a608092075ef8c0cdd96e3e726cd687/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:528dba7ef1357bd7ce1aea143084501f47f5dd0fff7937d3906a68565aa59cfe", size = 63624, upload-time = "2025-07-27T13:04:23.952Z" }, + { url = "https://files.pythonhosted.org/packages/73/6e/52cb1ced2a517a3118b2e739e9417432049013ac7afa15d790103059e8e4/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:1da54be743d9a68671700cfe56c3ab8c26e8f2f5cc34eface905c55bc3a9af94", size = 56174, upload-time = "2025-07-27T13:04:25.419Z" }, + { url = "https://files.pythonhosted.org/packages/5b/9d/820fe79347467e48af985fe46180e1dd28e698ade7317bebd66de8a143f5/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9b07c0406c3eaa7014499b0aacafb21a6d1146cfaa85d56f0aa02e6d542ee8f3", size = 72640, upload-time = "2025-07-27T13:04:26.824Z" }, + { url = "https://files.pythonhosted.org/packages/53/58/e863e10d08361e694935c815b73faad7e1ab03f99ae154d86c4e2f331896/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:312f2aa4cf5d199a97fbcaee75d2e59ebbaafcd091993eb373b43683498cdacb", size = 62453, upload-time = "2025-07-27T13:04:28.562Z" }, + { url = "https://files.pythonhosted.org/packages/95/f0/c392c4ac8ccb7a34b28377c21faa2395313e3c676d76c382642e19a20703/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad59362fc267bf15498a318c9e076686e4beeb0dfe09b457fabbc2b32468b97a", size = 58103, upload-time = "2025-07-27T13:04:29.996Z" }, + { url = "https://files.pythonhosted.org/packages/32/30/00ab21316e7df8f526aa3e3dc06f74de6711d51c65b020575d0105a025b2/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:01593bd064e7dcd6c86d04e94e44acfe364049500c20ac68ca1e708fbb2ca970", size = 60779, upload-time = "2025-07-27T13:04:31.549Z" }, + { url = "https://files.pythonhosted.org/packages/a6/65/114ca81839b1805ce4a2b7d58bc16e95634734a2059991f6382fc71caf3e/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5b81547ad8ea271c79fdf10da89a1e9313cb15edcba2a17adf8871735e9c02a0", size = 74684, upload-time = "2025-07-27T13:04:32.976Z" }, + { url = "https://files.pythonhosted.org/packages/54/8f/aa9d445b9bb693b8f6bb1456bd6d8576d79b7a63bf6c69af3a539235b15f/pybase64-1.4.2-cp313-cp313t-win32.whl", hash = "sha256:7edbe70b5654545a37e6e6b02de738303b1bbdfcde67f6cfec374cfb5cc4099e", size = 33961, upload-time = "2025-07-27T13:04:34.806Z" }, + { url = "https://files.pythonhosted.org/packages/0e/e5/da37cfb173c646fd4fc7c6aae2bc41d40de2ee49529854af8f4e6f498b45/pybase64-1.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:385690addf87c25d6366fab5d8ff512eed8a7ecb18da9e8152af1c789162f208", size = 36199, upload-time = "2025-07-27T13:04:36.223Z" }, + { url = "https://files.pythonhosted.org/packages/66/3e/1eb68fb7d00f2cec8bd9838e2a30d183d6724ae06e745fd6e65216f170ff/pybase64-1.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c2070d0aa88580f57fe15ca88b09f162e604d19282915a95a3795b5d3c1c05b5", size = 31221, upload-time = "2025-07-27T13:04:37.704Z" }, + { url = "https://files.pythonhosted.org/packages/99/bf/00a87d951473ce96c8c08af22b6983e681bfabdb78dd2dcf7ee58eac0932/pybase64-1.4.2-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:4157ad277a32cf4f02a975dffc62a3c67d73dfa4609b2c1978ef47e722b18b8e", size = 30924, upload-time = "2025-07-27T13:04:39.189Z" }, + { url = "https://files.pythonhosted.org/packages/ae/43/dee58c9d60e60e6fb32dc6da722d84592e22f13c277297eb4ce6baf99a99/pybase64-1.4.2-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e113267dc349cf624eb4f4fbf53fd77835e1aa048ac6877399af426aab435757", size = 31390, upload-time = "2025-07-27T13:04:40.995Z" }, + { url = "https://files.pythonhosted.org/packages/e1/11/b28906fc2e330b8b1ab4bc845a7bef808b8506734e90ed79c6062b095112/pybase64-1.4.2-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:cea5aaf218fd9c5c23afacfe86fd4464dfedc1a0316dd3b5b4075b068cc67df0", size = 38212, upload-time = "2025-07-27T13:04:42.729Z" }, + { url = "https://files.pythonhosted.org/packages/24/9e/868d1e104413d14b19feaf934fc7fad4ef5b18946385f8bb79684af40f24/pybase64-1.4.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:41213497abbd770435c7a9c8123fb02b93709ac4cf60155cd5aefc5f3042b600", size = 38303, upload-time = "2025-07-27T13:04:44.095Z" }, + { url = "https://files.pythonhosted.org/packages/a3/73/f7eac96ca505df0600280d6bfc671a9e2e2f947c2b04b12a70e36412f7eb/pybase64-1.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c8b522df7ee00f2ac1993ccd5e1f6608ae7482de3907668c2ff96a83ef213925", size = 31669, upload-time = "2025-07-27T13:04:45.845Z" }, + { url = "https://files.pythonhosted.org/packages/c6/43/8e18bea4fd455100112d6a73a83702843f067ef9b9272485b6bdfd9ed2f0/pybase64-1.4.2-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:06725022e540c5b098b978a0418ca979773e2cbdbb76f10bd97536f2ad1c5b49", size = 68452, upload-time = "2025-07-27T13:04:47.788Z" }, + { url = "https://files.pythonhosted.org/packages/e4/2e/851eb51284b97354ee5dfa1309624ab90920696e91a33cd85b13d20cc5c1/pybase64-1.4.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a3e54dcf0d0305ec88473c9d0009f698cabf86f88a8a10090efeff2879c421bb", size = 71674, upload-time = "2025-07-27T13:04:49.294Z" }, + { url = "https://files.pythonhosted.org/packages/57/0d/5cf1e5dc64aec8db43e8dee4e4046856d639a72bcb0fb3e716be42ced5f1/pybase64-1.4.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67675cee727a60dc91173d2790206f01aa3c7b3fbccfa84fd5c1e3d883fe6caa", size = 60027, upload-time = "2025-07-27T13:04:50.769Z" }, + { url = "https://files.pythonhosted.org/packages/a4/8e/3479266bc0e65f6cc48b3938d4a83bff045330649869d950a378f2ddece0/pybase64-1.4.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:753da25d4fd20be7bda2746f545935773beea12d5cb5ec56ec2d2960796477b1", size = 56461, upload-time = "2025-07-27T13:04:52.37Z" }, + { url = "https://files.pythonhosted.org/packages/20/b6/f2b6cf59106dd78bae8717302be5b814cec33293504ad409a2eb752ad60c/pybase64-1.4.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a78c768ce4ca550885246d14babdb8923e0f4a848dfaaeb63c38fc99e7ea4052", size = 59446, upload-time = "2025-07-27T13:04:53.967Z" }, + { url = "https://files.pythonhosted.org/packages/16/70/3417797dfccdfdd0a54e4ad17c15b0624f0fc2d6a362210f229f5c4e8fd0/pybase64-1.4.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:51b17f36d890c92f0618fb1c8db2ccc25e6ed07afa505bab616396fc9b0b0492", size = 60350, upload-time = "2025-07-27T13:04:55.881Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c6/6e4269dd98d150ae95d321b311a345eae0f7fd459d97901b4a586d7513bb/pybase64-1.4.2-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f92218d667049ab4f65d54fa043a88ffdb2f07fff1f868789ef705a5221de7ec", size = 54989, upload-time = "2025-07-27T13:04:57.436Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e8/18c1b0c255f964fafd0412b0d5a163aad588aeccb8f84b9bf9c8611d80f6/pybase64-1.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3547b3d1499919a06491b3f879a19fbe206af2bd1a424ecbb4e601eb2bd11fea", size = 58724, upload-time = "2025-07-27T13:04:59.406Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ad/ddfbd2125fc20b94865fb232b2e9105376fa16eee492e4b7786d42a86cbf/pybase64-1.4.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:958af7b0e09ddeb13e8c2330767c47b556b1ade19c35370f6451d139cde9f2a9", size = 52285, upload-time = "2025-07-27T13:05:01.198Z" }, + { url = "https://files.pythonhosted.org/packages/b6/4c/b9d4ec9224add33c84b925a03d1a53cd4106efb449ea8e0ae7795fed7bf7/pybase64-1.4.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:4facc57f6671e2229a385a97a618273e7be36a9ea0a9d1c1b9347f14d19ceba8", size = 69036, upload-time = "2025-07-27T13:05:03.109Z" }, + { url = "https://files.pythonhosted.org/packages/92/38/7b96794da77bed3d9b4fea40f14ae563648fba83a696e7602fabe60c0eb7/pybase64-1.4.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a32fc57d05d73a7c9b0ca95e9e265e21cf734195dc6873829a890058c35f5cfd", size = 57938, upload-time = "2025-07-27T13:05:04.744Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c5/ae8bbce3c322d1b074e79f51f5df95961fe90cb8748df66c6bc97616e974/pybase64-1.4.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3dc853243c81ce89cc7318e6946f860df28ddb7cd2a0648b981652d9ad09ee5a", size = 54474, upload-time = "2025-07-27T13:05:06.662Z" }, + { url = "https://files.pythonhosted.org/packages/15/9a/c09887c4bb1b43c03fc352e2671ef20c6686c6942a99106a45270ee5b840/pybase64-1.4.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0e6d863a86b3e7bc6ac9bd659bebda4501b9da842521111b0b0e54eb51295df5", size = 56533, upload-time = "2025-07-27T13:05:08.368Z" }, + { url = "https://files.pythonhosted.org/packages/4f/0f/d5114d63d35d085639606a880cb06e2322841cd4b213adfc14d545c1186f/pybase64-1.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6579475140ff2067903725d8aca47f5747bcb211597a1edd60b58f6d90ada2bd", size = 71030, upload-time = "2025-07-27T13:05:10.3Z" }, + { url = "https://files.pythonhosted.org/packages/40/0e/fe6f1ed22ea52eb99f490a8441815ba21de288f4351aeef4968d71d20d2d/pybase64-1.4.2-cp314-cp314-win32.whl", hash = "sha256:373897f728d7b4f241a1f803ac732c27b6945d26d86b2741ad9b75c802e4e378", size = 34174, upload-time = "2025-07-27T13:05:12.254Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/0e15bea52ffc63e8ae7935e945accbaf635e0aefa26d3e31fdf9bc9dcd01/pybase64-1.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:1afe3361344617d298c1d08bc657ef56d0f702d6b72cb65d968b2771017935aa", size = 36308, upload-time = "2025-07-27T13:05:13.898Z" }, + { url = "https://files.pythonhosted.org/packages/4f/dc/55849fee2577bda77c1e078da04cc9237e8e474a8c8308deb702a26f2511/pybase64-1.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:f131c9360babe522f3d90f34da3f827cba80318125cf18d66f2ee27e3730e8c4", size = 31341, upload-time = "2025-07-27T13:05:15.553Z" }, + { url = "https://files.pythonhosted.org/packages/39/44/c69d088e28b25e70ac742b6789cde038473815b2a69345c4bae82d5e244d/pybase64-1.4.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2583ac304131c1bd6e3120b0179333610f18816000db77c0a2dd6da1364722a8", size = 38678, upload-time = "2025-07-27T13:05:17.544Z" }, + { url = "https://files.pythonhosted.org/packages/00/93/2860ec067497b9cbb06242f96d44caebbd9eed32174e4eb8c1ffef760f94/pybase64-1.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:75a8116be4ea4cdd30a5c4f1a6f3b038e0d457eb03c8a2685d8ce2aa00ef8f92", size = 32066, upload-time = "2025-07-27T13:05:19.18Z" }, + { url = "https://files.pythonhosted.org/packages/d3/55/1e96249a38759332e8a01b31c370d88c60ceaf44692eb6ba4f0f451ee496/pybase64-1.4.2-cp314-cp314t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:217ea776a098d7c08668e5526b9764f5048bbfd28cac86834217ddfe76a4e3c4", size = 72465, upload-time = "2025-07-27T13:05:20.866Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ab/0f468605b899f3e35dbb7423fba3ff98aeed1ec16abb02428468494a58f4/pybase64-1.4.2-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4ec14683e343c95b14248cdfdfa78c052582be7a3865fd570aa7cffa5ab5cf37", size = 75693, upload-time = "2025-07-27T13:05:22.896Z" }, + { url = "https://files.pythonhosted.org/packages/91/d1/9980a0159b699e2489baba05b71b7c953b29249118ba06fdbb3e9ea1b9b5/pybase64-1.4.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:480ecf21e1e956c5a10d3cf7b3b7e75bce3f9328cf08c101e4aab1925d879f34", size = 65577, upload-time = "2025-07-27T13:05:25Z" }, + { url = "https://files.pythonhosted.org/packages/16/86/b27e7b95f9863d245c0179a7245582eda3d262669d8f822777364d8fd7d5/pybase64-1.4.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:1fe1ebdc55e9447142e2f6658944aadfb5a4fbf03dbd509be34182585515ecc1", size = 60662, upload-time = "2025-07-27T13:05:27.138Z" }, + { url = "https://files.pythonhosted.org/packages/28/87/a7f0dde0abc26bfbee761f1d3558eb4b139f33ddd9fe1f6825ffa7daa22d/pybase64-1.4.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c793a2b06753accdaf5e1a8bbe5d800aab2406919e5008174f989a1ca0081411", size = 64179, upload-time = "2025-07-27T13:05:28.996Z" }, + { url = "https://files.pythonhosted.org/packages/1e/88/5d6fa1c60e1363b4cac4c396978f39e9df4689e75225d7d9c0a5998e3a14/pybase64-1.4.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6acae6e1d1f7ebe40165f08076c7a73692b2bf9046fefe673f350536e007f556", size = 64968, upload-time = "2025-07-27T13:05:30.818Z" }, + { url = "https://files.pythonhosted.org/packages/20/6e/2ed585af5b2211040445d9849326dd2445320c9316268794f5453cfbaf30/pybase64-1.4.2-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:88b91cd0949358aadcea75f8de5afbcf3c8c5fb9ec82325bd24285b7119cf56e", size = 58738, upload-time = "2025-07-27T13:05:32.629Z" }, + { url = "https://files.pythonhosted.org/packages/ce/94/e2960b56322eabb3fbf303fc5a72e6444594c1b90035f3975c6fe666db5c/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:53316587e1b1f47a11a5ff068d3cbd4a3911c291f2aec14882734973684871b2", size = 63802, upload-time = "2025-07-27T13:05:34.687Z" }, + { url = "https://files.pythonhosted.org/packages/95/47/312139d764c223f534f751528ce3802887c279125eac64f71cd3b4e05abc/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:caa7f20f43d00602cf9043b5ba758d54f5c41707d3709b2a5fac17361579c53c", size = 56341, upload-time = "2025-07-27T13:05:36.554Z" }, + { url = "https://files.pythonhosted.org/packages/3f/d7/aec9a6ed53b128dac32f8768b646ca5730c88eef80934054d7fa7d02f3ef/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2d93817e24fdd79c534ed97705df855af6f1d2535ceb8dfa80da9de75482a8d7", size = 72838, upload-time = "2025-07-27T13:05:38.459Z" }, + { url = "https://files.pythonhosted.org/packages/e3/a8/6ccc54c5f1f7c3450ad7c56da10c0f131d85ebe069ea6952b5b42f2e92d9/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:63cd769b51474d8d08f7f2ce73b30380d9b4078ec92ea6b348ea20ed1e1af88a", size = 62633, upload-time = "2025-07-27T13:05:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/34/22/2b9d89f8ff6f2a01d6d6a88664b20a4817049cfc3f2c62caca040706660c/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cd07e6a9993c392ec8eb03912a43c6a6b21b2deb79ee0d606700fe276e9a576f", size = 58282, upload-time = "2025-07-27T13:05:42.565Z" }, + { url = "https://files.pythonhosted.org/packages/b2/14/dbf6266177532a6a11804ac080ebffcee272f491b92820c39886ee20f201/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:6a8944e8194adff4668350504bc6b7dbde2dab9244c88d99c491657d145b5af5", size = 60948, upload-time = "2025-07-27T13:05:44.48Z" }, + { url = "https://files.pythonhosted.org/packages/fd/7a/b2ae9046a66dd5746cd72836a41386517b1680bea5ce02f2b4f1c9ebc688/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:04ab398ec4b6a212af57f6a21a6336d5a1d754ff4ccb215951366ab9080481b2", size = 74854, upload-time = "2025-07-27T13:05:46.416Z" }, + { url = "https://files.pythonhosted.org/packages/ef/7e/9856f6d6c38a7b730e001123d2d9fa816b8b1a45f0cdee1d509d5947b047/pybase64-1.4.2-cp314-cp314t-win32.whl", hash = "sha256:3b9201ecdcb1c3e23be4caebd6393a4e6615bd0722528f5413b58e22e3792dd3", size = 34490, upload-time = "2025-07-27T13:05:48.304Z" }, + { url = "https://files.pythonhosted.org/packages/c7/38/8523a9dc1ec8704dedbe5ccc95192ae9a7585f7eec85cc62946fe3cacd32/pybase64-1.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:36e9b0cad8197136d73904ef5a71d843381d063fd528c5ab203fc4990264f682", size = 36680, upload-time = "2025-07-27T13:05:50.264Z" }, + { url = "https://files.pythonhosted.org/packages/3c/52/5600104ef7b85f89fb8ec54f73504ead3f6f0294027e08d281f3cafb5c1a/pybase64-1.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:f25140496b02db0e7401567cd869fb13b4c8118bf5c2428592ec339987146d8b", size = 31600, upload-time = "2025-07-27T13:05:52.24Z" }, +] + +[[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.0" +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/c3/da/b8a7ee04378a53f6fefefc0c5e05570a3ebfdfa0523a878bcd3b475683ee/pydantic-2.12.0.tar.gz", hash = "sha256:c1a077e6270dbfb37bfd8b498b3981e2bb18f68103720e51fa6c306a5a9af563", size = 814760, upload-time = "2025-10-07T15:58:03.467Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/9d/d5c855424e2e5b6b626fbc6ec514d8e655a600377ce283008b115abb7445/pydantic-2.12.0-py3-none-any.whl", hash = "sha256:f6a1da352d42790537e95e83a8bdfb91c7efbae63ffd0b86fa823899e807116f", size = 459730, upload-time = "2025-10-07T15:58:01.576Z" }, +] + +[package.optional-dependencies] +email = [ + { name = "email-validator" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/14/12b4a0d2b0b10d8e1d9a24ad94e7bbb43335eaf29c0c4e57860e8a30734a/pydantic_core-2.41.1.tar.gz", hash = "sha256:1ad375859a6d8c356b7704ec0f547a58e82ee80bb41baa811ad710e124bc8f2f", size = 454870, upload-time = "2025-10-07T10:50:45.974Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/bc/5f520319ee1c9e25010412fac4154a72e0a40d0a19eb00281b1f200c0947/pydantic_core-2.41.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:db2f82c0ccbce8f021ad304ce35cbe02aa2f95f215cac388eed542b03b4d5eb4", size = 2099300, upload-time = "2025-10-06T21:10:30.463Z" }, + { url = "https://files.pythonhosted.org/packages/31/14/010cd64c5c3814fb6064786837ec12604be0dd46df3327cf8474e38abbbd/pydantic_core-2.41.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47694a31c710ced9205d5f1e7e8af3ca57cbb8a503d98cb9e33e27c97a501601", size = 1910179, upload-time = "2025-10-06T21:10:31.782Z" }, + { url = "https://files.pythonhosted.org/packages/8e/2e/23fc2a8a93efad52df302fdade0a60f471ecc0c7aac889801ac24b4c07d6/pydantic_core-2.41.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e9decce94daf47baf9e9d392f5f2557e783085f7c5e522011545d9d6858e00", size = 1957225, upload-time = "2025-10-06T21:10:33.11Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b6/6db08b2725b2432b9390844852e11d320281e5cea8a859c52c68001975fa/pydantic_core-2.41.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab0adafdf2b89c8b84f847780a119437a0931eca469f7b44d356f2b426dd9741", size = 2053315, upload-time = "2025-10-06T21:10:34.87Z" }, + { url = "https://files.pythonhosted.org/packages/61/d9/4de44600f2d4514b44f3f3aeeda2e14931214b6b5bf52479339e801ce748/pydantic_core-2.41.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5da98cc81873f39fd56882e1569c4677940fbc12bce6213fad1ead784192d7c8", size = 2224298, upload-time = "2025-10-06T21:10:36.233Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ae/dbe51187a7f35fc21b283c5250571a94e36373eb557c1cba9f29a9806dcf/pydantic_core-2.41.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:209910e88afb01fd0fd403947b809ba8dba0e08a095e1f703294fda0a8fdca51", size = 2351797, upload-time = "2025-10-06T21:10:37.601Z" }, + { url = "https://files.pythonhosted.org/packages/b5/a7/975585147457c2e9fb951c7c8dab56deeb6aa313f3aa72c2fc0df3f74a49/pydantic_core-2.41.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365109d1165d78d98e33c5bfd815a9b5d7d070f578caefaabcc5771825b4ecb5", size = 2074921, upload-time = "2025-10-06T21:10:38.927Z" }, + { url = "https://files.pythonhosted.org/packages/62/37/ea94d1d0c01dec1b7d236c7cec9103baab0021f42500975de3d42522104b/pydantic_core-2.41.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:706abf21e60a2857acdb09502bc853ee5bce732955e7b723b10311114f033115", size = 2187767, upload-time = "2025-10-06T21:10:40.651Z" }, + { url = "https://files.pythonhosted.org/packages/d3/fe/694cf9fdd3a777a618c3afd210dba7b414cb8a72b1bd29b199c2e5765fee/pydantic_core-2.41.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bf0bd5417acf7f6a7ec3b53f2109f587be176cb35f9cf016da87e6017437a72d", size = 2136062, upload-time = "2025-10-06T21:10:42.09Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/174aeabd89916fbd2988cc37b81a59e1186e952afd2a7ed92018c22f31ca/pydantic_core-2.41.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:2e71b1c6ceb9c78424ae9f63a07292fb769fb890a4e7efca5554c47f33a60ea5", size = 2317819, upload-time = "2025-10-06T21:10:43.974Z" }, + { url = "https://files.pythonhosted.org/packages/65/e8/e9aecafaebf53fc456314f72886068725d6fba66f11b013532dc21259343/pydantic_core-2.41.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:80745b9770b4a38c25015b517451c817799bfb9d6499b0d13d8227ec941cb513", size = 2312267, upload-time = "2025-10-06T21:10:45.34Z" }, + { url = "https://files.pythonhosted.org/packages/35/2f/1c2e71d2a052f9bb2f2df5a6a05464a0eb800f9e8d9dd800202fe31219e1/pydantic_core-2.41.1-cp312-cp312-win32.whl", hash = "sha256:83b64d70520e7890453f1aa21d66fda44e7b35f1cfea95adf7b4289a51e2b479", size = 1990927, upload-time = "2025-10-06T21:10:46.738Z" }, + { url = "https://files.pythonhosted.org/packages/b1/78/562998301ff2588b9c6dcc5cb21f52fa919d6e1decc75a35055feb973594/pydantic_core-2.41.1-cp312-cp312-win_amd64.whl", hash = "sha256:377defd66ee2003748ee93c52bcef2d14fde48fe28a0b156f88c3dbf9bc49a50", size = 2034703, upload-time = "2025-10-06T21:10:48.524Z" }, + { url = "https://files.pythonhosted.org/packages/b2/53/d95699ce5a5cdb44bb470bd818b848b9beadf51459fd4ea06667e8ede862/pydantic_core-2.41.1-cp312-cp312-win_arm64.whl", hash = "sha256:c95caff279d49c1d6cdfe2996e6c2ad712571d3b9caaa209a404426c326c4bde", size = 1972719, upload-time = "2025-10-06T21:10:50.256Z" }, + { url = "https://files.pythonhosted.org/packages/27/8a/6d54198536a90a37807d31a156642aae7a8e1263ed9fe6fc6245defe9332/pydantic_core-2.41.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:70e790fce5f05204ef4403159857bfcd587779da78627b0babb3654f75361ebf", size = 2105825, upload-time = "2025-10-06T21:10:51.719Z" }, + { url = "https://files.pythonhosted.org/packages/4f/2e/4784fd7b22ac9c8439db25bf98ffed6853d01e7e560a346e8af821776ccc/pydantic_core-2.41.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9cebf1ca35f10930612d60bd0f78adfacee824c30a880e3534ba02c207cceceb", size = 1910126, upload-time = "2025-10-06T21:10:53.145Z" }, + { url = "https://files.pythonhosted.org/packages/f3/92/31eb0748059ba5bd0aa708fb4bab9fcb211461ddcf9e90702a6542f22d0d/pydantic_core-2.41.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:170406a37a5bc82c22c3274616bf6f17cc7df9c4a0a0a50449e559cb755db669", size = 1961472, upload-time = "2025-10-06T21:10:55.754Z" }, + { url = "https://files.pythonhosted.org/packages/ab/91/946527792275b5c4c7dde4cfa3e81241bf6900e9fee74fb1ba43e0c0f1ab/pydantic_core-2.41.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12d4257fc9187a0ccd41b8b327d6a4e57281ab75e11dda66a9148ef2e1fb712f", size = 2063230, upload-time = "2025-10-06T21:10:57.179Z" }, + { url = "https://files.pythonhosted.org/packages/31/5d/a35c5d7b414e5c0749f1d9f0d159ee2ef4bab313f499692896b918014ee3/pydantic_core-2.41.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a75a33b4db105dd1c8d57839e17ee12db8d5ad18209e792fa325dbb4baeb00f4", size = 2229469, upload-time = "2025-10-06T21:10:59.409Z" }, + { url = "https://files.pythonhosted.org/packages/21/4d/8713737c689afa57ecfefe38db78259d4484c97aa494979e6a9d19662584/pydantic_core-2.41.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08a589f850803a74e0fcb16a72081cafb0d72a3cdda500106942b07e76b7bf62", size = 2347986, upload-time = "2025-10-06T21:11:00.847Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ec/929f9a3a5ed5cda767081494bacd32f783e707a690ce6eeb5e0730ec4986/pydantic_core-2.41.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a97939d6ea44763c456bd8a617ceada2c9b96bb5b8ab3dfa0d0827df7619014", size = 2072216, upload-time = "2025-10-06T21:11:02.43Z" }, + { url = "https://files.pythonhosted.org/packages/26/55/a33f459d4f9cc8786d9db42795dbecc84fa724b290d7d71ddc3d7155d46a/pydantic_core-2.41.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae423c65c556f09569524b80ffd11babff61f33055ef9773d7c9fabc11ed8d", size = 2193047, upload-time = "2025-10-06T21:11:03.787Z" }, + { url = "https://files.pythonhosted.org/packages/77/af/d5c6959f8b089f2185760a2779079e3c2c411bfc70ea6111f58367851629/pydantic_core-2.41.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:4dc703015fbf8764d6a8001c327a87f1823b7328d40b47ce6000c65918ad2b4f", size = 2140613, upload-time = "2025-10-06T21:11:05.607Z" }, + { url = "https://files.pythonhosted.org/packages/58/e5/2c19bd2a14bffe7fabcf00efbfbd3ac430aaec5271b504a938ff019ac7be/pydantic_core-2.41.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:968e4ffdfd35698a5fe659e5e44c508b53664870a8e61c8f9d24d3d145d30257", size = 2327641, upload-time = "2025-10-06T21:11:07.143Z" }, + { url = "https://files.pythonhosted.org/packages/93/ef/e0870ccda798c54e6b100aff3c4d49df5458fd64217e860cb9c3b0a403f4/pydantic_core-2.41.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:fff2b76c8e172d34771cd4d4f0ade08072385310f214f823b5a6ad4006890d32", size = 2318229, upload-time = "2025-10-06T21:11:08.73Z" }, + { url = "https://files.pythonhosted.org/packages/b1/4b/c3b991d95f5deb24d0bd52e47bcf716098fa1afe0ce2d4bd3125b38566ba/pydantic_core-2.41.1-cp313-cp313-win32.whl", hash = "sha256:a38a5263185407ceb599f2f035faf4589d57e73c7146d64f10577f6449e8171d", size = 1997911, upload-time = "2025-10-06T21:11:10.329Z" }, + { url = "https://files.pythonhosted.org/packages/a7/ce/5c316fd62e01f8d6be1b7ee6b54273214e871772997dc2c95e204997a055/pydantic_core-2.41.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42ae7fd6760782c975897e1fdc810f483b021b32245b0105d40f6e7a3803e4b", size = 2034301, upload-time = "2025-10-06T21:11:12.113Z" }, + { url = "https://files.pythonhosted.org/packages/29/41/902640cfd6a6523194123e2c3373c60f19006447f2fb06f76de4e8466c5b/pydantic_core-2.41.1-cp313-cp313-win_arm64.whl", hash = "sha256:ad4111acc63b7384e205c27a2f15e23ac0ee21a9d77ad6f2e9cb516ec90965fb", size = 1977238, upload-time = "2025-10-06T21:11:14.1Z" }, + { url = "https://files.pythonhosted.org/packages/04/04/28b040e88c1b89d851278478842f0bdf39c7a05da9e850333c6c8cbe7dfa/pydantic_core-2.41.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:440d0df7415b50084a4ba9d870480c16c5f67c0d1d4d5119e3f70925533a0edc", size = 1875626, upload-time = "2025-10-06T21:11:15.69Z" }, + { url = "https://files.pythonhosted.org/packages/d6/58/b41dd3087505220bb58bc81be8c3e8cbc037f5710cd3c838f44f90bdd704/pydantic_core-2.41.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71eaa38d342099405dae6484216dcf1e8e4b0bebd9b44a4e08c9b43db6a2ab67", size = 2045708, upload-time = "2025-10-06T21:11:17.258Z" }, + { url = "https://files.pythonhosted.org/packages/d7/b8/760f23754e40bf6c65b94a69b22c394c24058a0ef7e2aa471d2e39219c1a/pydantic_core-2.41.1-cp313-cp313t-win_amd64.whl", hash = "sha256:555ecf7e50f1161d3f693bc49f23c82cf6cdeafc71fa37a06120772a09a38795", size = 1997171, upload-time = "2025-10-06T21:11:18.822Z" }, + { url = "https://files.pythonhosted.org/packages/41/12/cec246429ddfa2778d2d6301eca5362194dc8749ecb19e621f2f65b5090f/pydantic_core-2.41.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:05226894a26f6f27e1deb735d7308f74ef5fa3a6de3e0135bb66cdcaee88f64b", size = 2107836, upload-time = "2025-10-06T21:11:20.432Z" }, + { url = "https://files.pythonhosted.org/packages/20/39/baba47f8d8b87081302498e610aefc37142ce6a1cc98b2ab6b931a162562/pydantic_core-2.41.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:85ff7911c6c3e2fd8d3779c50925f6406d770ea58ea6dde9c230d35b52b16b4a", size = 1904449, upload-time = "2025-10-06T21:11:22.185Z" }, + { url = "https://files.pythonhosted.org/packages/50/32/9a3d87cae2c75a5178334b10358d631bd094b916a00a5993382222dbfd92/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47f1f642a205687d59b52dc1a9a607f45e588f5a2e9eeae05edd80c7a8c47674", size = 1961750, upload-time = "2025-10-06T21:11:24.348Z" }, + { url = "https://files.pythonhosted.org/packages/27/42/a96c9d793a04cf2a9773bff98003bb154087b94f5530a2ce6063ecfec583/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df11c24e138876ace5ec6043e5cae925e34cf38af1a1b3d63589e8f7b5f5cdc4", size = 2063305, upload-time = "2025-10-06T21:11:26.556Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8d/028c4b7d157a005b1f52c086e2d4b0067886b213c86220c1153398dbdf8f/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f0bf7f5c8f7bf345c527e8a0d72d6b26eda99c1227b0c34e7e59e181260de31", size = 2228959, upload-time = "2025-10-06T21:11:28.426Z" }, + { url = "https://files.pythonhosted.org/packages/08/f7/ee64cda8fcc9ca3f4716e6357144f9ee71166775df582a1b6b738bf6da57/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82b887a711d341c2c47352375d73b029418f55b20bd7815446d175a70effa706", size = 2345421, upload-time = "2025-10-06T21:11:30.226Z" }, + { url = "https://files.pythonhosted.org/packages/13/c0/e8ec05f0f5ee7a3656973ad9cd3bc73204af99f6512c1a4562f6fb4b3f7d/pydantic_core-2.41.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5f1d5d6bbba484bdf220c72d8ecd0be460f4bd4c5e534a541bb2cd57589fb8b", size = 2065288, upload-time = "2025-10-06T21:11:32.019Z" }, + { url = "https://files.pythonhosted.org/packages/0a/25/d77a73ff24e2e4fcea64472f5e39b0402d836da9b08b5361a734d0153023/pydantic_core-2.41.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bf1917385ebe0f968dc5c6ab1375886d56992b93ddfe6bf52bff575d03662be", size = 2189759, upload-time = "2025-10-06T21:11:33.753Z" }, + { url = "https://files.pythonhosted.org/packages/66/45/4a4ebaaae12a740552278d06fe71418c0f2869537a369a89c0e6723b341d/pydantic_core-2.41.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:4f94f3ab188f44b9a73f7295663f3ecb8f2e2dd03a69c8f2ead50d37785ecb04", size = 2140747, upload-time = "2025-10-06T21:11:35.781Z" }, + { url = "https://files.pythonhosted.org/packages/da/6d/b727ce1022f143194a36593243ff244ed5a1eb3c9122296bf7e716aa37ba/pydantic_core-2.41.1-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:3925446673641d37c30bd84a9d597e49f72eacee8b43322c8999fa17d5ae5bc4", size = 2327416, upload-time = "2025-10-06T21:11:37.75Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8c/02df9d8506c427787059f87c6c7253435c6895e12472a652d9616ee0fc95/pydantic_core-2.41.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:49bd51cc27adb980c7b97357ae036ce9b3c4d0bb406e84fbe16fb2d368b602a8", size = 2318138, upload-time = "2025-10-06T21:11:39.463Z" }, + { url = "https://files.pythonhosted.org/packages/98/67/0cf429a7d6802536941f430e6e3243f6d4b68f41eeea4b242372f1901794/pydantic_core-2.41.1-cp314-cp314-win32.whl", hash = "sha256:a31ca0cd0e4d12ea0df0077df2d487fc3eb9d7f96bbb13c3c5b88dcc21d05159", size = 1998429, upload-time = "2025-10-06T21:11:41.989Z" }, + { url = "https://files.pythonhosted.org/packages/38/60/742fef93de5d085022d2302a6317a2b34dbfe15258e9396a535c8a100ae7/pydantic_core-2.41.1-cp314-cp314-win_amd64.whl", hash = "sha256:1b5c4374a152e10a22175d7790e644fbd8ff58418890e07e2073ff9d4414efae", size = 2028870, upload-time = "2025-10-06T21:11:43.66Z" }, + { url = "https://files.pythonhosted.org/packages/31/38/cdd8ccb8555ef7720bd7715899bd6cfbe3c29198332710e1b61b8f5dd8b8/pydantic_core-2.41.1-cp314-cp314-win_arm64.whl", hash = "sha256:4fee76d757639b493eb600fba668f1e17475af34c17dd61db7a47e824d464ca9", size = 1974275, upload-time = "2025-10-06T21:11:45.476Z" }, + { url = "https://files.pythonhosted.org/packages/e7/7e/8ac10ccb047dc0221aa2530ec3c7c05ab4656d4d4bd984ee85da7f3d5525/pydantic_core-2.41.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f9b9c968cfe5cd576fdd7361f47f27adeb120517e637d1b189eea1c3ece573f4", size = 1875124, upload-time = "2025-10-06T21:11:47.591Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e4/7d9791efeb9c7d97e7268f8d20e0da24d03438a7fa7163ab58f1073ba968/pydantic_core-2.41.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ebc7ab67b856384aba09ed74e3e977dded40e693de18a4f197c67d0d4e6d8e", size = 2043075, upload-time = "2025-10-06T21:11:49.542Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c3/3f6e6b2342ac11ac8cd5cb56e24c7b14afa27c010e82a765ffa5f771884a/pydantic_core-2.41.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8ae0dc57b62a762985bc7fbf636be3412394acc0ddb4ade07fe104230f1b9762", size = 1995341, upload-time = "2025-10-06T21:11:51.497Z" }, + { url = "https://files.pythonhosted.org/packages/2b/3e/a51c5f5d37b9288ba30683d6e96f10fa8f1defad1623ff09f1020973b577/pydantic_core-2.41.1-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:b04fa9ed049461a7398138c604b00550bc89e3e1151d84b81ad6dc93e39c4c06", size = 2115344, upload-time = "2025-10-07T10:50:02.466Z" }, + { url = "https://files.pythonhosted.org/packages/5a/bd/389504c9e0600ef4502cd5238396b527afe6ef8981a6a15cd1814fc7b434/pydantic_core-2.41.1-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:b3b7d9cfbfdc43c80a16638c6dc2768e3956e73031fca64e8e1a3ae744d1faeb", size = 1927994, upload-time = "2025-10-07T10:50:04.379Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9c/5111c6b128861cb792a4c082677e90dac4f2e090bb2e2fe06aa5b2d39027/pydantic_core-2.41.1-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eec83fc6abef04c7f9bec616e2d76ee9a6a4ae2a359b10c21d0f680e24a247ca", size = 1959394, upload-time = "2025-10-07T10:50:06.335Z" }, + { url = "https://files.pythonhosted.org/packages/14/3f/cfec8b9a0c48ce5d64409ec5e1903cb0b7363da38f14b41de2fcb3712700/pydantic_core-2.41.1-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6771a2d9f83c4038dfad5970a3eef215940682b2175e32bcc817bdc639019b28", size = 2147365, upload-time = "2025-10-07T10:50:07.978Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/c5/dbbc27b814c71676593d1c3f718e6cd7d4f00652cefa24b75f7aa3efb25e/pydantic_settings-2.11.0.tar.gz", hash = "sha256:d0e87a1c7d33593beb7194adb8470fc426e95ba02af83a0f23474a04c9a08180", size = 188394, upload-time = "2025-09-24T14:19:11.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/d6/887a1ff844e64aa823fb4905978d882a633cfe295c32eacad582b78a7d8b/pydantic_settings-2.11.0-py3-none-any.whl", hash = "sha256:fe2cea3413b9530d10f3a5875adffb17ada5c1e1bab0b2885546d7310415207c", size = 48608, upload-time = "2025-09-24T14:19:10.015Z" }, +] + +[[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 = "pypdf" +version = "6.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/ba/f82d1cb35b04041b5f796d4eedbaecafcbf99e83b7a2542b44a936959dd7/pypdf-6.12.0.tar.gz", hash = "sha256:061f135db8934503ed301c2d4cfaccb12f0a2ef1db11c5d0768a72a5ab4097d8", size = 6466074, upload-time = "2026-05-21T09:21:42.621Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/fa/3597fb3fb28f40bf8291fdddbc4dcd51ce52fccaf1cbfca10ee9db09c69a/pypdf-6.12.0-py3-none-any.whl", hash = "sha256:a8e104ab950e655d0bcf5fa5e71317c06474bc707987335da44a210f73a8883b", size = 343457, upload-time = "2026-05-21T09:21:40.852Z" }, +] + +[[package]] +name = "pypdf2" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/bb/18dc3062d37db6c491392007dfd1a7f524bb95886eb956569ac38a23a784/PyPDF2-3.0.1.tar.gz", hash = "sha256:a74408f69ba6271f71b9352ef4ed03dc53a31aa404d29b5d31f53bfecfee1440", size = 227419, upload-time = "2022-12-31T10:36:13.13Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/5e/c86a5643653825d3c913719e788e41386bee415c2b87b4f955432f2de6b2/pypdf2-3.0.1-py3-none-any.whl", hash = "sha256:d16e4205cfee272fbdc0568b68d82be796540b1537508cef59388f839c191928", size = 232572, upload-time = "2022-12-31T10:36:10.327Z" }, +] + +[[package]] +name = "pypika" +version = "0.48.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/2c/94ed7b91db81d61d7096ac8f2d325ec562fc75e35f3baea8749c85b28784/PyPika-0.48.9.tar.gz", hash = "sha256:838836a61747e7c8380cd1b7ff638694b7a7335345d0f559b04b2cd832ad5378", size = 67259, upload-time = "2022-03-15T11:22:57.066Z" } + +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228, upload-time = "2024-09-29T09:24:13.293Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" }, +] + +[[package]] +name = "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 = "pytest" +version = "8.4.2" +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/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 = "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 = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-docx" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lxml" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" }, +] + +[[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-jose" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ecdsa" }, + { name = "pyasn1" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/77/3a1c9039db7124eb039772b935f2244fbb73fc8ee65b9acf2375da1c07bf/python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b", size = 92726, upload-time = "2025-05-28T17:31:54.288Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/c3/0bd11992072e6a1c513b16500a5d07f91a24017c5909b02c72c62d7ad024/python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771", size = 34624, upload-time = "2025-05-28T17:31:52.802Z" }, +] + +[package.optional-dependencies] +cryptography = [ + { name = "cryptography" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, +] + +[[package]] +name = "pytokens" +version = "0.1.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/5f/e959a442435e24f6fb5a01aec6c657079ceaca1b3baf18561c3728d681da/pytokens-0.1.10.tar.gz", hash = "sha256:c9a4bfa0be1d26aebce03e6884ba454e842f186a59ea43a6d3b25af58223c044", size = 12171, upload-time = "2025-02-19T14:51:22.001Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/e5/63bed382f6a7a5ba70e7e132b8b7b8abbcf4888ffa6be4877698dcfbed7d/pytokens-0.1.10-py3-none-any.whl", hash = "sha256:db7b72284e480e69fb085d9f251f66b3d2df8b7166059261258ff35f50fb711b", size = 12046, upload-time = "2025-02-19T14:51:18.694Z" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + +[[package]] +name = "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/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 = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "regex" +version = "2025.9.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/d3/eaa0d28aba6ad1827ad1e716d9a93e1ba963ada61887498297d3da715133/regex-2025.9.18.tar.gz", hash = "sha256:c5ba23274c61c6fef447ba6a39333297d0c247f53059dba0bca415cac511edc4", size = 400917, upload-time = "2025-09-19T00:38:35.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/99/05859d87a66ae7098222d65748f11ef7f2dff51bfd7482a4e2256c90d72b/regex-2025.9.18-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:436e1b31d7efd4dcd52091d076482031c611dde58bf9c46ca6d0a26e33053a7e", size = 486335, upload-time = "2025-09-19T00:36:03.661Z" }, + { url = "https://files.pythonhosted.org/packages/97/7e/d43d4e8b978890932cf7b0957fce58c5b08c66f32698f695b0c2c24a48bf/regex-2025.9.18-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c190af81e5576b9c5fdc708f781a52ff20f8b96386c6e2e0557a78402b029f4a", size = 289720, upload-time = "2025-09-19T00:36:05.471Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3b/ff80886089eb5dcf7e0d2040d9aaed539e25a94300403814bb24cc775058/regex-2025.9.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e4121f1ce2b2b5eec4b397cc1b277686e577e658d8f5870b7eb2d726bd2300ab", size = 287257, upload-time = "2025-09-19T00:36:07.072Z" }, + { url = "https://files.pythonhosted.org/packages/ee/66/243edf49dd8720cba8d5245dd4d6adcb03a1defab7238598c0c97cf549b8/regex-2025.9.18-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:300e25dbbf8299d87205e821a201057f2ef9aa3deb29caa01cd2cac669e508d5", size = 797463, upload-time = "2025-09-19T00:36:08.399Z" }, + { url = "https://files.pythonhosted.org/packages/df/71/c9d25a1142c70432e68bb03211d4a82299cd1c1fbc41db9409a394374ef5/regex-2025.9.18-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b47fcf9f5316c0bdaf449e879407e1b9937a23c3b369135ca94ebc8d74b1742", size = 862670, upload-time = "2025-09-19T00:36:10.101Z" }, + { url = "https://files.pythonhosted.org/packages/f8/8f/329b1efc3a64375a294e3a92d43372bf1a351aa418e83c21f2f01cf6ec41/regex-2025.9.18-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:57a161bd3acaa4b513220b49949b07e252165e6b6dc910ee7617a37ff4f5b425", size = 910881, upload-time = "2025-09-19T00:36:12.223Z" }, + { url = "https://files.pythonhosted.org/packages/35/9e/a91b50332a9750519320ed30ec378b74c996f6befe282cfa6bb6cea7e9fd/regex-2025.9.18-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f130c3a7845ba42de42f380fff3c8aebe89a810747d91bcf56d40a069f15352", size = 802011, upload-time = "2025-09-19T00:36:13.901Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1d/6be3b8d7856b6e0d7ee7f942f437d0a76e0d5622983abbb6d21e21ab9a17/regex-2025.9.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f96fa342b6f54dcba928dd452e8d8cb9f0d63e711d1721cd765bb9f73bb048d", size = 786668, upload-time = "2025-09-19T00:36:15.391Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ce/4a60e53df58bd157c5156a1736d3636f9910bdcc271d067b32b7fcd0c3a8/regex-2025.9.18-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0f0d676522d68c207828dcd01fb6f214f63f238c283d9f01d85fc664c7c85b56", size = 856578, upload-time = "2025-09-19T00:36:16.845Z" }, + { url = "https://files.pythonhosted.org/packages/86/e8/162c91bfe7217253afccde112868afb239f94703de6580fb235058d506a6/regex-2025.9.18-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:40532bff8a1a0621e7903ae57fce88feb2e8a9a9116d341701302c9302aef06e", size = 849017, upload-time = "2025-09-19T00:36:18.597Z" }, + { url = "https://files.pythonhosted.org/packages/35/34/42b165bc45289646ea0959a1bc7531733e90b47c56a72067adfe6b3251f6/regex-2025.9.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:039f11b618ce8d71a1c364fdee37da1012f5a3e79b1b2819a9f389cd82fd6282", size = 788150, upload-time = "2025-09-19T00:36:20.464Z" }, + { url = "https://files.pythonhosted.org/packages/79/5d/cdd13b1f3c53afa7191593a7ad2ee24092a5a46417725ffff7f64be8342d/regex-2025.9.18-cp312-cp312-win32.whl", hash = "sha256:e1dd06f981eb226edf87c55d523131ade7285137fbde837c34dc9d1bf309f459", size = 264536, upload-time = "2025-09-19T00:36:21.922Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f5/4a7770c9a522e7d2dc1fa3ffc83ab2ab33b0b22b447e62cffef186805302/regex-2025.9.18-cp312-cp312-win_amd64.whl", hash = "sha256:3d86b5247bf25fa3715e385aa9ff272c307e0636ce0c9595f64568b41f0a9c77", size = 275501, upload-time = "2025-09-19T00:36:23.4Z" }, + { url = "https://files.pythonhosted.org/packages/df/05/9ce3e110e70d225ecbed455b966003a3afda5e58e8aec2964042363a18f4/regex-2025.9.18-cp312-cp312-win_arm64.whl", hash = "sha256:032720248cbeeae6444c269b78cb15664458b7bb9ed02401d3da59fe4d68c3a5", size = 268601, upload-time = "2025-09-19T00:36:25.092Z" }, + { url = "https://files.pythonhosted.org/packages/d2/c7/5c48206a60ce33711cf7dcaeaed10dd737733a3569dc7e1dce324dd48f30/regex-2025.9.18-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2a40f929cd907c7e8ac7566ac76225a77701a6221bca937bdb70d56cb61f57b2", size = 485955, upload-time = "2025-09-19T00:36:26.822Z" }, + { url = "https://files.pythonhosted.org/packages/e9/be/74fc6bb19a3c491ec1ace943e622b5a8539068771e8705e469b2da2306a7/regex-2025.9.18-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c90471671c2cdf914e58b6af62420ea9ecd06d1554d7474d50133ff26ae88feb", size = 289583, upload-time = "2025-09-19T00:36:28.577Z" }, + { url = "https://files.pythonhosted.org/packages/25/c4/9ceaa433cb5dc515765560f22a19578b95b92ff12526e5a259321c4fc1a0/regex-2025.9.18-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a351aff9e07a2dabb5022ead6380cff17a4f10e4feb15f9100ee56c4d6d06af", size = 287000, upload-time = "2025-09-19T00:36:30.161Z" }, + { url = "https://files.pythonhosted.org/packages/7d/e6/68bc9393cb4dc68018456568c048ac035854b042bc7c33cb9b99b0680afa/regex-2025.9.18-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc4b8e9d16e20ddfe16430c23468a8707ccad3365b06d4536142e71823f3ca29", size = 797535, upload-time = "2025-09-19T00:36:31.876Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1c/ebae9032d34b78ecfe9bd4b5e6575b55351dc8513485bb92326613732b8c/regex-2025.9.18-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b8cdbddf2db1c5e80338ba2daa3cfa3dec73a46fff2a7dda087c8efbf12d62f", size = 862603, upload-time = "2025-09-19T00:36:33.344Z" }, + { url = "https://files.pythonhosted.org/packages/3b/74/12332c54b3882557a4bcd2b99f8be581f5c6a43cf1660a85b460dd8ff468/regex-2025.9.18-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a276937d9d75085b2c91fb48244349c6954f05ee97bba0963ce24a9d915b8b68", size = 910829, upload-time = "2025-09-19T00:36:34.826Z" }, + { url = "https://files.pythonhosted.org/packages/86/70/ba42d5ed606ee275f2465bfc0e2208755b06cdabd0f4c7c4b614d51b57ab/regex-2025.9.18-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92a8e375ccdc1256401c90e9dc02b8642894443d549ff5e25e36d7cf8a80c783", size = 802059, upload-time = "2025-09-19T00:36:36.664Z" }, + { url = "https://files.pythonhosted.org/packages/da/c5/fcb017e56396a7f2f8357412638d7e2963440b131a3ca549be25774b3641/regex-2025.9.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0dc6893b1f502d73037cf807a321cdc9be29ef3d6219f7970f842475873712ac", size = 786781, upload-time = "2025-09-19T00:36:38.168Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ee/21c4278b973f630adfb3bcb23d09d83625f3ab1ca6e40ebdffe69901c7a1/regex-2025.9.18-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a61e85bfc63d232ac14b015af1261f826260c8deb19401c0597dbb87a864361e", size = 856578, upload-time = "2025-09-19T00:36:40.129Z" }, + { url = "https://files.pythonhosted.org/packages/87/0b/de51550dc7274324435c8f1539373ac63019b0525ad720132866fff4a16a/regex-2025.9.18-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1ef86a9ebc53f379d921fb9a7e42b92059ad3ee800fcd9e0fe6181090e9f6c23", size = 849119, upload-time = "2025-09-19T00:36:41.651Z" }, + { url = "https://files.pythonhosted.org/packages/60/52/383d3044fc5154d9ffe4321696ee5b2ee4833a28c29b137c22c33f41885b/regex-2025.9.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d3bc882119764ba3a119fbf2bd4f1b47bc56c1da5d42df4ed54ae1e8e66fdf8f", size = 788219, upload-time = "2025-09-19T00:36:43.575Z" }, + { url = "https://files.pythonhosted.org/packages/20/bd/2614fc302671b7359972ea212f0e3a92df4414aaeacab054a8ce80a86073/regex-2025.9.18-cp313-cp313-win32.whl", hash = "sha256:3810a65675845c3bdfa58c3c7d88624356dd6ee2fc186628295e0969005f928d", size = 264517, upload-time = "2025-09-19T00:36:45.503Z" }, + { url = "https://files.pythonhosted.org/packages/07/0f/ab5c1581e6563a7bffdc1974fb2d25f05689b88e2d416525271f232b1946/regex-2025.9.18-cp313-cp313-win_amd64.whl", hash = "sha256:16eaf74b3c4180ede88f620f299e474913ab6924d5c4b89b3833bc2345d83b3d", size = 275481, upload-time = "2025-09-19T00:36:46.965Z" }, + { url = "https://files.pythonhosted.org/packages/49/22/ee47672bc7958f8c5667a587c2600a4fba8b6bab6e86bd6d3e2b5f7cac42/regex-2025.9.18-cp313-cp313-win_arm64.whl", hash = "sha256:4dc98ba7dd66bd1261927a9f49bd5ee2bcb3660f7962f1ec02617280fc00f5eb", size = 268598, upload-time = "2025-09-19T00:36:48.314Z" }, + { url = "https://files.pythonhosted.org/packages/e8/83/6887e16a187c6226cb85d8301e47d3b73ecc4505a3a13d8da2096b44fd76/regex-2025.9.18-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:fe5d50572bc885a0a799410a717c42b1a6b50e2f45872e2b40f4f288f9bce8a2", size = 489765, upload-time = "2025-09-19T00:36:49.996Z" }, + { url = "https://files.pythonhosted.org/packages/51/c5/e2f7325301ea2916ff301c8d963ba66b1b2c1b06694191df80a9c4fea5d0/regex-2025.9.18-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b9d9a2d6cda6621551ca8cf7a06f103adf72831153f3c0d982386110870c4d3", size = 291228, upload-time = "2025-09-19T00:36:51.654Z" }, + { url = "https://files.pythonhosted.org/packages/91/60/7d229d2bc6961289e864a3a3cfebf7d0d250e2e65323a8952cbb7e22d824/regex-2025.9.18-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:13202e4c4ac0ef9a317fff817674b293c8f7e8c68d3190377d8d8b749f566e12", size = 289270, upload-time = "2025-09-19T00:36:53.118Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d7/b4f06868ee2958ff6430df89857fbf3d43014bbf35538b6ec96c2704e15d/regex-2025.9.18-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:874ff523b0fecffb090f80ae53dc93538f8db954c8bb5505f05b7787ab3402a0", size = 806326, upload-time = "2025-09-19T00:36:54.631Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e4/bca99034a8f1b9b62ccf337402a8e5b959dd5ba0e5e5b2ead70273df3277/regex-2025.9.18-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d13ab0490128f2bb45d596f754148cd750411afc97e813e4b3a61cf278a23bb6", size = 871556, upload-time = "2025-09-19T00:36:56.208Z" }, + { url = "https://files.pythonhosted.org/packages/6d/df/e06ffaf078a162f6dd6b101a5ea9b44696dca860a48136b3ae4a9caf25e2/regex-2025.9.18-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:05440bc172bc4b4b37fb9667e796597419404dbba62e171e1f826d7d2a9ebcef", size = 913817, upload-time = "2025-09-19T00:36:57.807Z" }, + { url = "https://files.pythonhosted.org/packages/9e/05/25b05480b63292fd8e84800b1648e160ca778127b8d2367a0a258fa2e225/regex-2025.9.18-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5514b8e4031fdfaa3d27e92c75719cbe7f379e28cacd939807289bce76d0e35a", size = 811055, upload-time = "2025-09-19T00:36:59.762Z" }, + { url = "https://files.pythonhosted.org/packages/70/97/7bc7574655eb651ba3a916ed4b1be6798ae97af30104f655d8efd0cab24b/regex-2025.9.18-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:65d3c38c39efce73e0d9dc019697b39903ba25b1ad45ebbd730d2cf32741f40d", size = 794534, upload-time = "2025-09-19T00:37:01.405Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c2/d5da49166a52dda879855ecdba0117f073583db2b39bb47ce9a3378a8e9e/regex-2025.9.18-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ae77e447ebc144d5a26d50055c6ddba1d6ad4a865a560ec7200b8b06bc529368", size = 866684, upload-time = "2025-09-19T00:37:03.441Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2d/0a5c4e6ec417de56b89ff4418ecc72f7e3feca806824c75ad0bbdae0516b/regex-2025.9.18-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e3ef8cf53dc8df49d7e28a356cf824e3623764e9833348b655cfed4524ab8a90", size = 853282, upload-time = "2025-09-19T00:37:04.985Z" }, + { url = "https://files.pythonhosted.org/packages/f4/8e/d656af63e31a86572ec829665d6fa06eae7e144771e0330650a8bb865635/regex-2025.9.18-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9feb29817df349c976da9a0debf775c5c33fc1c8ad7b9f025825da99374770b7", size = 797830, upload-time = "2025-09-19T00:37:06.697Z" }, + { url = "https://files.pythonhosted.org/packages/db/ce/06edc89df8f7b83ffd321b6071be4c54dc7332c0f77860edc40ce57d757b/regex-2025.9.18-cp313-cp313t-win32.whl", hash = "sha256:168be0d2f9b9d13076940b1ed774f98595b4e3c7fc54584bba81b3cc4181742e", size = 267281, upload-time = "2025-09-19T00:37:08.568Z" }, + { url = "https://files.pythonhosted.org/packages/83/9a/2b5d9c8b307a451fd17068719d971d3634ca29864b89ed5c18e499446d4a/regex-2025.9.18-cp313-cp313t-win_amd64.whl", hash = "sha256:d59ecf3bb549e491c8104fea7313f3563c7b048e01287db0a90485734a70a730", size = 278724, upload-time = "2025-09-19T00:37:10.023Z" }, + { url = "https://files.pythonhosted.org/packages/3d/70/177d31e8089a278a764f8ec9a3faac8d14a312d622a47385d4b43905806f/regex-2025.9.18-cp313-cp313t-win_arm64.whl", hash = "sha256:dbef80defe9fb21310948a2595420b36c6d641d9bea4c991175829b2cc4bc06a", size = 269771, upload-time = "2025-09-19T00:37:13.041Z" }, + { url = "https://files.pythonhosted.org/packages/44/b7/3b4663aa3b4af16819f2ab6a78c4111c7e9b066725d8107753c2257448a5/regex-2025.9.18-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c6db75b51acf277997f3adcd0ad89045d856190d13359f15ab5dda21581d9129", size = 486130, upload-time = "2025-09-19T00:37:14.527Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/4533f5d7ac9c6a02a4725fe8883de2aebc713e67e842c04cf02626afb747/regex-2025.9.18-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8f9698b6f6895d6db810e0bda5364f9ceb9e5b11328700a90cae573574f61eea", size = 289539, upload-time = "2025-09-19T00:37:16.356Z" }, + { url = "https://files.pythonhosted.org/packages/b8/8d/5ab6797c2750985f79e9995fad3254caa4520846580f266ae3b56d1cae58/regex-2025.9.18-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29cd86aa7cb13a37d0f0d7c21d8d949fe402ffa0ea697e635afedd97ab4b69f1", size = 287233, upload-time = "2025-09-19T00:37:18.025Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/95afcb02ba8d3a64e6ffeb801718ce73471ad6440c55d993f65a4a5e7a92/regex-2025.9.18-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c9f285a071ee55cd9583ba24dde006e53e17780bb309baa8e4289cd472bcc47", size = 797876, upload-time = "2025-09-19T00:37:19.609Z" }, + { url = "https://files.pythonhosted.org/packages/c8/fb/720b1f49cec1f3b5a9fea5b34cd22b88b5ebccc8c1b5de9cc6f65eed165a/regex-2025.9.18-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5adf266f730431e3be9021d3e5b8d5ee65e563fec2883ea8093944d21863b379", size = 863385, upload-time = "2025-09-19T00:37:21.65Z" }, + { url = "https://files.pythonhosted.org/packages/a9/ca/e0d07ecf701e1616f015a720dc13b84c582024cbfbb3fc5394ae204adbd7/regex-2025.9.18-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1137cabc0f38807de79e28d3f6e3e3f2cc8cfb26bead754d02e6d1de5f679203", size = 910220, upload-time = "2025-09-19T00:37:23.723Z" }, + { url = "https://files.pythonhosted.org/packages/b6/45/bba86413b910b708eca705a5af62163d5d396d5f647ed9485580c7025209/regex-2025.9.18-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7cc9e5525cada99699ca9223cce2d52e88c52a3d2a0e842bd53de5497c604164", size = 801827, upload-time = "2025-09-19T00:37:25.684Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a6/740fbd9fcac31a1305a8eed30b44bf0f7f1e042342be0a4722c0365ecfca/regex-2025.9.18-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bbb9246568f72dce29bcd433517c2be22c7791784b223a810225af3b50d1aafb", size = 786843, upload-time = "2025-09-19T00:37:27.62Z" }, + { url = "https://files.pythonhosted.org/packages/80/a7/0579e8560682645906da640c9055506465d809cb0f5415d9976f417209a6/regex-2025.9.18-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6a52219a93dd3d92c675383efff6ae18c982e2d7651c792b1e6d121055808743", size = 857430, upload-time = "2025-09-19T00:37:29.362Z" }, + { url = "https://files.pythonhosted.org/packages/8d/9b/4dc96b6c17b38900cc9fee254fc9271d0dde044e82c78c0811b58754fde5/regex-2025.9.18-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:ae9b3840c5bd456780e3ddf2f737ab55a79b790f6409182012718a35c6d43282", size = 848612, upload-time = "2025-09-19T00:37:31.42Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6a/6f659f99bebb1775e5ac81a3fb837b85897c1a4ef5acffd0ff8ffe7e67fb/regex-2025.9.18-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d488c236ac497c46a5ac2005a952c1a0e22a07be9f10c3e735bc7d1209a34773", size = 787967, upload-time = "2025-09-19T00:37:34.019Z" }, + { url = "https://files.pythonhosted.org/packages/61/35/9e35665f097c07cf384a6b90a1ac11b0b1693084a0b7a675b06f760496c6/regex-2025.9.18-cp314-cp314-win32.whl", hash = "sha256:0c3506682ea19beefe627a38872d8da65cc01ffa25ed3f2e422dffa1474f0788", size = 269847, upload-time = "2025-09-19T00:37:35.759Z" }, + { url = "https://files.pythonhosted.org/packages/af/64/27594dbe0f1590b82de2821ebfe9a359b44dcb9b65524876cd12fabc447b/regex-2025.9.18-cp314-cp314-win_amd64.whl", hash = "sha256:57929d0f92bebb2d1a83af372cd0ffba2263f13f376e19b1e4fa32aec4efddc3", size = 278755, upload-time = "2025-09-19T00:37:37.367Z" }, + { url = "https://files.pythonhosted.org/packages/30/a3/0cd8d0d342886bd7d7f252d701b20ae1a3c72dc7f34ef4b2d17790280a09/regex-2025.9.18-cp314-cp314-win_arm64.whl", hash = "sha256:6a4b44df31d34fa51aa5c995d3aa3c999cec4d69b9bd414a8be51984d859f06d", size = 271873, upload-time = "2025-09-19T00:37:39.125Z" }, + { url = "https://files.pythonhosted.org/packages/99/cb/8a1ab05ecf404e18b54348e293d9b7a60ec2bd7aa59e637020c5eea852e8/regex-2025.9.18-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b176326bcd544b5e9b17d6943f807697c0cb7351f6cfb45bf5637c95ff7e6306", size = 489773, upload-time = "2025-09-19T00:37:40.968Z" }, + { url = "https://files.pythonhosted.org/packages/93/3b/6543c9b7f7e734d2404fa2863d0d710c907bef99d4598760ed4563d634c3/regex-2025.9.18-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0ffd9e230b826b15b369391bec167baed57c7ce39efc35835448618860995946", size = 291221, upload-time = "2025-09-19T00:37:42.901Z" }, + { url = "https://files.pythonhosted.org/packages/cd/91/e9fdee6ad6bf708d98c5d17fded423dcb0661795a49cba1b4ffb8358377a/regex-2025.9.18-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ec46332c41add73f2b57e2f5b642f991f6b15e50e9f86285e08ffe3a512ac39f", size = 289268, upload-time = "2025-09-19T00:37:44.823Z" }, + { url = "https://files.pythonhosted.org/packages/94/a6/bc3e8a918abe4741dadeaeb6c508e3a4ea847ff36030d820d89858f96a6c/regex-2025.9.18-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b80fa342ed1ea095168a3f116637bd1030d39c9ff38dc04e54ef7c521e01fc95", size = 806659, upload-time = "2025-09-19T00:37:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/2b/71/ea62dbeb55d9e6905c7b5a49f75615ea1373afcad95830047e4e310db979/regex-2025.9.18-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4d97071c0ba40f0cf2a93ed76e660654c399a0a04ab7d85472239460f3da84b", size = 871701, upload-time = "2025-09-19T00:37:48.882Z" }, + { url = "https://files.pythonhosted.org/packages/6a/90/fbe9dedb7dad24a3a4399c0bae64bfa932ec8922a0a9acf7bc88db30b161/regex-2025.9.18-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0ac936537ad87cef9e0e66c5144484206c1354224ee811ab1519a32373e411f3", size = 913742, upload-time = "2025-09-19T00:37:51.015Z" }, + { url = "https://files.pythonhosted.org/packages/f0/1c/47e4a8c0e73d41eb9eb9fdeba3b1b810110a5139a2526e82fd29c2d9f867/regex-2025.9.18-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dec57f96d4def58c422d212d414efe28218d58537b5445cf0c33afb1b4768571", size = 811117, upload-time = "2025-09-19T00:37:52.686Z" }, + { url = "https://files.pythonhosted.org/packages/2a/da/435f29fddfd015111523671e36d30af3342e8136a889159b05c1d9110480/regex-2025.9.18-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:48317233294648bf7cd068857f248e3a57222259a5304d32c7552e2284a1b2ad", size = 794647, upload-time = "2025-09-19T00:37:54.626Z" }, + { url = "https://files.pythonhosted.org/packages/23/66/df5e6dcca25c8bc57ce404eebc7342310a0d218db739d7882c9a2b5974a3/regex-2025.9.18-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:274687e62ea3cf54846a9b25fc48a04459de50af30a7bd0b61a9e38015983494", size = 866747, upload-time = "2025-09-19T00:37:56.367Z" }, + { url = "https://files.pythonhosted.org/packages/82/42/94392b39b531f2e469b2daa40acf454863733b674481fda17462a5ffadac/regex-2025.9.18-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a78722c86a3e7e6aadf9579e3b0ad78d955f2d1f1a8ca4f67d7ca258e8719d4b", size = 853434, upload-time = "2025-09-19T00:37:58.39Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f8/dcc64c7f7bbe58842a8f89622b50c58c3598fbbf4aad0a488d6df2c699f1/regex-2025.9.18-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:06104cd203cdef3ade989a1c45b6215bf42f8b9dd705ecc220c173233f7cba41", size = 798024, upload-time = "2025-09-19T00:38:00.397Z" }, + { url = "https://files.pythonhosted.org/packages/20/8d/edf1c5d5aa98f99a692313db813ec487732946784f8f93145e0153d910e5/regex-2025.9.18-cp314-cp314t-win32.whl", hash = "sha256:2e1eddc06eeaffd249c0adb6fafc19e2118e6308c60df9db27919e96b5656096", size = 273029, upload-time = "2025-09-19T00:38:02.383Z" }, + { url = "https://files.pythonhosted.org/packages/a7/24/02d4e4f88466f17b145f7ea2b2c11af3a942db6222429c2c146accf16054/regex-2025.9.18-cp314-cp314t-win_amd64.whl", hash = "sha256:8620d247fb8c0683ade51217b459cb4a1081c0405a3072235ba43a40d355c09a", size = 282680, upload-time = "2025-09-19T00:38:04.102Z" }, + { url = "https://files.pythonhosted.org/packages/1f/a3/c64894858aaaa454caa7cc47e2f225b04d3ed08ad649eacf58d45817fad2/regex-2025.9.18-cp314-cp314t-win_arm64.whl", hash = "sha256:b7531a8ef61de2c647cdf68b3229b071e46ec326b3138b2180acb4275f470b01", size = 273034, upload-time = "2025-09-19T00:38:05.807Z" }, +] + +[[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 = "requests-oauthlib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "oauthlib" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + +[[package]] +name = "rich" +version = "14.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/fe/38de28dee5df58b8198c743fe2bea0c785c6d40941b9950bac4cdb71a014/rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90", size = 361887, upload-time = "2025-08-27T12:13:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/4b6c7eedc7dd90986bf0fab6ea2a091ec11c01b15f8ba0a14d3f80450468/rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5", size = 345795, upload-time = "2025-08-27T12:13:11.65Z" }, + { url = "https://files.pythonhosted.org/packages/6f/0e/e650e1b81922847a09cca820237b0edee69416a01268b7754d506ade11ad/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e", size = 385121, upload-time = "2025-08-27T12:13:13.008Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ea/b306067a712988e2bff00dcc7c8f31d26c29b6d5931b461aa4b60a013e33/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881", size = 398976, upload-time = "2025-08-27T12:13:14.368Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0a/26dc43c8840cb8fe239fe12dbc8d8de40f2365e838f3d395835dde72f0e5/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec", size = 525953, upload-time = "2025-08-27T12:13:15.774Z" }, + { url = "https://files.pythonhosted.org/packages/22/14/c85e8127b573aaf3a0cbd7fbb8c9c99e735a4a02180c84da2a463b766e9e/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb", size = 407915, upload-time = "2025-08-27T12:13:17.379Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7b/8f4fee9ba1fb5ec856eb22d725a4efa3deb47f769597c809e03578b0f9d9/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5", size = 386883, upload-time = "2025-08-27T12:13:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/86/47/28fa6d60f8b74fcdceba81b272f8d9836ac0340570f68f5df6b41838547b/rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a", size = 405699, upload-time = "2025-08-27T12:13:20.089Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fd/c5987b5e054548df56953a21fe2ebed51fc1ec7c8f24fd41c067b68c4a0a/rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444", size = 423713, upload-time = "2025-08-27T12:13:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ba/3c4978b54a73ed19a7d74531be37a8bcc542d917c770e14d372b8daea186/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a", size = 562324, upload-time = "2025-08-27T12:13:22.789Z" }, + { url = "https://files.pythonhosted.org/packages/b5/6c/6943a91768fec16db09a42b08644b960cff540c66aab89b74be6d4a144ba/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1", size = 593646, upload-time = "2025-08-27T12:13:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/11/73/9d7a8f4be5f4396f011a6bb7a19fe26303a0dac9064462f5651ced2f572f/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998", size = 558137, upload-time = "2025-08-27T12:13:25.557Z" }, + { url = "https://files.pythonhosted.org/packages/6e/96/6772cbfa0e2485bcceef8071de7821f81aeac8bb45fbfd5542a3e8108165/rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39", size = 221343, upload-time = "2025-08-27T12:13:26.967Z" }, + { url = "https://files.pythonhosted.org/packages/67/b6/c82f0faa9af1c6a64669f73a17ee0eeef25aff30bb9a1c318509efe45d84/rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594", size = 232497, upload-time = "2025-08-27T12:13:28.326Z" }, + { url = "https://files.pythonhosted.org/packages/e1/96/2817b44bd2ed11aebacc9251da03689d56109b9aba5e311297b6902136e2/rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502", size = 222790, upload-time = "2025-08-27T12:13:29.71Z" }, + { url = "https://files.pythonhosted.org/packages/cc/77/610aeee8d41e39080c7e14afa5387138e3c9fa9756ab893d09d99e7d8e98/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b", size = 361741, upload-time = "2025-08-27T12:13:31.039Z" }, + { url = "https://files.pythonhosted.org/packages/3a/fc/c43765f201c6a1c60be2043cbdb664013def52460a4c7adace89d6682bf4/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf", size = 345574, upload-time = "2025-08-27T12:13:32.902Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/ee2b2ca114294cd9847d0ef9c26d2b0851b2e7e00bf14cc4c0b581df0fc3/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83", size = 385051, upload-time = "2025-08-27T12:13:34.228Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e8/1e430fe311e4799e02e2d1af7c765f024e95e17d651612425b226705f910/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf", size = 398395, upload-time = "2025-08-27T12:13:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/82/95/9dc227d441ff2670651c27a739acb2535ccaf8b351a88d78c088965e5996/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2", size = 524334, upload-time = "2025-08-27T12:13:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/01/a670c232f401d9ad461d9a332aa4080cd3cb1d1df18213dbd0d2a6a7ab51/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0", size = 407691, upload-time = "2025-08-27T12:13:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418", size = 386868, upload-time = "2025-08-27T12:13:40.192Z" }, + { url = "https://files.pythonhosted.org/packages/3b/03/8c897fb8b5347ff6c1cc31239b9611c5bf79d78c984430887a353e1409a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d", size = 405469, upload-time = "2025-08-27T12:13:41.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/07/88c60edc2df74850d496d78a1fdcdc7b54360a7f610a4d50008309d41b94/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274", size = 422125, upload-time = "2025-08-27T12:13:42.802Z" }, + { url = "https://files.pythonhosted.org/packages/6b/86/5f4c707603e41b05f191a749984f390dabcbc467cf833769b47bf14ba04f/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd", size = 562341, upload-time = "2025-08-27T12:13:44.472Z" }, + { url = "https://files.pythonhosted.org/packages/b2/92/3c0cb2492094e3cd9baf9e49bbb7befeceb584ea0c1a8b5939dca4da12e5/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2", size = 592511, upload-time = "2025-08-27T12:13:45.898Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/82e64fbb0047c46a168faa28d0d45a7851cd0582f850b966811d30f67ad8/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002", size = 557736, upload-time = "2025-08-27T12:13:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/00/95/3c863973d409210da7fb41958172c6b7dbe7fc34e04d3cc1f10bb85e979f/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3", size = 221462, upload-time = "2025-08-27T12:13:48.742Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2c/5867b14a81dc217b56d95a9f2a40fdbc56a1ab0181b80132beeecbd4b2d6/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83", size = 232034, upload-time = "2025-08-27T12:13:50.11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/3958f3f018c01923823f1e47f1cc338e398814b92d83cd278364446fac66/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d", size = 222392, upload-time = "2025-08-27T12:13:52.587Z" }, + { url = "https://files.pythonhosted.org/packages/01/76/1cdf1f91aed5c3a7bf2eba1f1c4e4d6f57832d73003919a20118870ea659/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228", size = 358355, upload-time = "2025-08-27T12:13:54.012Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6f/bf142541229374287604caf3bb2a4ae17f0a580798fd72d3b009b532db4e/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92", size = 342138, upload-time = "2025-08-27T12:13:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/1a/77/355b1c041d6be40886c44ff5e798b4e2769e497b790f0f7fd1e78d17e9a8/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2", size = 380247, upload-time = "2025-08-27T12:13:57.683Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a4/d9cef5c3946ea271ce2243c51481971cd6e34f21925af2783dd17b26e815/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723", size = 390699, upload-time = "2025-08-27T12:13:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/3a/06/005106a7b8c6c1a7e91b73169e49870f4af5256119d34a361ae5240a0c1d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802", size = 521852, upload-time = "2025-08-27T12:14:00.583Z" }, + { url = "https://files.pythonhosted.org/packages/e5/3e/50fb1dac0948e17a02eb05c24510a8fe12d5ce8561c6b7b7d1339ab7ab9c/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f", size = 402582, upload-time = "2025-08-27T12:14:02.034Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/f4e224090dc5b0ec15f31a02d746ab24101dd430847c4d99123798661bfc/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2", size = 384126, upload-time = "2025-08-27T12:14:03.437Z" }, + { url = "https://files.pythonhosted.org/packages/54/77/ac339d5f82b6afff1df8f0fe0d2145cc827992cb5f8eeb90fc9f31ef7a63/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21", size = 399486, upload-time = "2025-08-27T12:14:05.443Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/3e1c255eee6ac358c056a57d6d6869baa00a62fa32eea5ee0632039c50a3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef", size = 414832, upload-time = "2025-08-27T12:14:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/3f/db/6d498b844342deb3fa1d030598db93937a9964fcf5cb4da4feb5f17be34b/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081", size = 557249, upload-time = "2025-08-27T12:14:08.37Z" }, + { url = "https://files.pythonhosted.org/packages/60/f3/690dd38e2310b6f68858a331399b4d6dbb9132c3e8ef8b4333b96caf403d/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd", size = 587356, upload-time = "2025-08-27T12:14:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" }, + { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" }, + { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" }, + { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" }, + { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" }, + { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" }, + { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" }, + { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" }, + { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" }, + { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" }, + { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" }, + { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" }, + { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" }, + { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" }, + { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" }, + { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" }, + { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" }, + { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" }, + { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" }, +] + +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/b9/9bd84453ed6dd04688de9b3f3a4146a1698e8faae2ceeccce4e14c67ae17/ruff-0.14.0.tar.gz", hash = "sha256:62ec8969b7510f77945df916de15da55311fade8d6050995ff7f680afe582c57", size = 5452071, upload-time = "2025-10-07T18:21:55.763Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/4e/79d463a5f80654e93fa653ebfb98e0becc3f0e7cf6219c9ddedf1e197072/ruff-0.14.0-py3-none-linux_armv6l.whl", hash = "sha256:58e15bffa7054299becf4bab8a1187062c6f8cafbe9f6e39e0d5aface455d6b3", size = 12494532, upload-time = "2025-10-07T18:21:00.373Z" }, + { url = "https://files.pythonhosted.org/packages/ee/40/e2392f445ed8e02aa6105d49db4bfff01957379064c30f4811c3bf38aece/ruff-0.14.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:838d1b065f4df676b7c9957992f2304e41ead7a50a568185efd404297d5701e8", size = 13160768, upload-time = "2025-10-07T18:21:04.73Z" }, + { url = "https://files.pythonhosted.org/packages/75/da/2a656ea7c6b9bd14c7209918268dd40e1e6cea65f4bb9880eaaa43b055cd/ruff-0.14.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:703799d059ba50f745605b04638fa7e9682cc3da084b2092feee63500ff3d9b8", size = 12363376, upload-time = "2025-10-07T18:21:07.833Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/1ffef5a1875add82416ff388fcb7ea8b22a53be67a638487937aea81af27/ruff-0.14.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ba9a8925e90f861502f7d974cc60e18ca29c72bb0ee8bfeabb6ade35a3abde7", size = 12608055, upload-time = "2025-10-07T18:21:10.72Z" }, + { url = "https://files.pythonhosted.org/packages/4a/32/986725199d7cee510d9f1dfdf95bf1efc5fa9dd714d0d85c1fb1f6be3bc3/ruff-0.14.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e41f785498bd200ffc276eb9e1570c019c1d907b07cfb081092c8ad51975bbe7", size = 12318544, upload-time = "2025-10-07T18:21:13.741Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ed/4969cefd53315164c94eaf4da7cfba1f267dc275b0abdd593d11c90829a3/ruff-0.14.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30a58c087aef4584c193aebf2700f0fbcfc1e77b89c7385e3139956fa90434e2", size = 14001280, upload-time = "2025-10-07T18:21:16.411Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ad/96c1fc9f8854c37681c9613d825925c7f24ca1acfc62a4eb3896b50bacd2/ruff-0.14.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f8d07350bc7af0a5ce8812b7d5c1a7293cf02476752f23fdfc500d24b79b783c", size = 15027286, upload-time = "2025-10-07T18:21:19.577Z" }, + { url = "https://files.pythonhosted.org/packages/b3/00/1426978f97df4fe331074baf69615f579dc4e7c37bb4c6f57c2aad80c87f/ruff-0.14.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eec3bbbf3a7d5482b5c1f42d5fc972774d71d107d447919fca620b0be3e3b75e", size = 14451506, upload-time = "2025-10-07T18:21:22.779Z" }, + { url = "https://files.pythonhosted.org/packages/58/d5/9c1cea6e493c0cf0647674cca26b579ea9d2a213b74b5c195fbeb9678e15/ruff-0.14.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16b68e183a0e28e5c176d51004aaa40559e8f90065a10a559176713fcf435206", size = 13437384, upload-time = "2025-10-07T18:21:25.758Z" }, + { url = "https://files.pythonhosted.org/packages/29/b4/4cd6a4331e999fc05d9d77729c95503f99eae3ba1160469f2b64866964e3/ruff-0.14.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb732d17db2e945cfcbbc52af0143eda1da36ca8ae25083dd4f66f1542fdf82e", size = 13447976, upload-time = "2025-10-07T18:21:28.83Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c0/ac42f546d07e4f49f62332576cb845d45c67cf5610d1851254e341d563b6/ruff-0.14.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:c958f66ab884b7873e72df38dcabee03d556a8f2ee1b8538ee1c2bbd619883dd", size = 13682850, upload-time = "2025-10-07T18:21:31.842Z" }, + { url = "https://files.pythonhosted.org/packages/5f/c4/4b0c9bcadd45b4c29fe1af9c5d1dc0ca87b4021665dfbe1c4688d407aa20/ruff-0.14.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7eb0499a2e01f6e0c285afc5bac43ab380cbfc17cd43a2e1dd10ec97d6f2c42d", size = 12449825, upload-time = "2025-10-07T18:21:35.074Z" }, + { url = "https://files.pythonhosted.org/packages/4b/a8/e2e76288e6c16540fa820d148d83e55f15e994d852485f221b9524514730/ruff-0.14.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4c63b2d99fafa05efca0ab198fd48fa6030d57e4423df3f18e03aa62518c565f", size = 12272599, upload-time = "2025-10-07T18:21:38.08Z" }, + { url = "https://files.pythonhosted.org/packages/18/14/e2815d8eff847391af632b22422b8207704222ff575dec8d044f9ab779b2/ruff-0.14.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:668fce701b7a222f3f5327f86909db2bbe99c30877c8001ff934c5413812ac02", size = 13193828, upload-time = "2025-10-07T18:21:41.216Z" }, + { url = "https://files.pythonhosted.org/packages/44/c6/61ccc2987cf0aecc588ff8f3212dea64840770e60d78f5606cd7dc34de32/ruff-0.14.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a86bf575e05cb68dcb34e4c7dfe1064d44d3f0c04bbc0491949092192b515296", size = 13628617, upload-time = "2025-10-07T18:21:44.04Z" }, + { url = "https://files.pythonhosted.org/packages/73/e6/03b882225a1b0627e75339b420883dc3c90707a8917d2284abef7a58d317/ruff-0.14.0-py3-none-win32.whl", hash = "sha256:7450a243d7125d1c032cb4b93d9625dea46c8c42b4f06c6b709baac168e10543", size = 12367872, upload-time = "2025-10-07T18:21:46.67Z" }, + { url = "https://files.pythonhosted.org/packages/41/77/56cf9cf01ea0bfcc662de72540812e5ba8e9563f33ef3d37ab2174892c47/ruff-0.14.0-py3-none-win_amd64.whl", hash = "sha256:ea95da28cd874c4d9c922b39381cbd69cb7e7b49c21b8152b014bd4f52acddc2", size = 13464628, upload-time = "2025-10-07T18:21:50.318Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2a/65880dfd0e13f7f13a775998f34703674a4554906167dce02daf7865b954/ruff-0.14.0-py3-none-win_arm64.whl", hash = "sha256:f42c9495f5c13ff841b1da4cb3c2a42075409592825dada7c5885c2c844ac730", size = 12565142, upload-time = "2025-10-07T18:21:53.577Z" }, +] + +[[package]] +name = "safetensors" +version = "0.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/cc/738f3011628920e027a11754d9cae9abec1aed00f7ae860abbf843755233/safetensors-0.6.2.tar.gz", hash = "sha256:43ff2aa0e6fa2dc3ea5524ac7ad93a9839256b8703761e76e2d0b2a3fa4f15d9", size = 197968, upload-time = "2025-08-08T13:13:58.654Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/b1/3f5fd73c039fc87dba3ff8b5d528bfc5a32b597fea8e7a6a4800343a17c7/safetensors-0.6.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9c85ede8ec58f120bad982ec47746981e210492a6db876882aa021446af8ffba", size = 454797, upload-time = "2025-08-08T13:13:52.066Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c9/bb114c158540ee17907ec470d01980957fdaf87b4aa07914c24eba87b9c6/safetensors-0.6.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6675cf4b39c98dbd7d940598028f3742e0375a6b4d4277e76beb0c35f4b843b", size = 432206, upload-time = "2025-08-08T13:13:50.931Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8e/f70c34e47df3110e8e0bb268d90db8d4be8958a54ab0336c9be4fe86dac8/safetensors-0.6.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d2d2b3ce1e2509c68932ca03ab8f20570920cd9754b05063d4368ee52833ecd", size = 473261, upload-time = "2025-08-08T13:13:41.259Z" }, + { url = "https://files.pythonhosted.org/packages/2a/f5/be9c6a7c7ef773e1996dc214e73485286df1836dbd063e8085ee1976f9cb/safetensors-0.6.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:93de35a18f46b0f5a6a1f9e26d91b442094f2df02e9fd7acf224cfec4238821a", size = 485117, upload-time = "2025-08-08T13:13:43.506Z" }, + { url = "https://files.pythonhosted.org/packages/c9/55/23f2d0a2c96ed8665bf17a30ab4ce5270413f4d74b6d87dd663258b9af31/safetensors-0.6.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89a89b505f335640f9120fac65ddeb83e40f1fd081cb8ed88b505bdccec8d0a1", size = 616154, upload-time = "2025-08-08T13:13:45.096Z" }, + { url = "https://files.pythonhosted.org/packages/98/c6/affb0bd9ce02aa46e7acddbe087912a04d953d7a4d74b708c91b5806ef3f/safetensors-0.6.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc4d0d0b937e04bdf2ae6f70cd3ad51328635fe0e6214aa1fc811f3b576b3bda", size = 520713, upload-time = "2025-08-08T13:13:46.25Z" }, + { url = "https://files.pythonhosted.org/packages/fe/5d/5a514d7b88e310c8b146e2404e0dc161282e78634d9358975fd56dfd14be/safetensors-0.6.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8045db2c872db8f4cbe3faa0495932d89c38c899c603f21e9b6486951a5ecb8f", size = 485835, upload-time = "2025-08-08T13:13:49.373Z" }, + { url = "https://files.pythonhosted.org/packages/7a/7b/4fc3b2ba62c352b2071bea9cfbad330fadda70579f617506ae1a2f129cab/safetensors-0.6.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:81e67e8bab9878bb568cffbc5f5e655adb38d2418351dc0859ccac158f753e19", size = 521503, upload-time = "2025-08-08T13:13:47.651Z" }, + { url = "https://files.pythonhosted.org/packages/5a/50/0057e11fe1f3cead9254315a6c106a16dd4b1a19cd247f7cc6414f6b7866/safetensors-0.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0e4d029ab0a0e0e4fdf142b194514695b1d7d3735503ba700cf36d0fc7136ce", size = 652256, upload-time = "2025-08-08T13:13:53.167Z" }, + { url = "https://files.pythonhosted.org/packages/e9/29/473f789e4ac242593ac1656fbece6e1ecd860bb289e635e963667807afe3/safetensors-0.6.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:fa48268185c52bfe8771e46325a1e21d317207bcabcb72e65c6e28e9ffeb29c7", size = 747281, upload-time = "2025-08-08T13:13:54.656Z" }, + { url = "https://files.pythonhosted.org/packages/68/52/f7324aad7f2df99e05525c84d352dc217e0fa637a4f603e9f2eedfbe2c67/safetensors-0.6.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:d83c20c12c2d2f465997c51b7ecb00e407e5f94d7dec3ea0cc11d86f60d3fde5", size = 692286, upload-time = "2025-08-08T13:13:55.884Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/cad1d9762868c7c5dc70c8620074df28ebb1a8e4c17d4c0cb031889c457e/safetensors-0.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d944cea65fad0ead848b6ec2c37cc0b197194bec228f8020054742190e9312ac", size = 655957, upload-time = "2025-08-08T13:13:57.029Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/e2158e17bbe57d104f0abbd95dff60dda916cf277c9f9663b4bf9bad8b6e/safetensors-0.6.2-cp38-abi3-win32.whl", hash = "sha256:cab75ca7c064d3911411461151cb69380c9225798a20e712b102edda2542ddb1", size = 308926, upload-time = "2025-08-08T13:14:01.095Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c3/c0be1135726618dc1e28d181b8c442403d8dbb9e273fd791de2d4384bcdd/safetensors-0.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:c7b214870df923cbc1593c3faee16bec59ea462758699bd3fee399d00aac072c", size = 320192, upload-time = "2025-08-08T13:13:59.467Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818, upload-time = "2025-09-09T08:20:43.19Z" }, + { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997, upload-time = "2025-09-09T08:20:45.468Z" }, + { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381, upload-time = "2025-09-09T08:20:47.982Z" }, + { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296, upload-time = "2025-09-09T08:20:50.366Z" }, + { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256, upload-time = "2025-09-09T08:20:52.627Z" }, + { url = "https://files.pythonhosted.org/packages/ae/93/a3038cb0293037fd335f77f31fe053b89c72f17b1c8908c576c29d953e84/scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7", size = 9212382, upload-time = "2025-09-09T08:20:54.731Z" }, + { url = "https://files.pythonhosted.org/packages/40/dd/9a88879b0c1104259136146e4742026b52df8540c39fec21a6383f8292c7/scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe", size = 8592042, upload-time = "2025-09-09T08:20:57.313Z" }, + { url = "https://files.pythonhosted.org/packages/46/af/c5e286471b7d10871b811b72ae794ac5fe2989c0a2df07f0ec723030f5f5/scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f", size = 9434180, upload-time = "2025-09-09T08:20:59.671Z" }, + { url = "https://files.pythonhosted.org/packages/f1/fd/df59faa53312d585023b2da27e866524ffb8faf87a68516c23896c718320/scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0", size = 9283660, upload-time = "2025-09-09T08:21:01.71Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c7/03000262759d7b6f38c836ff9d512f438a70d8a8ddae68ee80de72dcfb63/scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c", size = 8702057, upload-time = "2025-09-09T08:21:04.234Z" }, + { url = "https://files.pythonhosted.org/packages/55/87/ef5eb1f267084532c8e4aef98a28b6ffe7425acbfd64b5e2f2e066bc29b3/scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8", size = 9558731, upload-time = "2025-09-09T08:21:06.381Z" }, + { url = "https://files.pythonhosted.org/packages/93/f8/6c1e3fc14b10118068d7938878a9f3f4e6d7b74a8ddb1e5bed65159ccda8/scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a", size = 9038852, upload-time = "2025-09-09T08:21:08.628Z" }, + { url = "https://files.pythonhosted.org/packages/83/87/066cafc896ee540c34becf95d30375fe5cbe93c3b75a0ee9aa852cd60021/scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c", size = 9527094, upload-time = "2025-09-09T08:21:11.486Z" }, + { url = "https://files.pythonhosted.org/packages/9c/2b/4903e1ccafa1f6453b1ab78413938c8800633988c838aa0be386cbb33072/scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c", size = 9367436, upload-time = "2025-09-09T08:21:13.602Z" }, + { url = "https://files.pythonhosted.org/packages/b5/aa/8444be3cfb10451617ff9d177b3c190288f4563e6c50ff02728be67ad094/scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973", size = 9275749, upload-time = "2025-09-09T08:21:15.96Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/dee5acf66837852e8e68df6d8d3a6cb22d3df997b733b032f513d95205b7/scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33", size = 9208906, upload-time = "2025-09-09T08:21:18.557Z" }, + { url = "https://files.pythonhosted.org/packages/3c/30/9029e54e17b87cb7d50d51a5926429c683d5b4c1732f0507a6c3bed9bf65/scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615", size = 8627836, upload-time = "2025-09-09T08:21:20.695Z" }, + { url = "https://files.pythonhosted.org/packages/60/18/4a52c635c71b536879f4b971c2cedf32c35ee78f48367885ed8025d1f7ee/scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106", size = 9426236, upload-time = "2025-09-09T08:21:22.645Z" }, + { url = "https://files.pythonhosted.org/packages/99/7e/290362f6ab582128c53445458a5befd471ed1ea37953d5bcf80604619250/scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61", size = 9312593, upload-time = "2025-09-09T08:21:24.65Z" }, + { url = "https://files.pythonhosted.org/packages/8e/87/24f541b6d62b1794939ae6422f8023703bbf6900378b2b34e0b4384dfefd/scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8", size = 8820007, upload-time = "2025-09-09T08:21:26.713Z" }, +] + +[[package]] +name = "scipy" +version = "1.16.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/3b/546a6f0bfe791bbb7f8d591613454d15097e53f906308ec6f7c1ce588e8e/scipy-1.16.2.tar.gz", hash = "sha256:af029b153d243a80afb6eabe40b0a07f8e35c9adc269c019f364ad747f826a6b", size = 30580599, upload-time = "2025-09-11T17:48:08.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/8d/6396e00db1282279a4ddd507c5f5e11f606812b608ee58517ce8abbf883f/scipy-1.16.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:89d6c100fa5c48472047632e06f0876b3c4931aac1f4291afc81a3644316bb0d", size = 36646259, upload-time = "2025-09-11T17:40:39.329Z" }, + { url = "https://files.pythonhosted.org/packages/3b/93/ea9edd7e193fceb8eef149804491890bde73fb169c896b61aa3e2d1e4e77/scipy-1.16.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ca748936cd579d3f01928b30a17dc474550b01272d8046e3e1ee593f23620371", size = 28888976, upload-time = "2025-09-11T17:40:46.82Z" }, + { url = "https://files.pythonhosted.org/packages/91/4d/281fddc3d80fd738ba86fd3aed9202331180b01e2c78eaae0642f22f7e83/scipy-1.16.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:fac4f8ce2ddb40e2e3d0f7ec36d2a1e7f92559a2471e59aec37bd8d9de01fec0", size = 20879905, upload-time = "2025-09-11T17:40:52.545Z" }, + { url = "https://files.pythonhosted.org/packages/69/40/b33b74c84606fd301b2915f0062e45733c6ff5708d121dd0deaa8871e2d0/scipy-1.16.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:033570f1dcefd79547a88e18bccacff025c8c647a330381064f561d43b821232", size = 23553066, upload-time = "2025-09-11T17:40:59.014Z" }, + { url = "https://files.pythonhosted.org/packages/55/a7/22c739e2f21a42cc8f16bc76b47cff4ed54fbe0962832c589591c2abec34/scipy-1.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ea3421209bf00c8a5ef2227de496601087d8f638a2363ee09af059bd70976dc1", size = 33336407, upload-time = "2025-09-11T17:41:06.796Z" }, + { url = "https://files.pythonhosted.org/packages/53/11/a0160990b82999b45874dc60c0c183d3a3a969a563fffc476d5a9995c407/scipy-1.16.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f66bd07ba6f84cd4a380b41d1bf3c59ea488b590a2ff96744845163309ee8e2f", size = 35673281, upload-time = "2025-09-11T17:41:15.055Z" }, + { url = "https://files.pythonhosted.org/packages/96/53/7ef48a4cfcf243c3d0f1643f5887c81f29fdf76911c4e49331828e19fc0a/scipy-1.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e9feab931bd2aea4a23388c962df6468af3d808ddf2d40f94a81c5dc38f32ef", size = 36004222, upload-time = "2025-09-11T17:41:23.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7f/71a69e0afd460049d41c65c630c919c537815277dfea214031005f474d78/scipy-1.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03dfc75e52f72cf23ec2ced468645321407faad8f0fe7b1f5b49264adbc29cb1", size = 38664586, upload-time = "2025-09-11T17:41:31.021Z" }, + { url = "https://files.pythonhosted.org/packages/34/95/20e02ca66fb495a95fba0642fd48e0c390d0ece9b9b14c6e931a60a12dea/scipy-1.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:0ce54e07bbb394b417457409a64fd015be623f36e330ac49306433ffe04bc97e", size = 38550641, upload-time = "2025-09-11T17:41:36.61Z" }, + { url = "https://files.pythonhosted.org/packages/92/ad/13646b9beb0a95528ca46d52b7babafbe115017814a611f2065ee4e61d20/scipy-1.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a8ffaa4ac0df81a0b94577b18ee079f13fecdb924df3328fc44a7dc5ac46851", size = 25456070, upload-time = "2025-09-11T17:41:41.3Z" }, + { url = "https://files.pythonhosted.org/packages/c1/27/c5b52f1ee81727a9fc457f5ac1e9bf3d6eab311805ea615c83c27ba06400/scipy-1.16.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:84f7bf944b43e20b8a894f5fe593976926744f6c185bacfcbdfbb62736b5cc70", size = 36604856, upload-time = "2025-09-11T17:41:47.695Z" }, + { url = "https://files.pythonhosted.org/packages/32/a9/15c20d08e950b540184caa8ced675ba1128accb0e09c653780ba023a4110/scipy-1.16.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5c39026d12edc826a1ef2ad35ad1e6d7f087f934bb868fc43fa3049c8b8508f9", size = 28864626, upload-time = "2025-09-11T17:41:52.642Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fc/ea36098df653cca26062a627c1a94b0de659e97127c8491e18713ca0e3b9/scipy-1.16.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e52729ffd45b68777c5319560014d6fd251294200625d9d70fd8626516fc49f5", size = 20855689, upload-time = "2025-09-11T17:41:57.886Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6f/d0b53be55727f3e6d7c72687ec18ea6d0047cf95f1f77488b99a2bafaee1/scipy-1.16.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:024dd4a118cccec09ca3209b7e8e614931a6ffb804b2a601839499cb88bdf925", size = 23512151, upload-time = "2025-09-11T17:42:02.303Z" }, + { url = "https://files.pythonhosted.org/packages/11/85/bf7dab56e5c4b1d3d8eef92ca8ede788418ad38a7dc3ff50262f00808760/scipy-1.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7a5dc7ee9c33019973a470556081b0fd3c9f4c44019191039f9769183141a4d9", size = 33329824, upload-time = "2025-09-11T17:42:07.549Z" }, + { url = "https://files.pythonhosted.org/packages/da/6a/1a927b14ddc7714111ea51f4e568203b2bb6ed59bdd036d62127c1a360c8/scipy-1.16.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c2275ff105e508942f99d4e3bc56b6ef5e4b3c0af970386ca56b777608ce95b7", size = 35681881, upload-time = "2025-09-11T17:42:13.255Z" }, + { url = "https://files.pythonhosted.org/packages/c1/5f/331148ea5780b4fcc7007a4a6a6ee0a0c1507a796365cc642d4d226e1c3a/scipy-1.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af80196eaa84f033e48444d2e0786ec47d328ba00c71e4299b602235ffef9acb", size = 36006219, upload-time = "2025-09-11T17:42:18.765Z" }, + { url = "https://files.pythonhosted.org/packages/46/3a/e991aa9d2aec723b4a8dcfbfc8365edec5d5e5f9f133888067f1cbb7dfc1/scipy-1.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9fb1eb735fe3d6ed1f89918224e3385fbf6f9e23757cacc35f9c78d3b712dd6e", size = 38682147, upload-time = "2025-09-11T17:42:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/a1/57/0f38e396ad19e41b4c5db66130167eef8ee620a49bc7d0512e3bb67e0cab/scipy-1.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:fda714cf45ba43c9d3bae8f2585c777f64e3f89a2e073b668b32ede412d8f52c", size = 38520766, upload-time = "2025-09-11T17:43:25.342Z" }, + { url = "https://files.pythonhosted.org/packages/1b/a5/85d3e867b6822d331e26c862a91375bb7746a0b458db5effa093d34cdb89/scipy-1.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:2f5350da923ccfd0b00e07c3e5cfb316c1c0d6c1d864c07a72d092e9f20db104", size = 25451169, upload-time = "2025-09-11T17:43:30.198Z" }, + { url = "https://files.pythonhosted.org/packages/09/d9/60679189bcebda55992d1a45498de6d080dcaf21ce0c8f24f888117e0c2d/scipy-1.16.2-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:53d8d2ee29b925344c13bda64ab51785f016b1b9617849dac10897f0701b20c1", size = 37012682, upload-time = "2025-09-11T17:42:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/83/be/a99d13ee4d3b7887a96f8c71361b9659ba4ef34da0338f14891e102a127f/scipy-1.16.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:9e05e33657efb4c6a9d23bd8300101536abd99c85cca82da0bffff8d8764d08a", size = 29389926, upload-time = "2025-09-11T17:42:35.845Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0a/130164a4881cec6ca8c00faf3b57926f28ed429cd6001a673f83c7c2a579/scipy-1.16.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:7fe65b36036357003b3ef9d37547abeefaa353b237e989c21027b8ed62b12d4f", size = 21381152, upload-time = "2025-09-11T17:42:40.07Z" }, + { url = "https://files.pythonhosted.org/packages/47/a6/503ffb0310ae77fba874e10cddfc4a1280bdcca1d13c3751b8c3c2996cf8/scipy-1.16.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6406d2ac6d40b861cccf57f49592f9779071655e9f75cd4f977fa0bdd09cb2e4", size = 23914410, upload-time = "2025-09-11T17:42:44.313Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c7/1147774bcea50d00c02600aadaa919facbd8537997a62496270133536ed6/scipy-1.16.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff4dc42bd321991fbf611c23fc35912d690f731c9914bf3af8f417e64aca0f21", size = 33481880, upload-time = "2025-09-11T17:42:49.325Z" }, + { url = "https://files.pythonhosted.org/packages/6a/74/99d5415e4c3e46b2586f30cdbecb95e101c7192628a484a40dd0d163811a/scipy-1.16.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:654324826654d4d9133e10675325708fb954bc84dae6e9ad0a52e75c6b1a01d7", size = 35791425, upload-time = "2025-09-11T17:42:54.711Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ee/a6559de7c1cc710e938c0355d9d4fbcd732dac4d0d131959d1f3b63eb29c/scipy-1.16.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63870a84cd15c44e65220eaed2dac0e8f8b26bbb991456a033c1d9abfe8a94f8", size = 36178622, upload-time = "2025-09-11T17:43:00.375Z" }, + { url = "https://files.pythonhosted.org/packages/4e/7b/f127a5795d5ba8ece4e0dce7d4a9fb7cb9e4f4757137757d7a69ab7d4f1a/scipy-1.16.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fa01f0f6a3050fa6a9771a95d5faccc8e2f5a92b4a2e5440a0fa7264a2398472", size = 38783985, upload-time = "2025-09-11T17:43:06.661Z" }, + { url = "https://files.pythonhosted.org/packages/3e/9f/bc81c1d1e033951eb5912cd3750cc005943afa3e65a725d2443a3b3c4347/scipy-1.16.2-cp313-cp313t-win_amd64.whl", hash = "sha256:116296e89fba96f76353a8579820c2512f6e55835d3fad7780fece04367de351", size = 38631367, upload-time = "2025-09-11T17:43:14.44Z" }, + { url = "https://files.pythonhosted.org/packages/d6/5e/2cc7555fd81d01814271412a1d59a289d25f8b63208a0a16c21069d55d3e/scipy-1.16.2-cp313-cp313t-win_arm64.whl", hash = "sha256:98e22834650be81d42982360382b43b17f7ba95e0e6993e2a4f5b9ad9283a94d", size = 25787992, upload-time = "2025-09-11T17:43:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ac/ad8951250516db71619f0bd3b2eb2448db04b720a003dd98619b78b692c0/scipy-1.16.2-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:567e77755019bb7461513c87f02bb73fb65b11f049aaaa8ca17cfaa5a5c45d77", size = 36595109, upload-time = "2025-09-11T17:43:35.713Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f6/5779049ed119c5b503b0f3dc6d6f3f68eefc3a9190d4ad4c276f854f051b/scipy-1.16.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:17d9bb346194e8967296621208fcdfd39b55498ef7d2f376884d5ac47cec1a70", size = 28859110, upload-time = "2025-09-11T17:43:40.814Z" }, + { url = "https://files.pythonhosted.org/packages/82/09/9986e410ae38bf0a0c737ff8189ac81a93b8e42349aac009891c054403d7/scipy-1.16.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:0a17541827a9b78b777d33b623a6dcfe2ef4a25806204d08ead0768f4e529a88", size = 20850110, upload-time = "2025-09-11T17:43:44.981Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ad/485cdef2d9215e2a7df6d61b81d2ac073dfacf6ae24b9ae87274c4e936ae/scipy-1.16.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:d7d4c6ba016ffc0f9568d012f5f1eb77ddd99412aea121e6fa8b4c3b7cbad91f", size = 23497014, upload-time = "2025-09-11T17:43:49.074Z" }, + { url = "https://files.pythonhosted.org/packages/a7/74/f6a852e5d581122b8f0f831f1d1e32fb8987776ed3658e95c377d308ed86/scipy-1.16.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9702c4c023227785c779cba2e1d6f7635dbb5b2e0936cdd3a4ecb98d78fd41eb", size = 33401155, upload-time = "2025-09-11T17:43:54.661Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f5/61d243bbc7c6e5e4e13dde9887e84a5cbe9e0f75fd09843044af1590844e/scipy-1.16.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d1cdf0ac28948d225decdefcc45ad7dd91716c29ab56ef32f8e0d50657dffcc7", size = 35691174, upload-time = "2025-09-11T17:44:00.101Z" }, + { url = "https://files.pythonhosted.org/packages/03/99/59933956331f8cc57e406cdb7a483906c74706b156998f322913e789c7e1/scipy-1.16.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:70327d6aa572a17c2941cdfb20673f82e536e91850a2e4cb0c5b858b690e1548", size = 36070752, upload-time = "2025-09-11T17:44:05.619Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7d/00f825cfb47ee19ef74ecf01244b43e95eae74e7e0ff796026ea7cd98456/scipy-1.16.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5221c0b2a4b58aa7c4ed0387d360fd90ee9086d383bb34d9f2789fafddc8a936", size = 38701010, upload-time = "2025-09-11T17:44:11.322Z" }, + { url = "https://files.pythonhosted.org/packages/e4/9f/b62587029980378304ba5a8563d376c96f40b1e133daacee76efdcae32de/scipy-1.16.2-cp314-cp314-win_amd64.whl", hash = "sha256:f5a85d7b2b708025af08f060a496dd261055b617d776fc05a1a1cc69e09fe9ff", size = 39360061, upload-time = "2025-09-11T17:45:09.814Z" }, + { url = "https://files.pythonhosted.org/packages/82/04/7a2f1609921352c7fbee0815811b5050582f67f19983096c4769867ca45f/scipy-1.16.2-cp314-cp314-win_arm64.whl", hash = "sha256:2cc73a33305b4b24556957d5857d6253ce1e2dcd67fa0ff46d87d1670b3e1e1d", size = 26126914, upload-time = "2025-09-11T17:45:14.73Z" }, + { url = "https://files.pythonhosted.org/packages/51/b9/60929ce350c16b221928725d2d1d7f86cf96b8bc07415547057d1196dc92/scipy-1.16.2-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:9ea2a3fed83065d77367775d689401a703d0f697420719ee10c0780bcab594d8", size = 37013193, upload-time = "2025-09-11T17:44:16.757Z" }, + { url = "https://files.pythonhosted.org/packages/2a/41/ed80e67782d4bc5fc85a966bc356c601afddd175856ba7c7bb6d9490607e/scipy-1.16.2-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7280d926f11ca945c3ef92ba960fa924e1465f8d07ce3a9923080363390624c4", size = 29390172, upload-time = "2025-09-11T17:44:21.783Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a3/2f673ace4090452696ccded5f5f8efffb353b8f3628f823a110e0170b605/scipy-1.16.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:8afae1756f6a1fe04636407ef7dbece33d826a5d462b74f3d0eb82deabefd831", size = 21381326, upload-time = "2025-09-11T17:44:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/42/bf/59df61c5d51395066c35836b78136accf506197617c8662e60ea209881e1/scipy-1.16.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:5c66511f29aa8d233388e7416a3f20d5cae7a2744d5cee2ecd38c081f4e861b3", size = 23915036, upload-time = "2025-09-11T17:44:30.527Z" }, + { url = "https://files.pythonhosted.org/packages/91/c3/edc7b300dc16847ad3672f1a6f3f7c5d13522b21b84b81c265f4f2760d4a/scipy-1.16.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efe6305aeaa0e96b0ccca5ff647a43737d9a092064a3894e46c414db84bc54ac", size = 33484341, upload-time = "2025-09-11T17:44:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/26/c7/24d1524e72f06ff141e8d04b833c20db3021020563272ccb1b83860082a9/scipy-1.16.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f3a337d9ae06a1e8d655ee9d8ecb835ea5ddcdcbd8d23012afa055ab014f374", size = 35790840, upload-time = "2025-09-11T17:44:41.76Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b7/5aaad984eeedd56858dc33d75efa59e8ce798d918e1033ef62d2708f2c3d/scipy-1.16.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bab3605795d269067d8ce78a910220262711b753de8913d3deeaedb5dded3bb6", size = 36174716, upload-time = "2025-09-11T17:44:47.316Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c2/e276a237acb09824822b0ada11b028ed4067fdc367a946730979feacb870/scipy-1.16.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b0348d8ddb55be2a844c518cd8cc8deeeb8aeba707cf834db5758fc89b476a2c", size = 38790088, upload-time = "2025-09-11T17:44:53.011Z" }, + { url = "https://files.pythonhosted.org/packages/c6/b4/5c18a766e8353015439f3780f5fc473f36f9762edc1a2e45da3ff5a31b21/scipy-1.16.2-cp314-cp314t-win_amd64.whl", hash = "sha256:26284797e38b8a75e14ea6631d29bda11e76ceaa6ddb6fdebbfe4c4d90faf2f9", size = 39457455, upload-time = "2025-09-11T17:44:58.899Z" }, + { url = "https://files.pythonhosted.org/packages/97/30/2f9a5243008f76dfc5dee9a53dfb939d9b31e16ce4bd4f2e628bfc5d89d2/scipy-1.16.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d2a4472c231328d4de38d5f1f68fdd6d28a615138f842580a8a321b5845cf779", size = 26448374, upload-time = "2025-09-11T17:45:03.45Z" }, +] + +[[package]] +name = "sentence-transformers" +version = "5.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "pillow" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "transformers" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/47/7d61a19ba7e6b5f36f0ffff5bbf032a1c1913612caac611e12383069eda0/sentence_transformers-5.1.1.tar.gz", hash = "sha256:8af3f844b2ecf9a6c2dfeafc2c02938a87f61202b54329d70dfd7dfd7d17a84e", size = 374434, upload-time = "2025-09-22T11:28:27.54Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/21/4670d03ab8587b0ab6f7d5fa02a95c3dd6b1f39d0e40e508870201f3d76c/sentence_transformers-5.1.1-py3-none-any.whl", hash = "sha256:5ed544629eafe89ca668a8910ebff96cf0a9c5254ec14b05c66c086226c892fd", size = 486574, upload-time = "2025-09-22T11:28:26.311Z" }, +] + +[[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 = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.44" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830, upload-time = "2025-10-10T14:39:12.935Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/c4/59c7c9b068e6813c898b771204aad36683c96318ed12d4233e1b18762164/sqlalchemy-2.0.44-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250", size = 2139675, upload-time = "2025-10-10T16:03:31.064Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ae/eeb0920537a6f9c5a3708e4a5fc55af25900216bdb4847ec29cfddf3bf3a/sqlalchemy-2.0.44-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29", size = 2127726, upload-time = "2025-10-10T16:03:35.934Z" }, + { url = "https://files.pythonhosted.org/packages/d8/d5/2ebbabe0379418eda8041c06b0b551f213576bfe4c2f09d77c06c07c8cc5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44", size = 3327603, upload-time = "2025-10-10T15:35:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/45/e5/5aa65852dadc24b7d8ae75b7efb8d19303ed6ac93482e60c44a585930ea5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1", size = 3337842, upload-time = "2025-10-10T15:43:45.431Z" }, + { url = "https://files.pythonhosted.org/packages/41/92/648f1afd3f20b71e880ca797a960f638d39d243e233a7082c93093c22378/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7", size = 3264558, upload-time = "2025-10-10T15:35:29.93Z" }, + { url = "https://files.pythonhosted.org/packages/40/cf/e27d7ee61a10f74b17740918e23cbc5bc62011b48282170dc4c66da8ec0f/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d", size = 3301570, upload-time = "2025-10-10T15:43:48.407Z" }, + { url = "https://files.pythonhosted.org/packages/3b/3d/3116a9a7b63e780fb402799b6da227435be878b6846b192f076d2f838654/sqlalchemy-2.0.44-cp312-cp312-win32.whl", hash = "sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4", size = 2103447, upload-time = "2025-10-10T15:03:21.678Z" }, + { url = "https://files.pythonhosted.org/packages/25/83/24690e9dfc241e6ab062df82cc0df7f4231c79ba98b273fa496fb3dd78ed/sqlalchemy-2.0.44-cp312-cp312-win_amd64.whl", hash = "sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e", size = 2130912, upload-time = "2025-10-10T15:03:24.656Z" }, + { url = "https://files.pythonhosted.org/packages/45/d3/c67077a2249fdb455246e6853166360054c331db4613cda3e31ab1cadbef/sqlalchemy-2.0.44-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1", size = 2135479, upload-time = "2025-10-10T16:03:37.671Z" }, + { url = "https://files.pythonhosted.org/packages/2b/91/eabd0688330d6fd114f5f12c4f89b0d02929f525e6bf7ff80aa17ca802af/sqlalchemy-2.0.44-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45", size = 2123212, upload-time = "2025-10-10T16:03:41.755Z" }, + { url = "https://files.pythonhosted.org/packages/b0/bb/43e246cfe0e81c018076a16036d9b548c4cc649de241fa27d8d9ca6f85ab/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976", size = 3255353, upload-time = "2025-10-10T15:35:31.221Z" }, + { url = "https://files.pythonhosted.org/packages/b9/96/c6105ed9a880abe346b64d3b6ddef269ddfcab04f7f3d90a0bf3c5a88e82/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c", size = 3260222, upload-time = "2025-10-10T15:43:50.124Z" }, + { url = "https://files.pythonhosted.org/packages/44/16/1857e35a47155b5ad927272fee81ae49d398959cb749edca6eaa399b582f/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d", size = 3189614, upload-time = "2025-10-10T15:35:32.578Z" }, + { url = "https://files.pythonhosted.org/packages/88/ee/4afb39a8ee4fc786e2d716c20ab87b5b1fb33d4ac4129a1aaa574ae8a585/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40", size = 3226248, upload-time = "2025-10-10T15:43:51.862Z" }, + { url = "https://files.pythonhosted.org/packages/32/d5/0e66097fc64fa266f29a7963296b40a80d6a997b7ac13806183700676f86/sqlalchemy-2.0.44-cp313-cp313-win32.whl", hash = "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73", size = 2101275, upload-time = "2025-10-10T15:03:26.096Z" }, + { url = "https://files.pythonhosted.org/packages/03/51/665617fe4f8c6450f42a6d8d69243f9420f5677395572c2fe9d21b493b7b/sqlalchemy-2.0.44-cp313-cp313-win_amd64.whl", hash = "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e", size = 2127901, upload-time = "2025-10-10T15:03:27.548Z" }, + { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718, upload-time = "2025-10-10T15:29:45.32Z" }, +] + +[[package]] +name = "sse-starlette" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/6f/22ed6e33f8a9e76ca0a412405f31abb844b779d52c5f96660766edcd737c/sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a", size = 20985, upload-time = "2025-07-27T09:07:44.565Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/10/c78f463b4ef22eef8491f218f692be838282cd65480f6e423d7730dfd1fb/sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a", size = 11297, upload-time = "2025-07-27T09:07:43.268Z" }, +] + +[[package]] +name = "starlette" +version = "0.48.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/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" }, +] + +[[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 = "tenacity" +version = "9.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, +] + +[[package]] +name = "threadpoolctl" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, +] + +[[package]] +name = "tiktoken" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/85/be65d39d6b647c79800fd9d29241d081d4eeb06271f383bb87200d74cf76/tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8", size = 1050728, upload-time = "2025-10-06T20:21:52.756Z" }, + { url = "https://files.pythonhosted.org/packages/4a/42/6573e9129bc55c9bf7300b3a35bef2c6b9117018acca0dc760ac2d93dffe/tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b", size = 994049, upload-time = "2025-10-06T20:21:53.782Z" }, + { url = "https://files.pythonhosted.org/packages/66/c5/ed88504d2f4a5fd6856990b230b56d85a777feab84e6129af0822f5d0f70/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37", size = 1129008, upload-time = "2025-10-06T20:21:54.832Z" }, + { url = "https://files.pythonhosted.org/packages/f4/90/3dae6cc5436137ebd38944d396b5849e167896fc2073da643a49f372dc4f/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad", size = 1152665, upload-time = "2025-10-06T20:21:56.129Z" }, + { url = "https://files.pythonhosted.org/packages/a3/fe/26df24ce53ffde419a42f5f53d755b995c9318908288c17ec3f3448313a3/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5", size = 1194230, upload-time = "2025-10-06T20:21:57.546Z" }, + { url = "https://files.pythonhosted.org/packages/20/cc/b064cae1a0e9fac84b0d2c46b89f4e57051a5f41324e385d10225a984c24/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3", size = 1254688, upload-time = "2025-10-06T20:21:58.619Z" }, + { url = "https://files.pythonhosted.org/packages/81/10/b8523105c590c5b8349f2587e2fdfe51a69544bd5a76295fc20f2374f470/tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd", size = 878694, upload-time = "2025-10-06T20:21:59.876Z" }, + { url = "https://files.pythonhosted.org/packages/00/61/441588ee21e6b5cdf59d6870f86beb9789e532ee9718c251b391b70c68d6/tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3", size = 1050802, upload-time = "2025-10-06T20:22:00.96Z" }, + { url = "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160", size = 993995, upload-time = "2025-10-06T20:22:02.788Z" }, + { url = "https://files.pythonhosted.org/packages/a0/70/5163fe5359b943f8db9946b62f19be2305de8c3d78a16f629d4165e2f40e/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa", size = 1128948, upload-time = "2025-10-06T20:22:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/c028aa0babf77315e1cef357d4d768800c5f8a6de04d0eac0f377cb619fa/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be", size = 1151986, upload-time = "2025-10-06T20:22:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/a0/5a/886b108b766aa53e295f7216b509be95eb7d60b166049ce2c58416b25f2a/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a", size = 1194222, upload-time = "2025-10-06T20:22:06.265Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f8/4db272048397636ac7a078d22773dd2795b1becee7bc4922fe6207288d57/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3", size = 1255097, upload-time = "2025-10-06T20:22:07.403Z" }, + { url = "https://files.pythonhosted.org/packages/8e/32/45d02e2e0ea2be3a9ed22afc47d93741247e75018aac967b713b2941f8ea/tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697", size = 879117, upload-time = "2025-10-06T20:22:08.418Z" }, + { url = "https://files.pythonhosted.org/packages/ce/76/994fc868f88e016e6d05b0da5ac24582a14c47893f4474c3e9744283f1d5/tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16", size = 1050309, upload-time = "2025-10-06T20:22:10.939Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b8/57ef1456504c43a849821920d582a738a461b76a047f352f18c0b26c6516/tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a", size = 993712, upload-time = "2025-10-06T20:22:12.115Z" }, + { url = "https://files.pythonhosted.org/packages/72/90/13da56f664286ffbae9dbcfadcc625439142675845baa62715e49b87b68b/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27", size = 1128725, upload-time = "2025-10-06T20:22:13.541Z" }, + { url = "https://files.pythonhosted.org/packages/05/df/4f80030d44682235bdaecd7346c90f67ae87ec8f3df4a3442cb53834f7e4/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb", size = 1151875, upload-time = "2025-10-06T20:22:14.559Z" }, + { url = "https://files.pythonhosted.org/packages/22/1f/ae535223a8c4ef4c0c1192e3f9b82da660be9eb66b9279e95c99288e9dab/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e", size = 1194451, upload-time = "2025-10-06T20:22:15.545Z" }, + { url = "https://files.pythonhosted.org/packages/78/a7/f8ead382fce0243cb625c4f266e66c27f65ae65ee9e77f59ea1653b6d730/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25", size = 1253794, upload-time = "2025-10-06T20:22:16.624Z" }, + { url = "https://files.pythonhosted.org/packages/93/e0/6cc82a562bc6365785a3ff0af27a2a092d57c47d7a81d9e2295d8c36f011/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f", size = 878777, upload-time = "2025-10-06T20:22:18.036Z" }, + { url = "https://files.pythonhosted.org/packages/72/05/3abc1db5d2c9aadc4d2c76fa5640134e475e58d9fbb82b5c535dc0de9b01/tiktoken-0.12.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a90388128df3b3abeb2bfd1895b0681412a8d7dc644142519e6f0a97c2111646", size = 1050188, upload-time = "2025-10-06T20:22:19.563Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7b/50c2f060412202d6c95f32b20755c7a6273543b125c0985d6fa9465105af/tiktoken-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da900aa0ad52247d8794e307d6446bd3cdea8e192769b56276695d34d2c9aa88", size = 993978, upload-time = "2025-10-06T20:22:20.702Z" }, + { url = "https://files.pythonhosted.org/packages/14/27/bf795595a2b897e271771cd31cb847d479073497344c637966bdf2853da1/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:285ba9d73ea0d6171e7f9407039a290ca77efcdb026be7769dccc01d2c8d7fff", size = 1129271, upload-time = "2025-10-06T20:22:22.06Z" }, + { url = "https://files.pythonhosted.org/packages/f5/de/9341a6d7a8f1b448573bbf3425fa57669ac58258a667eb48a25dfe916d70/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d186a5c60c6a0213f04a7a802264083dea1bbde92a2d4c7069e1a56630aef830", size = 1151216, upload-time = "2025-10-06T20:22:23.085Z" }, + { url = "https://files.pythonhosted.org/packages/75/0d/881866647b8d1be4d67cb24e50d0c26f9f807f994aa1510cb9ba2fe5f612/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:604831189bd05480f2b885ecd2d1986dc7686f609de48208ebbbddeea071fc0b", size = 1194860, upload-time = "2025-10-06T20:22:24.602Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1e/b651ec3059474dab649b8d5b69f5c65cd8fcd8918568c1935bd4136c9392/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8f317e8530bb3a222547b85a58583238c8f74fd7a7408305f9f63246d1a0958b", size = 1254567, upload-time = "2025-10-06T20:22:25.671Z" }, + { url = "https://files.pythonhosted.org/packages/80/57/ce64fd16ac390fafde001268c364d559447ba09b509181b2808622420eec/tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3", size = 921067, upload-time = "2025-10-06T20:22:26.753Z" }, + { url = "https://files.pythonhosted.org/packages/ac/a4/72eed53e8976a099539cdd5eb36f241987212c29629d0a52c305173e0a68/tiktoken-0.12.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2c714c72bc00a38ca969dae79e8266ddec999c7ceccd603cc4f0d04ccd76365", size = 1050473, upload-time = "2025-10-06T20:22:27.775Z" }, + { url = "https://files.pythonhosted.org/packages/e6/d7/0110b8f54c008466b19672c615f2168896b83706a6611ba6e47313dbc6e9/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cbb9a3ba275165a2cb0f9a83f5d7025afe6b9d0ab01a22b50f0e74fee2ad253e", size = 993855, upload-time = "2025-10-06T20:22:28.799Z" }, + { url = "https://files.pythonhosted.org/packages/5f/77/4f268c41a3957c418b084dd576ea2fad2e95da0d8e1ab705372892c2ca22/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:dfdfaa5ffff8993a3af94d1125870b1d27aed7cb97aa7eb8c1cefdbc87dbee63", size = 1129022, upload-time = "2025-10-06T20:22:29.981Z" }, + { url = "https://files.pythonhosted.org/packages/4e/2b/fc46c90fe5028bd094cd6ee25a7db321cb91d45dc87531e2bdbb26b4867a/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:584c3ad3d0c74f5269906eb8a659c8bfc6144a52895d9261cdaf90a0ae5f4de0", size = 1150736, upload-time = "2025-10-06T20:22:30.996Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/3c7a39ff68022ddfd7d93f3337ad90389a342f761c4d71de99a3ccc57857/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a", size = 1194908, upload-time = "2025-10-06T20:22:32.073Z" }, + { url = "https://files.pythonhosted.org/packages/ab/0d/c1ad6f4016a3968c048545f5d9b8ffebf577774b2ede3e2e352553b685fe/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0", size = 1253706, upload-time = "2025-10-06T20:22:33.385Z" }, + { url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667, upload-time = "2025-10-06T20:22:34.444Z" }, +] + +[[package]] +name = "tokenizers" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/46/fb6854cec3278fbfa4a75b50232c77622bc517ac886156e6afbfa4d8fc6e/tokenizers-0.22.1.tar.gz", hash = "sha256:61de6522785310a309b3407bac22d99c4db5dba349935e99e4d15ea2226af2d9", size = 363123, upload-time = "2025-09-19T09:49:23.424Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/33/f4b2d94ada7ab297328fc671fed209368ddb82f965ec2224eb1892674c3a/tokenizers-0.22.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:59fdb013df17455e5f950b4b834a7b3ee2e0271e6378ccb33aa74d178b513c73", size = 3069318, upload-time = "2025-09-19T09:49:11.848Z" }, + { url = "https://files.pythonhosted.org/packages/1c/58/2aa8c874d02b974990e89ff95826a4852a8b2a273c7d1b4411cdd45a4565/tokenizers-0.22.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8d4e484f7b0827021ac5f9f71d4794aaef62b979ab7608593da22b1d2e3c4edc", size = 2926478, upload-time = "2025-09-19T09:49:09.759Z" }, + { url = "https://files.pythonhosted.org/packages/1e/3b/55e64befa1e7bfea963cf4b787b2cea1011362c4193f5477047532ce127e/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d2962dd28bc67c1f205ab180578a78eef89ac60ca7ef7cbe9635a46a56422a", size = 3256994, upload-time = "2025-09-19T09:48:56.701Z" }, + { url = "https://files.pythonhosted.org/packages/71/0b/fbfecf42f67d9b7b80fde4aabb2b3110a97fac6585c9470b5bff103a80cb/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38201f15cdb1f8a6843e6563e6e79f4abd053394992b9bbdf5213ea3469b4ae7", size = 3153141, upload-time = "2025-09-19T09:48:59.749Z" }, + { url = "https://files.pythonhosted.org/packages/17/a9/b38f4e74e0817af8f8ef925507c63c6ae8171e3c4cb2d5d4624bf58fca69/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1cbe5454c9a15df1b3443c726063d930c16f047a3cc724b9e6e1a91140e5a21", size = 3508049, upload-time = "2025-09-19T09:49:05.868Z" }, + { url = "https://files.pythonhosted.org/packages/d2/48/dd2b3dac46bb9134a88e35d72e1aa4869579eacc1a27238f1577270773ff/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7d094ae6312d69cc2a872b54b91b309f4f6fbce871ef28eb27b52a98e4d0214", size = 3710730, upload-time = "2025-09-19T09:49:01.832Z" }, + { url = "https://files.pythonhosted.org/packages/93/0e/ccabc8d16ae4ba84a55d41345207c1e2ea88784651a5a487547d80851398/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afd7594a56656ace95cdd6df4cca2e4059d294c5cfb1679c57824b605556cb2f", size = 3412560, upload-time = "2025-09-19T09:49:03.867Z" }, + { url = "https://files.pythonhosted.org/packages/d0/c6/dc3a0db5a6766416c32c034286d7c2d406da1f498e4de04ab1b8959edd00/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ef6063d7a84994129732b47e7915e8710f27f99f3a3260b8a38fc7ccd083f4", size = 3250221, upload-time = "2025-09-19T09:49:07.664Z" }, + { url = "https://files.pythonhosted.org/packages/d7/a6/2c8486eef79671601ff57b093889a345dd3d576713ef047776015dc66de7/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba0a64f450b9ef412c98f6bcd2a50c6df6e2443b560024a09fa6a03189726879", size = 9345569, upload-time = "2025-09-19T09:49:14.214Z" }, + { url = "https://files.pythonhosted.org/packages/6b/16/32ce667f14c35537f5f605fe9bea3e415ea1b0a646389d2295ec348d5657/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:331d6d149fa9c7d632cde4490fb8bbb12337fa3a0232e77892be656464f4b446", size = 9271599, upload-time = "2025-09-19T09:49:16.639Z" }, + { url = "https://files.pythonhosted.org/packages/51/7c/a5f7898a3f6baa3fc2685c705e04c98c1094c523051c805cdd9306b8f87e/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:607989f2ea68a46cb1dfbaf3e3aabdf3f21d8748312dbeb6263d1b3b66c5010a", size = 9533862, upload-time = "2025-09-19T09:49:19.146Z" }, + { url = "https://files.pythonhosted.org/packages/36/65/7e75caea90bc73c1dd8d40438adf1a7bc26af3b8d0a6705ea190462506e1/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a0f307d490295717726598ef6fa4f24af9d484809223bbc253b201c740a06390", size = 9681250, upload-time = "2025-09-19T09:49:21.501Z" }, + { url = "https://files.pythonhosted.org/packages/30/2c/959dddef581b46e6209da82df3b78471e96260e2bc463f89d23b1bf0e52a/tokenizers-0.22.1-cp39-abi3-win32.whl", hash = "sha256:b5120eed1442765cd90b903bb6cfef781fd8fe64e34ccaecbae4c619b7b12a82", size = 2472003, upload-time = "2025-09-19T09:49:27.089Z" }, + { url = "https://files.pythonhosted.org/packages/b3/46/e33a8c93907b631a99377ef4c5f817ab453d0b34f93529421f42ff559671/tokenizers-0.22.1-cp39-abi3-win_amd64.whl", hash = "sha256:65fd6e3fb11ca1e78a6a93602490f134d1fdeb13bcef99389d5102ea318ed138", size = 2674684, upload-time = "2025-09-19T09:49:24.953Z" }, +] + +[[package]] +name = "torch" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "setuptools" }, + { name = "sympy" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/0c/2fd4df0d83a495bb5e54dca4474c4ec5f9c62db185421563deeb5dabf609/torch-2.8.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e2fab4153768d433f8ed9279c8133a114a034a61e77a3a104dcdf54388838705", size = 101906089, upload-time = "2025-08-06T14:53:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/99/a8/6acf48d48838fb8fe480597d98a0668c2beb02ee4755cc136de92a0a956f/torch-2.8.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2aca0939fb7e4d842561febbd4ffda67a8e958ff725c1c27e244e85e982173c", size = 887913624, upload-time = "2025-08-06T14:56:44.33Z" }, + { url = "https://files.pythonhosted.org/packages/af/8a/5c87f08e3abd825c7dfecef5a0f1d9aa5df5dd0e3fd1fa2f490a8e512402/torch-2.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:2f4ac52f0130275d7517b03a33d2493bab3693c83dcfadf4f81688ea82147d2e", size = 241326087, upload-time = "2025-08-06T14:53:46.503Z" }, + { url = "https://files.pythonhosted.org/packages/be/66/5c9a321b325aaecb92d4d1855421e3a055abd77903b7dab6575ca07796db/torch-2.8.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:619c2869db3ada2c0105487ba21b5008defcc472d23f8b80ed91ac4a380283b0", size = 73630478, upload-time = "2025-08-06T14:53:57.144Z" }, + { url = "https://files.pythonhosted.org/packages/10/4e/469ced5a0603245d6a19a556e9053300033f9c5baccf43a3d25ba73e189e/torch-2.8.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2b2f96814e0345f5a5aed9bf9734efa913678ed19caf6dc2cddb7930672d6128", size = 101936856, upload-time = "2025-08-06T14:54:01.526Z" }, + { url = "https://files.pythonhosted.org/packages/16/82/3948e54c01b2109238357c6f86242e6ecbf0c63a1af46906772902f82057/torch-2.8.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:65616ca8ec6f43245e1f5f296603e33923f4c30f93d65e103d9e50c25b35150b", size = 887922844, upload-time = "2025-08-06T14:55:50.78Z" }, + { url = "https://files.pythonhosted.org/packages/e3/54/941ea0a860f2717d86a811adf0c2cd01b3983bdd460d0803053c4e0b8649/torch-2.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:659df54119ae03e83a800addc125856effda88b016dfc54d9f65215c3975be16", size = 241330968, upload-time = "2025-08-06T14:54:45.293Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/8b7b13bba430f5e21d77708b616f767683629fc4f8037564a177d20f90ed/torch-2.8.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:1a62a1ec4b0498930e2543535cf70b1bef8c777713de7ceb84cd79115f553767", size = 73915128, upload-time = "2025-08-06T14:54:34.769Z" }, + { url = "https://files.pythonhosted.org/packages/15/0e/8a800e093b7f7430dbaefa80075aee9158ec22e4c4fc3c1a66e4fb96cb4f/torch-2.8.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:83c13411a26fac3d101fe8035a6b0476ae606deb8688e904e796a3534c197def", size = 102020139, upload-time = "2025-08-06T14:54:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/4a/15/5e488ca0bc6162c86a33b58642bc577c84ded17c7b72d97e49b5833e2d73/torch-2.8.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8f0a9d617a66509ded240add3754e462430a6c1fc5589f86c17b433dd808f97a", size = 887990692, upload-time = "2025-08-06T14:56:18.286Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a8/6a04e4b54472fc5dba7ca2341ab219e529f3c07b6941059fbf18dccac31f/torch-2.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a7242b86f42be98ac674b88a4988643b9bc6145437ec8f048fea23f72feb5eca", size = 241603453, upload-time = "2025-08-06T14:55:22.945Z" }, + { url = "https://files.pythonhosted.org/packages/04/6e/650bb7f28f771af0cb791b02348db8b7f5f64f40f6829ee82aa6ce99aabe/torch-2.8.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:7b677e17f5a3e69fdef7eb3b9da72622f8d322692930297e4ccb52fefc6c8211", size = 73632395, upload-time = "2025-08-06T14:55:28.645Z" }, +] + +[[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 = "transformers" +version = "4.57.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "regex" }, + { name = "requests" }, + { name = "safetensors" }, + { name = "tokenizers" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/5c/a22c39dac2687f3fe2a6b97e2c1ae516e91cd4d3976a7a2b7c24ff2fae48/transformers-4.57.0.tar.gz", hash = "sha256:d045753f3d93f9216e693cdb168698dfd2e9d3aad1bb72579a5d60ebf1545a8b", size = 10142956, upload-time = "2025-10-03T17:03:47.177Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/2b/4d2708ac1ff5cd708b6548f4c5812d0ae40d1c28591c4c1c762b6dbdef2d/transformers-4.57.0-py3-none-any.whl", hash = "sha256:9d7c6d098c026e40d897e017ed1f481ab803cbac041021dbc6ae6100e4949b55", size = 11990588, upload-time = "2025-10-03T17:03:43.629Z" }, +] + +[[package]] +name = "triton" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/66/b1eb52839f563623d185f0927eb3530ee4d5ffe9d377cdaf5346b306689e/triton-3.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c1d84a5c0ec2c0f8e8a072d7fd150cab84a9c239eaddc6706c081bfae4eb04", size = 155560068, upload-time = "2025-07-30T19:58:37.081Z" }, + { url = "https://files.pythonhosted.org/packages/30/7b/0a685684ed5322d2af0bddefed7906674f67974aa88b0fae6e82e3b766f6/triton-3.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00be2964616f4c619193cb0d1b29a99bd4b001d7dc333816073f92cf2a8ccdeb", size = 155569223, upload-time = "2025-07-30T19:58:44.017Z" }, + { url = "https://files.pythonhosted.org/packages/20/63/8cb444ad5cdb25d999b7d647abac25af0ee37d292afc009940c05b82dda0/triton-3.4.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7936b18a3499ed62059414d7df563e6c163c5e16c3773678a3ee3d417865035d", size = 155659780, upload-time = "2025-07-30T19:58:51.171Z" }, +] + +[[package]] +name = "typer" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/ca/950278884e2ca20547ff3eb109478c6baf6b8cf219318e6bc4f666fad8e8/typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca", size = 104755, upload-time = "2025-09-23T09:47:48.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/22/35617eee79080a5d071d0f14ad698d325ee6b3bf824fc0467c03b30e7fa8/typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9", size = 46748, upload-time = "2025-09-23T09:47:46.777Z" }, +] + +[[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-inspect" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload-time = "2024-12-22T07:47:30.032Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload-time = "2024-12-22T07:47:28.074Z" }, +] + +[[package]] +name = "uuid-utils" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/a1/822ceef22d1c139cffebe4b1b660cfaa10253d5c770aa2598dc8e9497593/uuid_utils-0.16.0.tar.gz", hash = "sha256:d6902d4375dfba4c9902c736bb82d3c040417b67f7d0fa48910ddfdb1ac95de7", size = 42596, upload-time = "2026-05-19T07:44:23.28Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/4c/b4cf43a5d22bcdb91727acdf54be0d78e83e595b73c5a9a8a4291875f059/uuid_utils-0.16.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:727fae3f0682191ec9c8ce1cd0f71e81b471a2e26b7c5fd66712fc0f11640aa0", size = 562183, upload-time = "2026-05-19T07:45:02.683Z" }, + { url = "https://files.pythonhosted.org/packages/d6/fb/4b0d1c4b5e9f8679ca41b9cdbce5749e1d5db3d3d42a07060d6ce61ac583/uuid_utils-0.16.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:66a9c8cedf7695c28e700f6a66bde0809c3b2e0d8a70968be7bfd47c908952e5", size = 289018, upload-time = "2026-05-19T07:44:07.726Z" }, + { url = "https://files.pythonhosted.org/packages/de/43/2dc6c7401c8fab86e46b0b33ada6dcfde949b2fd48877ba6f880862be80e/uuid_utils-0.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9152bff801ec2ccf630df06d67389090a2c612dea87fbf9a887ab4b222929f6f", size = 326171, upload-time = "2026-05-19T07:45:25.186Z" }, + { url = "https://files.pythonhosted.org/packages/9b/f5/48f11fb91f36453611ca148bc441436f279870b1ec6b576dc5167fb6e680/uuid_utils-0.16.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:06fc7db470c37e5c1ab3fd2cd159697d6f8b279d7d23b5b96bd418b115f8caa9", size = 332222, upload-time = "2026-05-19T07:45:09.036Z" }, + { url = "https://files.pythonhosted.org/packages/30/cb/b2b49528521e4a097f129e8bf7850a26f00af46afba778832cf3458a5c00/uuid_utils-0.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e1a1f57fe3631e164dad27b24aa81267810e20575f705af3b0fa734f3a21247", size = 444801, upload-time = "2026-05-19T07:45:37.517Z" }, + { url = "https://files.pythonhosted.org/packages/a9/b3/a28d9c6f7c701dfe01c8020b30e33899a28eb9e4d056b07e7388f50ebf67/uuid_utils-0.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ee392fe59808a731b7b6bf4d453fb6e833774921331cceae5f254d1e9c5b97d", size = 325594, upload-time = "2026-05-19T07:44:44.682Z" }, + { url = "https://files.pythonhosted.org/packages/cf/65/e1ff41dc44966e396ead86e104ba21b35ddb07ff7a64bb55013074ee77fe/uuid_utils-0.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b2e981b1258db444df4cf4bf4c79673570d081d48d35f22d0f86471e0ad795c5", size = 349312, upload-time = "2026-05-19T07:45:15.582Z" }, + { url = "https://files.pythonhosted.org/packages/ed/57/fb19b7951f66a46e03bd1943a61ee9d59c83e994e56e8c97d79aff1f0e47/uuid_utils-0.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbb92feb4db08cd76e27b4d3b1a82bfde708447317150c614eb9f761a43b387e", size = 502115, upload-time = "2026-05-19T07:43:38.756Z" }, + { url = "https://files.pythonhosted.org/packages/2f/8e/9a129c469b7b77afb62da5c6b7e92591073b845bd0c3108c0d0aa65389fb/uuid_utils-0.16.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c3c5afaaa68b1d6393d653e9fc93a2fde9da1681da01f74b4593f41d31fb5f1", size = 607433, upload-time = "2026-05-19T07:44:11.675Z" }, + { url = "https://files.pythonhosted.org/packages/4a/56/2ef71fad168cc3d894f7094fa458086c093635d7835381c91470b19c9ad3/uuid_utils-0.16.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:38126b353527c5f001e4b24db9e62351eb768d0367febcd68100a4b39a035109", size = 566076, upload-time = "2026-05-19T07:44:35.453Z" }, + { url = "https://files.pythonhosted.org/packages/95/bf/68e60ea053ca30f35df877b96001331398140d5c4983561affa1350331b1/uuid_utils-0.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41a67e546d9adf11c4e4cb5c8e81f000f8b1f000c17912ced089b499855719a5", size = 530645, upload-time = "2026-05-19T07:45:49.278Z" }, + { url = "https://files.pythonhosted.org/packages/42/19/b521f7d73094fca4c0c44002f4a42bfcbcf0b770fdc3c4b9a596dda25734/uuid_utils-0.16.0-cp312-cp312-win32.whl", hash = "sha256:52d2cc8c12a3466cd1727883e0746d8bad5dddd670369eb553ba17fdc3b565ca", size = 168887, upload-time = "2026-05-19T07:45:45.502Z" }, + { url = "https://files.pythonhosted.org/packages/87/1f/4126c3ccbc2d98a613664e55f6ab6d7bd4b98424a04486e4fcc76549af15/uuid_utils-0.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:c97625e5edfda8b118160ce1e88756f92b1635775f836c168be7bf10928d97fa", size = 174607, upload-time = "2026-05-19T07:43:52.938Z" }, + { url = "https://files.pythonhosted.org/packages/74/62/b83ccc8446ae39dcc0bda2cb3b525b6af6a2036383afe1d1d5fe7b234c2c/uuid_utils-0.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:baf79c8050eb784b252dd34807df73f61130fe8676b61231baccab62530f20ec", size = 173021, upload-time = "2026-05-19T07:45:10.204Z" }, + { url = "https://files.pythonhosted.org/packages/60/9b/74c1f47a9b4f138a254e51528e5ffaeba6bf99ecead9f0c4b6fccccfbfcb/uuid_utils-0.16.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d34cf9681e8892fad2a63e393068e544505408748cd8bf0c3517d753a01528d4", size = 563166, upload-time = "2026-05-19T07:44:10.494Z" }, + { url = "https://files.pythonhosted.org/packages/7c/1c/009e37b70f1f0ff17e7103a36bafde33d503d9ea7fe739761aa3e3c9fde6/uuid_utils-0.16.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0681d1bdb7956e0c6d581e7601dabcfb2b08c25d2a65189f4e9b102c94f5ff46", size = 289529, upload-time = "2026-05-19T07:43:54.466Z" }, + { url = "https://files.pythonhosted.org/packages/5e/5e/e0323d54321166639eb2be5e8a464f5cb0fc04d72d91f3e78944bb6a1da8/uuid_utils-0.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed45fb8732d216426227096b55accbb87cba57febc86a044d90780b090eb99d0", size = 326328, upload-time = "2026-05-19T07:45:31.901Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a3/046f6cb958467c3bf4a163a8a53b178b64a62e21ed8ad5b2c1dacb3a2cfc/uuid_utils-0.16.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b617a334bb01ef2ff8c22900f5a14125eb9063f602131494cc9dc59519beaa5b", size = 332322, upload-time = "2026-05-19T07:43:41.284Z" }, + { url = "https://files.pythonhosted.org/packages/67/80/01914e3949744db7acd0006885e5542fbebb6e39114857d007d29b3265c2/uuid_utils-0.16.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a750d8aeb8ae880aa9a2529606bde0e994bcc7448730c953107f357a28e6102e", size = 445787, upload-time = "2026-05-19T07:45:36.102Z" }, + { url = "https://files.pythonhosted.org/packages/14/ef/f6908f41279f205d70c8a0d5dcb25dd6802741d7f88e3f0123453c3584d3/uuid_utils-0.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a250e111903c4368745fce5ac2aa607bd477c62d3307e45347338fdb64b38e0", size = 324678, upload-time = "2026-05-19T07:45:12.77Z" }, + { url = "https://files.pythonhosted.org/packages/11/4a/bf841ba90f829c7779d82155e0f4b88ef6726ccc25507d064d50ac2cd329/uuid_utils-0.16.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:95b7f480010ea98a29ee809857a98aa923008c68129af1b39244adccff7377fb", size = 349704, upload-time = "2026-05-19T07:44:47.172Z" }, + { url = "https://files.pythonhosted.org/packages/e6/31/3b5c60172b8c57bf4ca485484b8e4edef550ca324f9287f1183be97422e2/uuid_utils-0.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:420aa3ca403cedb73490b6ea3aeefeea7e0455f5ce60bbf856390ee872ae3306", size = 502456, upload-time = "2026-05-19T07:45:00.821Z" }, + { url = "https://files.pythonhosted.org/packages/88/bf/3da8d497af80fd51d8bf85551c77ede67f07825924ec5987bf9b6031014a/uuid_utils-0.16.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b8a9a7b1065a12d40f2cc25b7d705ab34954cc57095034367bca39ebcf4a876b", size = 607727, upload-time = "2026-05-19T07:44:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/bd/4e/7c8cf03ec15cd6f40e4cbab81b2b4a625461327f68c7971e54723280ec3e/uuid_utils-0.16.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f235ac5827d74ac630cc87f29278cdaa5d2f273613a6e05bbd96df7aa4170776", size = 566204, upload-time = "2026-05-19T07:44:51.225Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5f/af955feae69cce7fd2121ca3f790ff4b85ad2e17b2149546f50753e1a047/uuid_utils-0.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c8083284488b84ad178e74add64cfd1e74e8be5e30821e5acbc5019281c658b0", size = 529986, upload-time = "2026-05-19T07:45:57.85Z" }, + { url = "https://files.pythonhosted.org/packages/10/cf/3fec757e51bef10eb41ae8075f5442c60e85ff456b42d16a3063f5dc6c80/uuid_utils-0.16.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:27a071a899ba46a551d6524dbbc5a98b88be176d0f55ddf72cf71c005326ac10", size = 98683, upload-time = "2026-05-19T07:44:16.369Z" }, + { url = "https://files.pythonhosted.org/packages/40/a7/cd1adbea7ef882a70db064c00cd93b12e11027b4cdd7ffd79e95c35fc3e3/uuid_utils-0.16.0-cp313-cp313-win32.whl", hash = "sha256:924a8de04460e4cf65998ad0b6568084f7c51740ebd3254d07a0bcde35a84af6", size = 168822, upload-time = "2026-05-19T07:44:24.09Z" }, + { url = "https://files.pythonhosted.org/packages/74/99/617ceb9e3a95b23837012740979baf71afad723b70daf34862da3f7c17a1/uuid_utils-0.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:5279bc7ab3c6683f1c67314695bee14d869015acbbc677bdb0015190fe753d16", size = 174967, upload-time = "2026-05-19T07:44:56.022Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d8/148ae707bfc36d482e39db679c86b81bdce264d4feb9df5d40a03b7687e3/uuid_utils-0.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:61a9c4c26ad12ac66fa4bfd0fdb8494724fe7a5b98a9fcd43e78e2b388663dbb", size = 173142, upload-time = "2026-05-19T07:43:50.171Z" }, + { url = "https://files.pythonhosted.org/packages/21/05/ca6d60705e71fdeaa3431dad94e279a8213c5573cb2925e1aabf3dc0330a/uuid_utils-0.16.0-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:73486b6aa3f755a6c97000f5ea67e7ac78d6df89bf22980789a1e943e24b74f0", size = 564408, upload-time = "2026-05-19T07:44:38.351Z" }, + { url = "https://files.pythonhosted.org/packages/eb/8c/b9a0462c38535c1662acb1025768e2d626bee5ce9e1790bad6b5381162ea/uuid_utils-0.16.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f1614572fd9345cdc3dde3f40c237345719fabca1aa87d2d87b321d523cfa34d", size = 289923, upload-time = "2026-05-19T07:45:19.611Z" }, + { url = "https://files.pythonhosted.org/packages/f2/33/a53afeef1a56051551a0f5a801e4bce411dd73c6a8c99bad16902651256d/uuid_utils-0.16.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9346ce6eb1fbd8b03a6b331d66016afcb4edcdff6eac708e21391600529a016a", size = 325762, upload-time = "2026-05-19T07:45:18.261Z" }, + { url = "https://files.pythonhosted.org/packages/72/ca/4462a4f36365d7ee72d41e05e6bcfe127e861b073ab37c25b2c8a518317c/uuid_utils-0.16.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a0fc6eb3fd821466fbab69cf356c6ec2b7327266bbbc740a2eb57c77c4bef965", size = 332359, upload-time = "2026-05-19T07:45:34.886Z" }, + { url = "https://files.pythonhosted.org/packages/c5/67/9d3373fa7c5a746fdecc64e30caf915c29eb632203508d87676f9243ed03/uuid_utils-0.16.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13a797e5e8f0dadc18351a5aa013815ddac25dce6864072a539d510910c95f71", size = 445483, upload-time = "2026-05-19T07:44:49.598Z" }, + { url = "https://files.pythonhosted.org/packages/57/08/ce01aa6d897fc7f875844fe58cad0a542c8ebf089d9242b654b56260ecb8/uuid_utils-0.16.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57c3583b1f1c00a94f59726a5e2b988fa209221143919a1af5c2fc24e318fc98", size = 326281, upload-time = "2026-05-19T07:44:59.677Z" }, + { url = "https://files.pythonhosted.org/packages/76/ef/2c719b2c26bb5b5e5061a1435c11ad2bd33ac3cd6d4cd0c7c3ac1d3396ed/uuid_utils-0.16.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:caac9c8b1d50e8fbddc76e93bfefbef472978eb45adbfdb6289d578816992953", size = 350809, upload-time = "2026-05-19T07:45:28.076Z" }, + { url = "https://files.pythonhosted.org/packages/e0/9b/c1ed447328b32229cca38ac4c62d309eab006e5e9c4020e2056a175bc607/uuid_utils-0.16.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:91db59bad97ed2b9d2c6ed25082fe9762b2c422e694fe06786b28cf4e776ac4c", size = 502088, upload-time = "2026-05-19T07:44:09.208Z" }, + { url = "https://files.pythonhosted.org/packages/c1/e0/8442f4efe7bde72f0b4ae5f675d0c7fbe209ad0b54718b8ddf43c46c6fae/uuid_utils-0.16.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:41985e342a30e76366a8becc60bbdb07d72cd1b86ec657b1f31654e9fb1baada", size = 607631, upload-time = "2026-05-19T07:44:19.384Z" }, + { url = "https://files.pythonhosted.org/packages/f1/1e/9a9fa261edf4c972f28ae83421377e3ab8dbd0bd7db58fd316e782d09a3b/uuid_utils-0.16.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1b0dcedf9266bf34a54d5cbe78648eaa627e02352f2a6923ed647530aea2f661", size = 567618, upload-time = "2026-05-19T07:43:58.478Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f7/1bcfdb9d539bd42736dd6076470a42fbb5db23f79712c0a06aa0a3752f7b/uuid_utils-0.16.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:26fe23ab60f05de4ad70aaa5b6a4c2a7bbd43055e3dd6f6b31efba0532ac9c71", size = 530971, upload-time = "2026-05-19T07:45:06.348Z" }, + { url = "https://files.pythonhosted.org/packages/24/0c/18945f417d6bb4d0dd2b7652fe36c58c4e83bcf593b9b326b83aa40b853a/uuid_utils-0.16.0-cp313-cp313t-win32.whl", hash = "sha256:7f8cf49c05d58523a0f977cb7f11afc05791a0fa164d7303b8365a34750638e7", size = 169369, upload-time = "2026-05-19T07:44:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cc/c0eb0c3fab2ed80d706369b750029143b53126809b77b36bcbb77da66bab/uuid_utils-0.16.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e99f9a8b2420b228faba23a637e96efaf5c6a678b2e225870f24431c82707f50", size = 175384, upload-time = "2026-05-19T07:45:56.623Z" }, + { url = "https://files.pythonhosted.org/packages/b7/77/50ac87b6e18b1c686f700aa38c9471a990683c6a955f71ac1a6677ed8145/uuid_utils-0.16.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6853b627983aa1b4fd95aa52d9e87136eb94a7b3b7de0fbb1db8a498d457eeec", size = 564108, upload-time = "2026-05-19T07:43:55.609Z" }, + { url = "https://files.pythonhosted.org/packages/83/16/65046676de246bb5334d9f58aa96d2feb9fc347fda3556aaff7da1c2fc7a/uuid_utils-0.16.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:f44b65ae0c329843817d9c90e36a7a3c677b413bf407c99e67db874dac49dad3", size = 289967, upload-time = "2026-05-19T07:45:38.886Z" }, + { url = "https://files.pythonhosted.org/packages/91/d6/54fa988606a15dfd2028e925d8eb9c3ee6edbf1eb7692a67b37282880b56/uuid_utils-0.16.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de8a365795a76f347f5622621c2bee543cffa0c70949f3ee093bdefc9d926dcc", size = 325835, upload-time = "2026-05-19T07:44:42.02Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1b/50622f967ceacea1f89fd065d9bfd395b51acb02cfb0a4ddc8fa9ff0c983/uuid_utils-0.16.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:426a8c9af90242d879706ccf29da56f0b0712e7739fb0bbe16baacabc75596e2", size = 332607, upload-time = "2026-05-19T07:43:42.42Z" }, + { url = "https://files.pythonhosted.org/packages/12/f5/4059706be6617e2787e375ea52994ce3c3fa3920b7d4a9c8ebf7895681a5/uuid_utils-0.16.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:833bc4b3c3fc24be541f67b01b4a75b6b9942a9b7137395b4eb35435948bd6da", size = 444287, upload-time = "2026-05-19T07:43:37.106Z" }, + { url = "https://files.pythonhosted.org/packages/65/d5/f44b2710563da687a368f0ce4dcbd462dfb6708bcd46439d831991d595c7/uuid_utils-0.16.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efb5252d7c00d586077f10e169d6e6d0b0d0f806d8a085073f0d19b4737aef4e", size = 324949, upload-time = "2026-05-19T07:45:33.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a7/a69e859e37d26c5603f0bc0ae481860f691224f140e5a832f325b804770d/uuid_utils-0.16.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b3377ce388fd7bf8d231ec9d1d4f58c8e87888ddea93581f60ed6f878a4f722", size = 349651, upload-time = "2026-05-19T07:43:59.998Z" }, + { url = "https://files.pythonhosted.org/packages/db/73/4139cd3ca7b81ea283c1c8769373e9b2008241c0744a8ffb25f0a1b31325/uuid_utils-0.16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:12b6310beb38adc173ec5dc89e98812fd7e3d98f87f3ef01d2ea6ecb5d87994f", size = 502326, upload-time = "2026-05-19T07:45:40.292Z" }, + { url = "https://files.pythonhosted.org/packages/cb/8c/858101583fbad1b3fa04da88b1f7170836aa0f00b4cb712063325c44466d/uuid_utils-0.16.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a49b5a75497643479c919e2e537a4a36224ac3aaa0fada61b75d87024021ac3e", size = 607689, upload-time = "2026-05-19T07:44:48.355Z" }, + { url = "https://files.pythonhosted.org/packages/5e/bd/8f3d54a4763dd91ebd0f3d7b0c2ec434e4e0b1fc667b03a44d611a465ec6/uuid_utils-0.16.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:63bfdf00be51b6b3b79275d6767d034ea5c7a0caa067a35d72861284100cb60a", size = 566214, upload-time = "2026-05-19T07:44:53.519Z" }, + { url = "https://files.pythonhosted.org/packages/54/76/4c9a8d9baaa243c7902d84dbba4d51b1ab51c379c66d3fd6368ff6933ecf/uuid_utils-0.16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7525bc59ac4579c32317d2493dd42cf134b9bb50cd0bc6a41dd9f77e4740dde6", size = 529989, upload-time = "2026-05-19T07:44:43.141Z" }, + { url = "https://files.pythonhosted.org/packages/6d/13/d32cea997f880cedde415730ce0e872ebfd7a040155ae0bbda70eccd208e/uuid_utils-0.16.0-cp314-cp314-win32.whl", hash = "sha256:fbcac6e6710aa2e4bfbb81762758e01470dc56d5048ba4253acc77c9833568ff", size = 169146, upload-time = "2026-05-19T07:45:46.655Z" }, + { url = "https://files.pythonhosted.org/packages/1c/19/9fc55172d8fe59e1f27a14d598b427fa508a7ebb35fa7b7b99c24fa0ef13/uuid_utils-0.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:d23fcaf37368a1647319187ef6f8b741bf079f033065899bc2d00a44b0a1214a", size = 175364, upload-time = "2026-05-19T07:45:55.335Z" }, + { url = "https://files.pythonhosted.org/packages/89/5d/fcd9226b715c5aa0638fcdd6deaf0de6c6c3c451c692cd76bfca810c6512/uuid_utils-0.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:ea3265f8e2b452a4870f3298cb1d183dc4e36a3682cbb264dbe46af31267e706", size = 173268, upload-time = "2026-05-19T07:44:31.19Z" }, + { url = "https://files.pythonhosted.org/packages/c1/64/97ec9af95e58b8187f2934008ffab26e1604d149e34fe01c388b0543a24f/uuid_utils-0.16.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:99f8420c3ed59f89a086782ac197e257f4b1debb4545dffa90cf5db23f96c892", size = 564464, upload-time = "2026-05-19T07:44:40.856Z" }, + { url = "https://files.pythonhosted.org/packages/3e/6d/e4082f407484ac28923c0bf8e861e71d277118d8b7542d0a350340e45350/uuid_utils-0.16.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:259bab73c241743d684dcc3507feb76f484d720545e4e4805582aeff8e19700b", size = 290087, upload-time = "2026-05-19T07:44:01.084Z" }, + { url = "https://files.pythonhosted.org/packages/8c/43/c5c5f273c0ff889f20f10344784f9197dd00eb81ccc294330d4b949fea7e/uuid_utils-0.16.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:897e8ef0dc5e4ac0b17cf9cae84bb41e560d806280ec5b93db7475b504022105", size = 325532, upload-time = "2026-05-19T07:43:47.508Z" }, + { url = "https://files.pythonhosted.org/packages/13/7f/669aa899ab5378374d28a28231e6978f739921a1af394c7ebd6cc86e2639/uuid_utils-0.16.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c5af79cde16a7600dfccb7d431aec0afd3088ff170b6a09887bf3f7ab3cc7c81", size = 332209, upload-time = "2026-05-19T07:43:51.528Z" }, + { url = "https://files.pythonhosted.org/packages/2b/57/a2a32406d79a222794ef98a19254fd9a81a029a0f32d7740fba9873bff1f/uuid_utils-0.16.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bece1a6f677ca36047442c465d8166643eed9818b9e43e0bf42d3cf73e92dcff", size = 445507, upload-time = "2026-05-19T07:44:20.541Z" }, + { url = "https://files.pythonhosted.org/packages/26/6b/85459a35bfa7d73e79acbc4eab1cf6aa6e4d9d022c3260ed9dea539c7f0b/uuid_utils-0.16.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb3444498e7b099499c8a607d7771377020fa55f7274e46f54106af19f752d7", size = 326154, upload-time = "2026-05-19T07:45:23.587Z" }, + { url = "https://files.pythonhosted.org/packages/84/9e/e965efdbb503ed14d6e57aec1a22b98326ed24cc2fb48e750c4d192267a0/uuid_utils-0.16.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:542098f6cb6874aebeff98715f3ab7646fbe0f2ffb24509ca372828c68c4ed0e", size = 350905, upload-time = "2026-05-19T07:44:36.957Z" }, + { url = "https://files.pythonhosted.org/packages/23/ae/4321867888a783d03b7c053c0b68ca45d03974d86fcebf44d4ec268db397/uuid_utils-0.16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7207b25fe534bcf4d57e0110f90670e61c1c38b6f4598ba855af69ab428fc118", size = 502098, upload-time = "2026-05-19T07:44:17.696Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9a/914a47bf42479bff0ce3e1fa1cbe3585354708edc928e27687cf91de9c26/uuid_utils-0.16.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:16dc5c6e439f75b0456114e955983e2156c1f38887733e54d54205d3005223e4", size = 607032, upload-time = "2026-05-19T07:44:22.151Z" }, + { url = "https://files.pythonhosted.org/packages/85/4c/2abacd6badba61a047eaa39c8347656229d12843bd9bbe4906daa6dc752c/uuid_utils-0.16.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6d3ee32c57898d8415242b08d5dd086bc4f7bcbbb3fc102ef257f3d793eb294", size = 567664, upload-time = "2026-05-19T07:45:21.043Z" }, + { url = "https://files.pythonhosted.org/packages/53/1f/9d1a09521276424da19dc0d74456aed3311170fec181b28fa6acba45d963/uuid_utils-0.16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7555f120a2282d1901c9a632c2398a614101af4fe3f7c8114aa0f1d8c1978855", size = 530996, upload-time = "2026-05-19T07:45:44.229Z" }, + { url = "https://files.pythonhosted.org/packages/b4/22/14dbedb6b61f492d5524077fd10bbfb137583b0f0aafa6cd870ccb43f39a/uuid_utils-0.16.0-cp314-cp314t-win32.whl", hash = "sha256:756575d082ea4cb7d2f923d5b640c0efe7c82573aab49220c4e09b62d13737ff", size = 169358, upload-time = "2026-05-19T07:45:05.146Z" }, + { url = "https://files.pythonhosted.org/packages/25/f4/a636806c98401a1108f2456e9cc3fa39a618145bfb1d0860c57203159cfe/uuid_utils-0.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:aa50261a83991dbb570a00573741455bd8f3249444f7329e5bdcd494799d1504", size = 174813, upload-time = "2026-05-19T07:45:59.579Z" }, + { url = "https://files.pythonhosted.org/packages/75/12/3823742459d87a100deb24bb6b41692aa961b267abd130fa7739cdf7d409/uuid_utils-0.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:22a17e93a371d850ffce8fcdbacc2239f890efe73aa3262b6170c1febc08afe1", size = 171733, upload-time = "2026-05-19T07:45:29.283Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/57/1616c8274c3442d802621abf5deb230771c7a0fec9414cb6763900eb3868/uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13", size = 80367, upload-time = "2025-09-23T13:33:47.486Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/cd/584a2ceb5532af99dd09e50919e3615ba99aa127e9850eafe5f31ddfdb9a/uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c", size = 67976, upload-time = "2025-09-23T13:33:45.842Z" }, +] + +[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/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 = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + +[[package]] +name = "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/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" }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, +] + +[[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/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 = "xxhash" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914, upload-time = "2025-10-02T14:34:38.6Z" }, + { url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163, upload-time = "2025-10-02T14:34:39.872Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411, upload-time = "2025-10-02T14:34:41.569Z" }, + { url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883, upload-time = "2025-10-02T14:34:43.249Z" }, + { url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392, upload-time = "2025-10-02T14:34:45.042Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898, upload-time = "2025-10-02T14:34:46.302Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655, upload-time = "2025-10-02T14:34:47.571Z" }, + { url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001, upload-time = "2025-10-02T14:34:49.273Z" }, + { url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431, upload-time = "2025-10-02T14:34:50.798Z" }, + { url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617, upload-time = "2025-10-02T14:34:51.954Z" }, + { url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534, upload-time = "2025-10-02T14:34:53.276Z" }, + { url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876, upload-time = "2025-10-02T14:34:54.371Z" }, + { url = "https://files.pythonhosted.org/packages/33/76/35d05267ac82f53ae9b0e554da7c5e281ee61f3cad44c743f0fcd354f211/xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec", size = 32738, upload-time = "2025-10-02T14:34:55.839Z" }, + { url = "https://files.pythonhosted.org/packages/31/a8/3fbce1cd96534a95e35d5120637bf29b0d7f5d8fa2f6374e31b4156dd419/xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1", size = 30821, upload-time = "2025-10-02T14:34:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ea/d387530ca7ecfa183cb358027f1833297c6ac6098223fd14f9782cd0015c/xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6", size = 194127, upload-time = "2025-10-02T14:34:59.21Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/71435dcb99874b09a43b8d7c54071e600a7481e42b3e3ce1eb5226a5711a/xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263", size = 212975, upload-time = "2025-10-02T14:35:00.816Z" }, + { url = "https://files.pythonhosted.org/packages/84/7a/c2b3d071e4bb4a90b7057228a99b10d51744878f4a8a6dd643c8bd897620/xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546", size = 212241, upload-time = "2025-10-02T14:35:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/81/5f/640b6eac0128e215f177df99eadcd0f1b7c42c274ab6a394a05059694c5a/xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89", size = 445471, upload-time = "2025-10-02T14:35:03.61Z" }, + { url = "https://files.pythonhosted.org/packages/5e/1e/3c3d3ef071b051cc3abbe3721ffb8365033a172613c04af2da89d5548a87/xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d", size = 193936, upload-time = "2025-10-02T14:35:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/2c/bd/4a5f68381939219abfe1c22a9e3a5854a4f6f6f3c4983a87d255f21f2e5d/xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7", size = 210440, upload-time = "2025-10-02T14:35:06.239Z" }, + { url = "https://files.pythonhosted.org/packages/eb/37/b80fe3d5cfb9faff01a02121a0f4d565eb7237e9e5fc66e73017e74dcd36/xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db", size = 197990, upload-time = "2025-10-02T14:35:07.735Z" }, + { url = "https://files.pythonhosted.org/packages/d7/fd/2c0a00c97b9e18f72e1f240ad4e8f8a90fd9d408289ba9c7c495ed7dc05c/xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42", size = 210689, upload-time = "2025-10-02T14:35:09.438Z" }, + { url = "https://files.pythonhosted.org/packages/93/86/5dd8076a926b9a95db3206aba20d89a7fc14dd5aac16e5c4de4b56033140/xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11", size = 414068, upload-time = "2025-10-02T14:35:11.162Z" }, + { url = "https://files.pythonhosted.org/packages/af/3c/0bb129170ee8f3650f08e993baee550a09593462a5cddd8e44d0011102b1/xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd", size = 191495, upload-time = "2025-10-02T14:35:12.971Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3a/6797e0114c21d1725e2577508e24006fd7ff1d8c0c502d3b52e45c1771d8/xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799", size = 30620, upload-time = "2025-10-02T14:35:14.129Z" }, + { url = "https://files.pythonhosted.org/packages/86/15/9bc32671e9a38b413a76d24722a2bf8784a132c043063a8f5152d390b0f9/xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392", size = 31542, upload-time = "2025-10-02T14:35:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/39/c5/cc01e4f6188656e56112d6a8e0dfe298a16934b8c47a247236549a3f7695/xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6", size = 27880, upload-time = "2025-10-02T14:35:16.315Z" }, + { url = "https://files.pythonhosted.org/packages/f3/30/25e5321c8732759e930c555176d37e24ab84365482d257c3b16362235212/xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702", size = 32956, upload-time = "2025-10-02T14:35:17.413Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3c/0573299560d7d9f8ab1838f1efc021a280b5ae5ae2e849034ef3dee18810/xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db", size = 31072, upload-time = "2025-10-02T14:35:18.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1c/52d83a06e417cd9d4137722693424885cc9878249beb3a7c829e74bf7ce9/xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54", size = 196409, upload-time = "2025-10-02T14:35:20.31Z" }, + { url = "https://files.pythonhosted.org/packages/e3/8e/c6d158d12a79bbd0b878f8355432075fc82759e356ab5a111463422a239b/xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f", size = 215736, upload-time = "2025-10-02T14:35:21.616Z" }, + { url = "https://files.pythonhosted.org/packages/bc/68/c4c80614716345d55071a396cf03d06e34b5f4917a467faf43083c995155/xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5", size = 214833, upload-time = "2025-10-02T14:35:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e9/ae27c8ffec8b953efa84c7c4a6c6802c263d587b9fc0d6e7cea64e08c3af/xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1", size = 448348, upload-time = "2025-10-02T14:35:25.111Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6b/33e21afb1b5b3f46b74b6bd1913639066af218d704cc0941404ca717fc57/xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee", size = 196070, upload-time = "2025-10-02T14:35:26.586Z" }, + { url = "https://files.pythonhosted.org/packages/96/b6/fcabd337bc5fa624e7203aa0fa7d0c49eed22f72e93229431752bddc83d9/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd", size = 212907, upload-time = "2025-10-02T14:35:28.087Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d3/9ee6160e644d660fcf176c5825e61411c7f62648728f69c79ba237250143/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729", size = 200839, upload-time = "2025-10-02T14:35:29.857Z" }, + { url = "https://files.pythonhosted.org/packages/0d/98/e8de5baa5109394baf5118f5e72ab21a86387c4f89b0e77ef3e2f6b0327b/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292", size = 213304, upload-time = "2025-10-02T14:35:31.222Z" }, + { url = "https://files.pythonhosted.org/packages/7b/1d/71056535dec5c3177eeb53e38e3d367dd1d16e024e63b1cee208d572a033/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf", size = 416930, upload-time = "2025-10-02T14:35:32.517Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6c/5cbde9de2cd967c322e651c65c543700b19e7ae3e0aae8ece3469bf9683d/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033", size = 193787, upload-time = "2025-10-02T14:35:33.827Z" }, + { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, + { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754, upload-time = "2025-10-02T14:35:38.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846, upload-time = "2025-10-02T14:35:39.6Z" }, + { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343, upload-time = "2025-10-02T14:35:40.69Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074, upload-time = "2025-10-02T14:35:42.29Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388, upload-time = "2025-10-02T14:35:43.929Z" }, + { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614, upload-time = "2025-10-02T14:35:45.216Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024, upload-time = "2025-10-02T14:35:46.959Z" }, + { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541, upload-time = "2025-10-02T14:35:48.301Z" }, + { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305, upload-time = "2025-10-02T14:35:49.584Z" }, + { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848, upload-time = "2025-10-02T14:35:50.877Z" }, + { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142, upload-time = "2025-10-02T14:35:52.15Z" }, + { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547, upload-time = "2025-10-02T14:35:53.547Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214, upload-time = "2025-10-02T14:35:54.746Z" }, + { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290, upload-time = "2025-10-02T14:35:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795, upload-time = "2025-10-02T14:35:57.162Z" }, + { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955, upload-time = "2025-10-02T14:35:58.267Z" }, + { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072, upload-time = "2025-10-02T14:35:59.382Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579, upload-time = "2025-10-02T14:36:00.838Z" }, + { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854, upload-time = "2025-10-02T14:36:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965, upload-time = "2025-10-02T14:36:03.507Z" }, + { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484, upload-time = "2025-10-02T14:36:04.828Z" }, + { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162, upload-time = "2025-10-02T14:36:06.182Z" }, + { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007, upload-time = "2025-10-02T14:36:07.733Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956, upload-time = "2025-10-02T14:36:09.106Z" }, + { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401, upload-time = "2025-10-02T14:36:10.585Z" }, + { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083, upload-time = "2025-10-02T14:36:12.276Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913, upload-time = "2025-10-02T14:36:14.025Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586, upload-time = "2025-10-02T14:36:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526, upload-time = "2025-10-02T14:36:16.708Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898, upload-time = "2025-10-02T14:36:17.843Z" }, +] + +[[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/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" }, +] + +[[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" }, +] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, + { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" }, + { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" }, + { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" }, + { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" }, + { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" }, + { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" }, + { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" }, + { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" }, + { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, + { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, +] diff --git a/data/book/README.md b/data/book/README.md new file mode 100644 index 0000000..4c90da9 --- /dev/null +++ b/data/book/README.md @@ -0,0 +1,58 @@ +# 国土空间规划:概念、原理、方法 - LaTeX版本 + +## 文件结构 + +``` +book/ +├── main.tex # 主LaTeX文件 +├── abstract.tex # 内容提要 +├── preface.tex # 前言 +├── chapter01.tex # 第一章:生态文明下的人居环境和国土空间 +├── chapter02.tex # 第二章:自然资源与土地利用 +├── chapter03.tex # 第三章:城乡空间规划思想与理论发展 +├── chapter04.tex # 第四章:国土空间规划基本原理与体系构成 +├── chapter05.tex # 第五章:国土空间规划的技术工具与方法 +└── README.md # 本文件 +``` + +## 编译说明 + +### 使用XeLaTeX编译(推荐) + +```bash +xelatex main.tex +xelatex main.tex # 第二次编译以生成目录 +``` + +### 使用pdfLaTeX编译 + +```bash +pdflatex main.tex +pdflatex main.tex # 第二次编译以生成目录 +``` + +## 注意事项 + +1. **中文字体**:本文件使用`ctex`宏包处理中文,需要确保系统安装了中文字体。 + +2. **图片路径**:如果需要在文档中插入图片,请将图片文件放在`book`目录下,并在LaTeX文件中使用相对路径引用。 + +3. **表格**:文档中的表格引用(如"见表1.1")需要手动转换为LaTeX表格格式。 + +4. **参考文献**:主文件中已注释掉参考文献部分,如需添加,请创建`references.bib`文件并取消注释。 + +## 转换说明 + +- 所有Word文档已转换为LaTeX格式 +- 章节标题已清理,移除了手动编号(LaTeX会自动编号) +- 保留了基本的段落结构和格式 +- 表格和图片需要手动处理 + +## 后续优化建议 + +1. 添加图片引用:将图片文件转换为PDF或PNG格式,并在相应位置添加`\includegraphics`命令 +2. 格式化表格:将文档中的表格描述转换为LaTeX表格格式 +3. 添加交叉引用:使用`\label`和`\ref`命令添加交叉引用 +4. 优化格式:根据需要调整字体、行距、页边距等格式设置 + + diff --git a/data/book/abstract.tex b/data/book/abstract.tex new file mode 100644 index 0000000..c2fb8a7 --- /dev/null +++ b/data/book/abstract.tex @@ -0,0 +1,8 @@ +\textbf{内容提要} + +国土空间规划是我国空间规划体系的历史性变革,是对各类传统空间规划编制体系的整合和系统性的重构,是推进生态文明建设,落实治国理政理念,提升国土空间效能,服务人居环境发展的重要的公共政策和技术性的工具。 + +本书基于“新工科”研究成果,将国土空间相关概念解析和有关规划原理以“多规合一”为目标进行梳理,形成聚焦性的国土空间规划原理核心内容,并以人居环境学科与国土空间规划互动互融为前提,梳理城乡规划空间理论,讲解国土空间规划体系构成及“双评价、一张图”等技术内容,以期为国土空间规划实践和教学研究提供参考与借鉴。 + +本书适合从事国土空间规划相关领域的研究、实践以及与国土空间有关的国土自然资源管理、发展与改革、生态环境保护部门等的技术管理人员阅读和参考,也可作为高等院校相关本科与研究生的教学参考用书。 + diff --git a/data/book/chapter01.tex b/data/book/chapter01.tex new file mode 100644 index 0000000..bc25eab --- /dev/null +++ b/data/book/chapter01.tex @@ -0,0 +1,480 @@ +\chapter{生态文明下的人居环境和国土空间} +“生态兴则文明兴,生态衰则文明衰” 生态环境是人类生存和发展的根基,生态环境变化直接影响到文明兴衰演替,生态文明建设是关系中华民族永续发展的根本大计,是我国持续发展最为重要的基础,同理,国土资源是经济社会发展的重要物质基础,国土空间规划,就是要促进国土资源的合理利用和格局优化,满足社会发展与生态保护的要求,实现国土空间可持续发展,在人居环境科学理论的框架下,国土空间规划重点聚焦于“生态、资源、环境、安全”这些约束条件,是实现以人民为中心的“五位一体”发展目标的战略选择和重要路径。 + +\section{我国人居环境发展历程} +\subsection{原始时期} +人类最初主要依附于自然,以自然的采集和狩猎、穴居和巢居为主要生活方式,随着人类的不断进化和发展,石器制作技术的提高以及农业大发展,逐渐产生原始固定的居民点村落。村落聚族而居,开始有了统一的规划并十分注重防御,由于生产与生活的需要,村落产生了简单的分区,形成相对清晰的居住区、墓葬区和陶窑区等(见表1.1)。 + +表1. 1原始时期人居环境发展情况 +\begin{table}[H] + \centering + \begin{tabular}{|c|c|c|} + \hline + 时期 & 物质生产方式 & 人居环境情况 \\ + \hline + 旧石器时代 & 采摘和狩猎为主 & 生活完全依附于自然,穴居或树居 \\ + 中石器时代 & 农业出现,农业与畜牧业及狩猎业分开 & 农业为主的固定居民点—原始的村落 \\ + 新石器时代 & 农业为主兼营渔猎 & 简单分区,聚族而居 \\ + \hline + \end{tabular} + \end{table} + +\subsection{古代时期} +中国古代人居环境的发展,与中国奴隶社会及封建社会整个时期中社会经济的发展和特点紧密结合,人居模式随着时代的变迁发生了巨大的变革(见表1.2)。 + +表1. 2古代时期人居环境发展情况(根据吴良镛先生的人居环境史绘制) + +\subsection{近代时期} +近代以来,特别是鸦片战争后,以租界出现、城墙拆毁为特征,城市开始出现,现代意义的城市化也从此启动。近代社会大转型进程中,中国人居建设步履艰难,险阻迭起,前路漫漫。但仍有难能可贵的艰难探索与独特创造,如“中国近代第一城”的南通,“新新世界雏形”淮南地区兴办垦牧公司,重庆北碚营卫星城。中国园林也进入继承、蜕变时期,作为广大公共生活之必需,发挥游憩作用并形成了租界园林、教堂园林、别墅园林、铁路园林等。中国民族形式在建筑现代化进程中成功运用,如南京中山陵、广州中山纪念堂等。 + +城市是社会经济的重要产物,社会的发展变革使城市发生不同内容和形式的变化(见表1.3)。近代以来中国农村经济社会在内忧外患中发展,传统的田园诗般的古朴生活状态被打破,出现了严重衰落。人们开始“救济乡村”“复兴乡村”,20世纪20年代末30年代初,华东华北和华中自下而上地广泛开展乡村社会学习和社会改良运动,通过兴办教育、改良农业、流通金融、提倡合作、办理地方自治与自卫,建立公共保障制度,实现“民族再造”和“民族自救”。 + +表1. 3近代城市发展类型 + +\subsection{现代时期} +现代时期的人居环境建设,以工业发展和五年计划实施为中心,使我国城乡发展产生了巨大的变化,以城市规划工作视角总结,能够比较全面地了解这一发展阶段。 + +\subsubsection{1.城市建设起步和规划初创(1949-1978年)} +随着社会主义新制度的建立,党中央提出了“必须用极大的努力去学会管理城市和建设城市”以及“城市建设为生产服务,为劳动人民生活服务”等论述,为制定新中国城市建设方针奠定了思想基础。 + +1949到20世纪60年代,呈现了包括长春第一汽车厂在内的156项工业基地建设等一系列建设成就,中国人居取得了长足的进步,人居建设实践出现了人民公社、农业学大寨等模式。鉴于大庆油田建设的成功,在“消除三大差别”、“走非工业化城市发展道路”等极左思潮影响下,城市的作用一度受到否定,这一时期中国最根本的问题就是如何解决吃饭问题,如何实现农业快速发展并为工业化奠定基础和提供保障。我国采取了城乡“剪刀差”的做法,即在“工业导向、城市偏向”的整体发展战略和“挖乡补城、以农哺工”的资金积累模式下,发展农业的意义除了解决吃饭问题之外,更重要的是为工业化提供积累和降低成本。由此导致了农村经济体制和城乡关系的变迁,逐步建立起农业支持工业、农村支持城市、城乡分隔的“二元”经济与社会体制,城镇化进程相当缓慢。20世纪的后半叶,中国进入一个新的历史时期。新中国成立初期提出要“变消费城市为生产城市”,为落实第二个五年计划中大规模工业建设项目,在区域范围内联合选厂,建设城市与工业镇,建立制度等,那段时间被称为“城市规划的春天”。 + +(1)城市建设的恢复(1949—1952年) + +解放初期的大多数城市,工业基础薄弱,布局极不合理;市政设施及福利事业不足,居住条件恶劣;城市化程度很低,发展也不平衡,内地许多城镇还停留在封建时代,根本没有现代工业与设施。在城市建设方面恢复、扩建和新建了一些工业;整治城市环境,初步改变了全国城市的环境面貌;维修、改建、新建住宅,改善劳动人民的居住条件;整修城市道路,增设公共交通,改善供水、供电等设施。由于经济能力所限,这一时期较为重点的城市建设,主要是一些大城市内的棚户区改造与工人新村的规划建设,如上海的肇嘉浜、北京的龙须沟、天津的墙子河等,上海新建了第一个完整的工人居住区——曹杨新村,天津在中山门、西南楼、唐家口等地修建了工人新村。 + +随着城市建设的恢复与发展,1952年建工部组织召开了第一次城市建设座谈会,会议提出城市建设要根据国家的长期计划,针对不同城市有计划有步骤地进行新建或改建,加强规划设计工作和统一领导,克服盲目性,以适应大规模经济建设的需要。会议决定从中央到地方建立健全管理机构;各城市都要开展城市规划;划定城市建设范围;对城市分类排队,中国开始了重点工业的城市发展规划和城市建设。 + +经过三年的调整恢复与发展,至1952年设市城市为160个,比1949年增加了17.6\%,城市人口及其分布都有了很大变化。新中国的人居环境建设,开始步入了一个以工业城市为目标进行规划建设的新阶段。 + +(2)城市规划的引入与发展(1953-1957年) + +这一时期是中国的第一个国民经济五年计划时期,国家急需建立城市规划体系。为此引入了“苏联模式”的规划方式,这一时期城市规划与建设工作奠定了中国城市规划与建设事业的开创性基础。“城市规划”用语得以统一;确立了以工业化为理论基础、以工业城市和社会主义城市为目标的城市规划学科,并建立了与之相应的规划建设机构,设置了城市规划专业,积累和培养一支城市规划专业队伍;随着大规模工业建设及手工业和工商业的社会主义改造,而进行的城市建设,是中国历史上前所未有的。 + +由于全面学习前苏联,包括与计划体制相适应的一整套城市规划理论与方法,使中国现代的城市规划与建设,具有严格的计划经济体制特征,也带有一些“古典形式主义”的色彩。在城市规划中强调平面构图、立体轮廓,讲究轴线、对称、放射路、对景、双周边街坊街景等古典形式主义手法;城市建设也一度出现了“规模过大、占地过多、求新过急、标准过高”的所谓“四过”现象,忽视工程经济等问题。 + +1954年建筑工程部组织召开了全国第一次城市建设会议,这次会议检查了过去城市建设工作中盲目、分散建设的缺点与错误,明确了城市建设必须贯彻国家过渡时期的总路线和总任务,为国家社会主义工业化、为生产、为劳动人民服务,采取与工业建设相适应的重点建设,稳步前进的方针。这次会议提出,第一个五年计划期间,城市建设必须把力量集中在“141”项工程所在地的重点工业城市,确保这些重要工业建设的顺利完成。在重点工业城市,市政建设也应把力量集中在工业区以及配合工业建设的主要工程项目上。除北京积极建设外,包头、太原、兰州、西安、武汉、洛阳、成都等是“一五”计划的重点工业城市,必须采取积极步骤,使城市建设工作能赶上工业建设的需要。上海、鞍山、沈阳、广州等城市,过去有一定工业基础和一些近代化市政设施,今后还要建设一些新的工业,城市建设可以进行必要的改建和扩建。会议还建议中央人民政府成立城市建设委员会或城市建设部,负责领导全国城市建设工作。 + +1953-1957年,中国成功地执行了发展国民经济的第一个五年计划。其建设的突出特点有三:一是按照社会主义有可能把有限的资金尽最大可能集中起来使用的原则,由国家来统一安排建设计划;二是针对旧中国许多工业行业都是空白的特点,计划优先安排这些空白工业产业的项目;三是把多数建设项目安排在内地,改变原有工业生产集中在沿海的布局。因此,一五期间共安排大中型工业建设项目825项,其中包括苏联援建的156项。 + +(3)城市规划的动荡与中断(1958-1978年) + +1958年大批劳动力涌向城市,出现了一次城市化高峰。许多城市为适应工业发展的需要,迅速编制、修订城市规划。于是,城市人口骤增,城市数量迅速增多;城市和农村工业遍地开花,在天津、上海、南京、南昌等大城市中,规划建设了大量卫星城。 + +由于这种所谓“快速规划”、“人民公社规划”等空想主义思潮的影响,导致了城市布局混乱。由于工业建设的盲目冒进,各城市不切实际地扩大城市规模,发展大城市,建设一条街,急于改变城市面貌,并借国庆十周年之际,盲目过早地改建旧城,不顾财力,大建楼堂馆所等。 + +1960年建筑工程部党组就城市规划问题向中央提交报告,提出今后城市建设的基本方针应以发展中小城市为主,尽可能地把城市搞得好些、美些,努力实现城市园林化。 + +1960-1962年是中国的三年困难时期,“三年不搞城市规划”的决策,不仅对过去几年不切实际的城市规划无从补救,而且导致规划机构撤并、人员下放,城市规划事业大为削弱,许多城市又进入无规划的混乱自发建设状况。1961年,国家提出“调整、巩固、充实、提高”的八字方针,作出了调整城市工业项目、压缩城市人口、撤销部分市镇建制等决策,全国设计革命领导小组,认为城市规划“只考虑远景,不照顾现实,规模过大”,又一次否定城市规划。 + +1964年在内地建设上实行“山、散、洞”的“三线”建设方针,无视城市规划的合理布局,在城市建设上采取的是一种“不要城市、不要规划的分散主义”做法。 + +1966年城市规划及建设被迫处于停滞甚至中断状态。至1968年全国许多城市的规划机构被撤销,人员下放,资料散失,学科专业停办,致使城市规划基本停顿,城市建设和管理呈现无政府主义状态,名胜古迹和园林绿地被侵占、破坏,违章建筑泛滥,城市布局混乱,造成了许多无法挽救的损失和后遗症。从1966年至1971年,“三线”建设进入高峰时期。这一时期建设的工厂,统统安排在山沟和山洞里,不但不建城市,而且要求新厂建设消除工厂的特征,实行厂社结合。要求城市向农村看齐,消灭城乡差别。由于这种错误指导思想的影响,有的城市根本不设立城市建设投资。 + +1971年周恩来主持中央日常工作,城市规划与建设工作开始出现转机,这一年在北京召开了城市建设会议,决定恢复城市规划机构,重新编制规划。1973年,《关于加强城市规划工作的意见》、《关于编制与审批城市规划工作的暂行规定》、《城市规划居住区用地控制指标》等几个文件草稿征求意见,并于1974年试行。1975年召开了小城镇规划建设座谈会,研究了建设小城镇的方针政策,推动了城市规划和城市建设工作。 + +\subsubsection{2. 城市建设的全面恢复和发展(1979—2000年)} +1978年改革开放后,国家大规模恢复建设,经济社会发生了深刻的变化,实现了持续稳定的快速发展。城市规划也步入了崭新的阶段。 + +这一时期城市人口增长迅速。1953年第一次人口普查时城市化水平为13.26\%,而1982、1990、2000年的第三、四、五次人口普查显示,城市化水平分别为20.60\%、26.23\%和36.09\%。1950年50万人口以上的大城市为13个,1980、1990和2000年分别增长为45个、59个和93个:20万至50万人口的中等城市则从22个,分别增长为70个、117个和218个。 + +1980年代改革开放的初期,从农村改革到城市改革,在不断地探索和推进过程中,自下而上地形成以乡镇企业和小城镇建设为基础的大规模城镇化进程;1990年代后,社会主义市场经济逐步确立,小城镇、大城市及开发区的全面迅速发展,我国人居环境发展进入一个全新的历史时期。 + +(1)1980年代的改革和恢复 + +随着经济体制改革从计划经济走向社会主义市场经济,城市与城市规划发展面临新的形势。 + +1978年3月,国务院召开第三次城市工作会议,制定了《关于加强城市建设工作的意见》,制定了一系列城市规划及其建设的方针、政策以及关键问题。强调城市在国民经济中的重要地位和作用,提出控制大城市规模,多搞小城镇,要求认真编制和修订城市总体规划、近期规划和详细规划等,城市规划工作重新走上正轨。这一时期是中国城市规划迅速发展阶段,可以称为开放式的规划时期,是中国内地城市规划的第二个春天。 + +1979年全面开展了城市规划的准备工作,国家建委起草了《中华人民共和国城市规划法草案》、《关于发展小城镇的意见》、《关于城镇建设用地综合开发的试行办法》、《关于征收城镇土地使用费的意见》等文件。国务院批准兰州市和呼和浩特市的总体规划,这是自第一个五年计划以来,国家重新审批城市规划的第一批城市,是城市规划工作重新步入正轨的重要标志。 + +1980年全国城市规划工作会议批判了不要城市规划和忽视城市建设的错误,提出了“控制大城市规模、合理发展中等城市、积极发展小城市”的城市建设方针,这次会议讨论通过了《城市规划法草案》,在现代中国的城市规划事业的发展历程中,占有重要的地位。同年正式颁布了《城市规划编制审批暂行办法》和《城市规划定额指标暂行规定》,使全国制定城市规划拥有了新的技术性法规。 + +1984年国务院颁发《城市规划条例》,这是我国城市建设和城市规划方面的第一部基本法规,同年中国建筑学会召开主题为“居住区环境规划”大会。 + +1985年科学家钱学森在致《新建筑》编辑部的信中提出“构建园林城市”设想。1990年,他又明确指出“城市规划立意要尊重生态环境,追求山环水绕的境界”。1992年10月他再次呼吁:“把整个城市建成一座大型园林”,我称之为‘山水城市、人造山水’。 + +1986年国务院在北京召开全国城市建设工作会议,这是继1978年第三次全国城市工作会议以来,国务院召开的专门研究城市建设问题的又一次重要会议。1986年公布了38个第二批历史文化名城,还公布了第一次全国城镇房屋普查结果,城乡建设环境保护部和国家统计局发布了第一次全国城镇房屋普查结果,其统计数字表明,我国28个省、自治区、直辖市的城镇普查范围内共有房屋建筑面积46.76亿平方米,其中323个市(不含市属县)有房屋28.33亿平方米,占60%,城市居民的居住水平略低于县镇。截至1986年底,全国有96\%的设市城市和85\%的县镇编制完成了城市总体规划,以2000年为期的城市总体规划在全国范围内已基本完成,以此为标志,我国的城市规划工作进入了一个新的历史发展阶段。 + +1989年12月全国人大通过了《城市规划法》,城市规划法是我国在城市规划、城市建设和城市管理方面的第一部法律,是城市建设的龙头。 + +城市规划及城市建设经济得到全面规划,并稳步开启法制的轨道,这一时期城市规划的内容在深度、广度上都有重大变革,规划思想的进一步丰富完善,为城市开放探索新的转折点做好了准备。 + +(2)1990年代的探索和发展 + +90年代邓小平主席发表了重要的南巡讲话和党的十四大决定建立社会主义市场经济体制以后,城市规划开创了一个全面宽敞的开放式城市规划体系,城市建设进入一个更快的发展阶段。 + +1991年第二次全国城市规划工作会议在北京举行。深圳被联合国授予人居奖。1993年由中国城市规划学会理事长、清华大学教授吴良镛先生主持设计建设的北京菊儿胡同四合院工程荣获1992年度的“世界人居奖”。 + +1993年建设部的全国农村建设工作会议,提出了20世纪末中国小城镇建设发展目标,随后经国务院同意颁发的《关于加强小城镇建设的若干意见》、《小城镇综合改革试点指导意见》(1995年4月)、《小城镇户籍管理制度改革试点方案》(1997年6月)等,从政策上对小城镇户籍管理制度、农村人口在小城镇就业和居住进行了适当改革和调整。 + +1998年的十五届三中全会《中共中央关于农业和农村工作若干重大问题的决定》,指出“发展小城镇,是带动农村经济和社会发展的一个大战略”。小城镇迅速发展,一些地方的小城镇已经成长为中小城市,成为农村生产、服务、文化、教育和信息中心,对带动农村发展发挥着重要作用,目前,小城镇的格局基本形成。中国第一份人类发展报告《中国人类发展报告1997》在北京发表。标志中国建筑史学走向世界的“第一届中国建筑史学国际研讨会”在北京举行,大会的主题为“人为环境与自然环境的融合”。 + +\subsubsection{3.新世纪城镇化高速发展期(2000-2016年)} +(1)城乡统筹发展——2000-2011年 + +2000年建设部下发《关于设立“中国人居环境奖”的通知》(建城〔2000〕93号),正式设立“中国人居环境奖”(含“中国人居环境范例奖”)。该奖是全国人居环境建设领域的最高荣誉奖项,在推动我国城市建设和管理事业发展上发挥了重要作用,同年建设部制定印发《创建国家园林城市实施方案》和《国家园林城市标准》。 + +2003年,党的十七大报告中提出了“科学发展观”这一理论。科学发展观的核心是以人为本,人是自然界的一部分,生态环境是人类生存的基础,良好的生态环境是实现人的全面发展的必然追求。科学发展观的基本要求是全面协调可持续,坚持把社会主义经济建设、政治建设、文化建设、社会建设和生态文明建设,看成是一个相互联系、相互促进、不可分割的整体和过程。科学发展观的根本方法是统筹兼顾,要求在发展过程中必须统筹人与自然的关系,在利用自然的同时,保护好自然。只有生态文明建设和经济建设齐头并进,构成了人类发展的科学可持续性。 + +2005年国家林业局颁布实施“国家森林城市”评价指标。创建城市森林是改善城市生态环境的主要措施,是城市生态建设实现城乡一体化发展,全面推进我国城市走生产发展、生活富裕、生态良好发展道路的重要途径。 + +2008年《中华人民共和国城乡规划法》开始实施,它是一部关于城乡规划建设和管理的基本法律,它的颁布实施,是全面贯彻落实科学发展观,协调城乡空间布局,改善人居环境,依法促进城乡经济社会全面协调可持续发展的客观要求,也是走中国特色城镇化道路的客观需要。 + +2000年代以来,中国各级政府一再强调要积极推进乡村人居环境的建设,并付出了巨大的努力,从新农村建设到乡村环境整治、美丽乡村建设,再到中共十九大报告提出实施乡村振兴战略,标志着中国从过去以城市为中心的高速城镇化阶段,全面转向以城乡统筹为目标的高质量城镇化阶段。 + +(2)五个统筹整合(2012-2016年) + +2012年《中国人居环境发展报告-人居环境白皮书》由中国建筑工业出版社出版,《人居环境白皮书:中国人居环境发展报告》分为调研篇、社区篇、引导篇、集萃篇、论文篇、资料篇六大部分内容,基本涵盖了从城市、住区、住宅单体建筑环境到城镇居民人居环境满意度调查等各个层面和领域。编撰重点体现了四个方面主旨:基于城市化,面向未来;突出社会性,关注民生;展示权威度,引领人居;拓宽覆盖面,持续创新。 + +2012年,党的十八大正式将生态文明建设写入党章,体现了对新世纪快速发展阶段出现的一系列阶段性问题的科学判断和对人类社会发展规律的深刻把握,是对人居科学理论的丰富和完善,对人与自然和谐发展的深刻洞察,是实现我国全面建设小康社会宏伟目标的基本要求,也是对日益恶劣的全球环境问题主动承担大国责任的庄严承诺。 + +建设生态文明,是关系人民福祉,关乎民族未来的长远大计,把生态文明放在突出地位,融入经济建设,政治建设,文化建设,社会建设各方面和全过程,努力建设美丽中国,实现中华民族永续发展,“美丽中国”一词进入公众视野。 + +2014年首届“世界城市日”全球启动仪式在上海世博中心举行,主题为“城市,让生活更美好”,年度主题为“城市转型与发展”。“世界城市日”是中国首次在联合国推动设立的国际日,获得了联合国全体会员国的支持 。 + +2014年3月14日,习总书记主持召开中央财经领导小组第五次会议时指出: “在经济社会发展方面我们提出了‘五个统筹’,治水也要统筹自然生态的各要素,不能就水论水。要用系统论的思想方法看问题,生态系统是一个有机生命躯体,应该统筹治水和治山、治水和治林、治水和治田、治山和治林等。” + +2015年住建部、上海市政府、联合国人居署在上海共同举办“2015世界城市日论坛”,年度主题为“城市设计,共创和谐”。2015年中央城市工作会议,提出城市工作要把创造优良人居环境作为中心目标,努力把城市建设成为人与人,人与自然和谐共处的美丽家园。 + +2016年为配合“人居三”大会的召开,根据联合国人居署有关要求,我国住房和城乡建设部组织力量编写了“人居三”中国国家报告,报告介绍了中国城乡住区发展20年回顾、中国政府对人类住区发展的基本主张、中国城乡住区发展的行动计划、中国政府支持“人居三”大会的工作及期望;“人居三”大会通过《新城市议程》以来第一次有关城市发展问题的全球性大规模活动,本次会议的主题是“城市2030,人人共享的城市”。 + +\subsubsection{4.国土空间统筹发展新时代(2017—至今)} +2017年中共十九大报告提出人与自然和谐共生的重大要求,将建设“美丽中国”作为全面建设社会主义现代化国家的重大目标,明确提出要统筹山水林田湖草生命共同体,坚持人与自然和谐共生,强调从自然资源的整体性与系统性角度合理统筹国土空间规划,达到人与自然之间的相互平衡关系。 + +十九大报告将生态文明视作“中华民族永续发展的千年大计”,十九大以来,国家更加关注生态文明建设,坚持以人为中心,满足人民对于美好生活的向往,这一时期追求“绿水青山就是金山银山”的现代化城乡宜居的人居环境。 + +2017年中国住房城乡建设部、广东省人民政府与联合国人居署共同在广州举办2017“世界城市日”全球主场活动。同年国家发布《农村人居环境整治三年行动方案》。方案提出,到2020年,实现农村人居环境明显改善,村庄环境基本干净整洁有序,村民环境与健康意识普遍增强。 + +2018年2月,习近平总书记在四川成都天府新区视察时提出了“公园城市”理念,指出天府新区是“一带一路”建设和长江经济带发展的重要节点,一定要规划好建设好,特别是要突出公园城市特点,把生态价值考虑进去,努力打造新的增长极,建设内陆开放经济高地。 + +2018年3月11日,十三届全国人大第一次会议生态文明写入《宪法》,标志着我国步入了新时代中国生态文明建设和绿色发展的新阶段,建设公园城市是新时代新形势下的必然要求。 + +习近平总书记在2019年中国北京世界园艺博览会开幕式上的讲话明确指出:“纵观人类文明发展史,生态兴则文明兴,生态衰则文明衰。”生态文明建设已经纳入中国国家发展总体布局,建设美丽中国已经成为中国人民心向往的奋斗目标。 + +2021年国务院印发《农村人居环境整治提升五年行动方案(2021-2025年)》明确到2025年,农村人居环境显著改善生态宜居美丽乡村建设取得新进步的行动目标,“十四五”时期将深入实施农村人居环境整治提升五年行动,扎实推进农村厕所革命,加快推进农村生活污水治理,全面提升农村生活垃圾治理水平,推动村容村貌整体提升,建立健全长效管护机制。 + +2022年国务院批复同意成都建设践行新发展理念的公园城市示范区,并提出示范区建设要打造山水人城和谐相融的公园城市。《中国县域人居环境气象评估报告》正式发布。《报告》旨在助力政府科学评估县域人居环境的改善效果,提高县域人居环境改善和治理的现代化管理水平。 + +\section{我国传统人居环境的理念与人居环境学科发展} +\subsection{人居环境的核心理念} +中国传统生态智慧,历经数千年中华文化传承和城市建设实践,其思想核心是建立人与自然和谐统一的关系。它统合在儒、道、佛等思想流派中,以“天人合一”“道法自然”“众生平等”等为基本精神,诠释着最朴素的生态伦理和哲学,有别于西方以“还原论”“物竞天择”“改造世界”为特点的自然哲学,中国传统生态智慧具有以“整体”“共生”“适应”“永续”为特征的绿色发展理念,为中国特色理论体系在城乡建设领域的构建确立了思想内核。 + +\subsubsection{1.整体理念} +在描绘人与自然的基本关系上,西方文化强调解析和还原,东方文化强调事物的整体性和综合性。中国哲学的思维特征则是体验的、综合的,与伦理、社会、人生结合,善于从整体视角研究高度复杂的系统。“一阴一阳之谓道”,表明事物和现象同时具有对立和统一的关系,它们相互依存、结成整体,因此不能孤立地看待任一部分。董仲舒的“以类合之,天人一也”,表达了人与天地万物具有同类合一的性质,在东方整体观的认知下,人与自然统合为一个整体。对自然各个领域的认识也首先强调关注其全貌及其展现的整体规律,其次才是各组成部分之间的相互关系,再次才是组成部分自身的特征。 + +吴良镛院士谈及中国人居环境的特点时曾说,“中国人居环境的营造,不是专注于一座建筑的设计或钟情于一片风景的塑造,而是强调整体,采用规划、建筑、园林‘三位一体’的营造方略。” + +\subsubsection{2.共生理念} +中国传统哲学认为天地造化、万物同源。《庄子·秋水》中写到“以道观之,物无贵贱”,因为万物平等,中国人的世界观带有善待万物的思想。 + +《礼记·中庸》有“万物并育而不相害,道并行而不相悖”的名句,表达了每一个生命体都拥有符合自然规律的生存权利,“上天有好生之德”,人类不能强行剥夺其他生命的发展权,善待生命、热爱自然才是符合世界运行的根本规律。习总书记提出的“山水林田湖草是一个生命共同体”思想重新诠释了这一传统认知,表达出生态环境各要素之间相互关联、相互影响、相互依存的特性,深刻阐明了万物共生共荣的自然规律,“人的命脉在田,田的命脉在水,水的命脉在山,山的命脉在土,土的命脉在树。” + +\subsubsection{3.适应理念} +中国长期的农业社会实践形成了遵循自然规律的认知,人类在自然面前作为弱者采取“顺应自然”的行为,在“因就”中满足自身的发展诉求。“二十四节气”表达的就是应时务农的思想,《管子·乘马》中“凡立国都,非于大山之下,必于广川之上,高毋近旱,而水用足;下毋近水,而沟防省;因天材,就地利,故城郭不必中规矩,道路不必中准绳。”代表着因地制宜进行城市选址和建设的经验总结,有鲜明的“顺应自然”特色。 + +今天,人类科学技术虽已取得巨大进步,改造自然的能力空前提高,但城市发展仍然面临也将长期面临如何适应自然的课题,气候安全、生态安全、能源资源安全、防灾减灾等问题的交织。按照“复杂适应系统”理论,主体需要根据客体环境的变化主动寻求适应,使自身的演进趋向“绿色化”;在与环境及其它主体间持续不断的交互作用中,不断“学习”或“积累经验”,调整自身结构和行为方式,实现顺应环境的发展,如果把城乡空间视为生命体,其宏观至微观层面系统的生长进化、推陈出新,都需要在这个适应的进程中逐步变化。 + +\subsubsection{4.永续理念} +中国传统对自然的利用强调 “从长计议”。它提倡有限度地开发利用自然,主动约束过度开采行为,以维系自然的永续平衡。从《礼记·王制》中可以看到,中国古代推行“时禁”“不夭其生,不绝其长”,认为对山林川泽的索取,要避开草木、鱼鳖刚开始生长发育的阶段,反对滥采以确保百姓能够长期获得所需资源。《淮南子·主术训》也讲到“畋不掩群,不取麛夭。不涸泽而渔,不焚林而猎。”认为人类渔猎动物应有不可逾越的底线,取之有度,用之有节,从而避免破坏大环境生态平衡。永续理念建立了城乡人居环境发展的时间维度,这与可持续发展观所强调的“代际公平”思想不谋而合。 + +\subsection{人居环境的科学发展} +\subsubsection{1.道萨迪亚斯的“人类聚居学”} +希腊建筑师道萨迪亚斯在20世纪50年代创立研究人类聚居的理论,又称城市居住规划学、人类环境生态学。1965年在希腊雅典成立人类聚居学世界学会。在他的积极努力下,联合国于1976年在温哥华召开“世界人居大会”,此后每隔20年召开一次,最新的第三届“世界人居大会”于2016年在厄瓜多尔首都基多召开,并通过了《新城市议程》,为城市可持续发展设定了新的全球标准。 + +道萨迪亚斯认为传统建筑学、地理学、社会学、人类学等学科,仅仅各自研究涉及人类聚居的某一侧面,而人类聚居学要吸收上述各学科的成果,在更高的层次上对人类聚居进行全面、综合的研究。一方面要建立一套科学的体系和方法,了解和掌握人类聚居的发展规律;另一方面要解决人类聚居中存在的具体问题,创造出良好的人类生活环境。 + +人类聚居主要是指包括乡村、集镇、城市等在内的人类生活环境,由五个基本要素组成——自然界、人、社会、建筑物、联系网络,人类聚居学研究上述五项要素以及它们之间的相互关系。 + +道萨迪亚斯按规模大小把人类聚居分成15级层次单位:个人、居室、住宅、 住宅组团、 小型邻里、邻里、集镇、城市、大城市、大都会、城市组团、大城市群区、城市地区、城市洲、全球城市。这15级单位上下互相联系构成人类聚居系统,要想解决各层次中的问题,必须对整个系统进行研究。 + +\subsubsection{2.吴良镛院士的“人居环境科学”} +1993年8月,吴良镛和周干峙、林志群在中科院技术科学部学部大会上,阐释了“人居环境学”的观念和系统。其后,吴良镛院士不断完善,于2001年出版《人居科学导论》,系统阐述了人居环境科学的框架。人居环境科学是一门以人类聚居为研究对象,着重探讨人与环境之间相互关系的科学,强调把人类聚居作为一个整体,而不像城市规划学、地理学、社会学那样,只涉及人类聚居的某一部分或是某个侧面,人居环境科学的目的是了解并掌握人类聚居发生、发展的客观规律,以更好地建设符合人类理想的聚居环境。 + +在借鉴人类聚居学的基础上,吴良镛院士提出人居环境的五个子系统,即自然系统、人类系统、居住系统、社会系统、支撑系统;根据中国实践将人居环境分为五个层次,即全球、区域、城市、社区和建筑;明确了发展中国人居环境科学的五大原则,即生态观、经济观、科技观、社会观和文化观,这些内容共同搭起了人居环境科学的框架。吴良镛院士认为,每个学科都应该有自己的方法论,人居环境科学面对错综复杂的自然与社会问题,需要借助复杂性科学的方法论,通过多学科的交叉从整体上予以探索和解决。 + +1999年6月23日,国际建协第20届世界建筑师大会在北京召开,大会一致通过了由吴良镛院士起草的《北京宪章》。《北京宪章》被公认为是指导二十一世纪人居环境发展的重要纲领性文献,标志着吴良镛院士的广义建筑学与人居环境学说,已被全球普遍接受和推崇。 + +人居环境科学是研究人类聚居及其环境相互关系与发展规律的科学,其理论与实践从中国建设的实际出发,与世界人居运动形成了良好的呼应,是“中国改革开放40周年的标志性成果之一”。 + +\subsubsection{3.新时代人居环境科学的侧重点} +当前,我国内外部环境的巨大变化、社会经济发展动力的变化、人口结构和城镇化发展阶段的变化,都已昭示了新发展阶段的到来。新阶段的城乡发展实践,需要新阶段的人居环境科学理论来支撑。 + +不同阶段的主要矛盾不同,决定解决其方法的不同。新时代我国社会主要矛盾已经转化为人民日益增长的美好生活需要和不平衡不充分的发展之间的矛盾,我国经济主要矛盾已经转化为生态资源环境安全紧约束和人均GDP倍增之间的矛盾,而两者共同的解决途径是破解“生态、资源、环境、安全”投入和“经济、政治、社会、文化、生态”产出之间“此消彼长、难以两全”的矛盾关系,实现两个“脱钩”:经济增长与资源环境消耗脱钩(经济增长快于资源环境消耗),人民生活质量提升与经济增长脱钩(人民生活质量提升快于经济增长)。 + +因此,在人居环境科学理论的框架之下,新发展阶段应将重点聚焦于“生态、资源、环境、安全”这组紧约束条件,回答在此条件之下如何实现“以人民为中心”的“五位一体”发展目标,这归根结蒂是一个道路问题。通过技术创新和制度创新,通过最小的生态资源环境安全代价,最大程度地满足人民对美好生活的向往。 + +\section{生态文明演进与我国国土空间的生态安全问题} +人类的发展经历了原始文明、农耕文明、工业文明等阶段,在深刻反思各类教训基础上,基于可持续发展理念,生态文明思想逐渐被人类所接受。 + +\subsection{生态文明的演进} +原始文明时期人类是自然的产物,人与自然之间是以自然为主宰,人敬畏自然、崇拜自然。从原始文明过渡到农业文明,是人类历史上的重大飞跃。农耕文明时期人类与自然之间保持着有序、协同、共生的关系,然而生产力相对落后,物质财富相对匮乏,农耕文明的活动主要是农业和畜牧业,人类不完全依赖自然,并努力寻找适合自身生存的生活地点。虽然农耕文明阶段生产力低下,人类对自然的破坏和损伤不大,但人与自然仍然存在大量矛盾。18世纪中叶以后欧洲爆发工业革命,农耕文明迅速被工业文明替代,工业文明时期生产力得到空前解放和发展,人类在获得巨大的物质财富的同时也导致了一定的资源环境危机,影响到人类生存质量。工业文明以大工业生产方式为主导,以物质财富的迅速积累为重要标志,并通过征服自然来积累财富,大量的掠夺式开发利用自然导致生态平衡被破坏,危害到人与自然的可持续发展。1970年代以后,生态环境问题日益严重,被国际上视为焦点话题。1972年在瑞典斯德哥尔摩举行了联合国人居环境会议,会议通过了《人类环境宣言》指出地球的能源和资源是有限的,为了支持人类的长远发展,必须遵循有机增长的路径。1973年联合国成立环境规划署,1980年代国际社会提出可持续发展理念,生态文明的思想开始广泛流传。生态文明时期是在深刻反思工业文明教训的基础上,汲取农耕文明精粹,协调“发展”和“保护”关系的新型发展理念。生态文明是对工业文明的深刻变革和扬弃,是汲取农耕文明精粹、协调人与自然关系的新型发展理念,人类文明的又一次提升和飞跃。 + +\subsection{我国生态资源的基本情况} +\subsubsection{1.自然资源总量大、类型多} +中国陆地面积约960万km²,居世界第三位;目前耕地面积约1.28亿hm²,居世界第四位;森林面积约2.8亿hm²,居世界第五位;草地约2.6亿hm²,居世界第四位;水资源约29638.2亿m³,居世界第六位;按45种主要矿产资源的潜在价值,按矿产总值比计,居世界第三位;水能、太阳能、煤炭资源分别居世界第一、第二、第四位。中国已发现矿产173种,矿产地(点)20余万处,已探明储量的157种,其中有20余种矿产储量居世界前列。从总量看,中国是世界资源大国之一。 + +\subsubsection{2.人均自然资源量少、分布不均} +中国主要自然资源的人均占有水平低。2019年,我国耕地面积居世界第四位,但人均耕地面积不足1.4亩,不到世界平均水平的1/2;人均森林面积仅为世界平均水平的1/5;我国人均可再生淡水资源为2200立方米,仅为世界平均水平的1/4,且时空分布极不平衡;全国建制市中的缺水城市占2/3以上,其中100多个城市严重缺水;地下水资源超采严重,浅层地下水含量逐年持续下降。中国主要矿产资源的人均占有量较低,与世界平均水平比较,石油探测储量的人均占比仅为世界人均占有量的7.9\%,天然气的占比不足18\%,一次性能源消费量(包括原煤、原油、天然气、水电、核电)的占比为26\%。中国自然资源分布的东西差异极其明显,南北资源组合的差异也很大。耕地资源、森林资源、水资源的90\%以上集中分布在东部,而能源、矿产等地下资源和天然草地相对集中于西部。中国大量淡水资源集中在南方,北方淡水资源只有南方淡水资源的1/4。而耕地的分布却是南少北多。 + +\subsubsection{3.资源禀赋欠佳} +中国耕地中,一等到三等耕地仅占31\%,中低产田占比三分之二以上;草地资源主要分布在半干旱、干旱地区与山区,资源质量较差;林地资源则较好,一等林地约占65\%。多数矿产资源贫矿多而富矿少。共、伴生矿多,单矿种矿少,利用难度大,成本较高。 + +\subsection{我国生态资源环境挑战} +过去四十年,中国的工业化、城市化超越了任何一个经济体,也超越了工业化国家的任何一个历史时期,但同时也带来了生态资源环境安全等方面的问题,具体体现在以下方面: + +\subsubsection{1.生态系统脆弱、退化形势严峻} +我国生态系统整体质量和稳定性状况不容乐观。自然生态系统总体较为脆弱、生态承载力和环境容量较低、优质生态产品供给能力不足现象尚未得到根本扭转。“胡焕庸线”东南方43\%的国土,居住着全国94\%左右的人口,以平原、水网、低山丘陵和喀斯特地貌为主,生态环境压力巨大;该线西北方57\%的国土,供养大约全国6\%的人口,以草原、戈壁沙漠、绿洲和雪域高原为主,生态系统非常脆弱。资源过度开发导致生态系统退化形势依然严峻。根据2021年中国水土保持公告,全国水土流失面积267.42万 km2,占国土面积的27.86\%;过度农垦、放牧导致草原生态系统失衡,2019年重点天然草原平均牲畜超载率达10.1\%,2021年我国人工林面积6801.96千公顷,超过森林总面积的30\%,且不少位于干旱、半干旱地区;不少农业开发和建设占用挤占或损毁生态空间,从历史上看,农牧交错带地区大量耕地是通过开垦优质草原、森林、湿地形成的,全国地理国情监测数据表明,2019年全国种植土地(含果树等经济作物)、建设用地(含设施农用地)均比2015年有所增加,全国草地面积有所减少,全国矿山开采占用、损毁土地问题比较严重。 + +\subsubsection{2.人均资源短缺、利用效率不高} +2021年,原油、天然气、煤炭、铁矿石、铜精矿、铝土矿的进口额约占我国矿产品进口总额的85\%以上,2019年,我国有2/3的战略性矿产存在较高的对外依存度,其中约有1/2的战略性矿产对外依存度超出了50\%。 + +我国有一批未来需求潜力大、但被他国“卡脖子”的矿种。2019年,我国油气、铁、铜、铝、镍、钴、锆、铬等等15种战略性矿产的资源储量占全球比重均低于20\%。其中,石油储量仅占全球总量的1.5\%;煤炭储量也仅占全球总量的13.2\%;从数量上对比看,我国2/3以上的战略性矿产资源储量在全球均处于劣势地位。 + +未来较长的一段时期内,我国仍然将保持国际制造业大国的地位。尤其是战略性新兴产业还将成为国家重点扶持的产业,这会导致战略性矿产消费量快速增长,加剧供需矛盾。资源粗放利用问题依然突出。城乡建设仍以外延扩张的发展模式为主,2021年全国人均城镇村及工矿用地250平方米。 + +\subsubsection{3.环境容量有限、防治任务艰巨} +根据2021年水土流失动态监测成果,全国水土流失面积267.42万平方公里,占陆地国土面积(不含港澳台)的27.96\%;根据第五次全国荒漠化和沙化监测结果,全国荒漠化土地面积为261.16万平方千米,沙化土地面积为172.12万km2,占国土面积的18.0\%;首次全国土壤污染状况调查显示全国土壤总的超标率为16.1\%。2021年,全国339个地级及以上城市中121个城市环境空气质量超标,占35.7\%;全国酸雨区面积约36.9万平方千米,占国土面积的3.8\%。 + +\subsubsection{4.城市韧性不足、安全事件频发} +伴随城镇化快速扩张的过程,城市公共安全事件频发,如水灾、气象灾害、环境污染、地震、火灾爆炸、危化品泄漏、交通事故、疫病疫情以及群体性事件等都会严重影响社会安全与稳定,并威胁人民生命财产安全。与城市相关的灾害种类有30多种,可分为自然和人为灾害两大类。(1)\textbf{城市自然灾害。}我国70\%以上的大城市集中在东部经济发达地区及沿海开放地带,其中不少地区是自然灾害的易发、多发区。(2)\textbf{城市人为灾害。}包括人类管理不善或疏忽、错误造成的,如火灾与爆炸、城市工业与高新技术致灾、公害致灾、城市生命保障线事故、交通事故等,以及人类的故意行为造成的灾害。从危险化学品事故看,危化品在产、运、储、销、用及废弃处理等环节中都有可能由于管理不善或疏忽、错误引起事故,造成人员伤亡和财产的损失。各类城市公共安全事件暴露出了我国城市韧性不足,公共应急管理体系软件建设和公共安全设施硬件建设都存在明显短板。 + +\section{生态文明建设的基本观念} +2017年,党的十九大报告提出了“2035年基本实现社会主义现代化、2050年建成富强民主文明和谐美丽的社会主义现代化强国的宏伟目标。” 在“富强民主文明和谐”之后增加“美丽”一词,体现了我党对社会主义现代化内涵理解的不断全面和深化,体现了“环境就是民生,青山就是美丽,蓝天也是幸福”的生态价值理念。 + +在此目标之下,党中央提出“十四五”时期经济社会发展要以推动高质量发展为主题,这是根据我国发展阶段、发展环境、发展条件变化做出的科学判断。高质量发展就是从“有没有”到“好不好”的发展,就是要着力解决发展不平衡不充分问题,解决这一社会主要矛盾的过程,就是高质量供给加快成长、升级需求得到有效满足的过程。 + +推动高质量发展,必须坚定不移贯彻新发展理念,以满足人民对美好生活的需要为出发点,以深化供给侧结构性改革为主线,坚持质量第一、效益优先,切实转变发展方式,推动质量变革、效率变革、动力变革,实现发展质量、结构、规模、速度、效益、安全相统一。 + +高质量发展是体现五大新发展理念的发展,是创新成为第一动力、协调成为内生特点、绿色成为普遍形态、开放成为必由之路、共享成为根本目的的发展。完整、准确、全面贯彻新发展理念,必须坚持系统观念,统筹国内国际两个大局,统筹“五位一体”总体布局和“四个全面”战略布局,加强前瞻性思考、全局性谋划、战略性布局、整体性推进。 + +2019年全国两会期间,习总书记参加内蒙古代表团审议时指出:“党的十八大以来,我们党关于生态文明建设的思想不断丰富和完善,在‘五位一体’总体布局中,生态文明建设是其中一位,在新时代坚持和发展中国特色社会主义基本方略中坚持人与自然和谐共生是其中一条基本方略,在新发展理念中绿色是其中一大理念,在三大攻坚战中污染防治是其中一大攻坚战。这‘四个一’体现了我们党对生态文明建设规律的把握,体现了生态文明建设在新时代党和国家事业发展中的地位,体现了党对建设生态文明的部署和要求。各地区各部门要认真贯彻落实,努力推动我国生态文明建设迈上新台阶。” + +习近平生态文明思想是新时代中国特色社会主义思想的重要组成部分,是贯彻绿色发展理念、探索“生态优先、绿色发展”路径的指导思想和行动指南。全面准确地理解和认识习近平生态文明思想有助于从整体上把握新时代中国特色社会主义思想,更好地贯彻党的十九大精神,推进绿色发展,实现中国的绿色崛起。习近平生态文明思想集中展现了八个方面思维: + +\subsection{历史思维:“生态兴则文明兴,生态衰则文明衰”} +生态环境是人类生存和发展的根基,生态环境变化直接影响文明兴衰演替。2013年5月24日,习总书记在主持十八届中共中央政治局第六次集体学习时指出:“生态文明是人类社会进步的重大成果。人类经历了原始文明、农业文明、工业文明,生态文明是工业文明发展到一定阶段的产物,是实现人与自然和谐发展的新要求。历史地看,生态兴则文明兴,生态衰则文明衰。古今中外,这方面的事例众多。”古代埃及、古代巴比伦、古代印度、古代中国四大文明古国均发源于森林茂密、水量丰沛、田野肥沃的地区。而生态环境衰退特别是严重的土地荒漠化则导致古代埃及、古代巴比伦衰落。我国古代一些地区,例如楼兰古国、河西走廊、黄土高原等,也有过惨痛教训。 + +生态文明建设是关系中华民族永续发展的根本大计。中华民族向来尊重自然、热爱自然,绵延5000多年的中华文明孕育着丰富的生态文化。奔腾不息的长江、黄河是中华民族的摇篮,哺育了灿烂的中华文明。2016年8月,习总书记在青海考察工作时强调:“党的十八大以来,我反复强调生态环境保护和生态文明建设,就是因为生态环境是人类生存最为基础的条件,是我国持续发展最为重要的基础。‘天育物有时,地生财有限。’生态环境没有替代品,用之不觉,失之难存。人类发展活动必须尊重自然、顺应自然、保护自然,否则就会遭到大自然的报复,这是规律,谁也无法抗拒。” + +\subsection{全球思维:“共谋全球生态文明建设”} +生态文明建设关乎人类未来,建设绿色家园是各国人民的共同梦想。国际社会需要加强合作、共同努力,构建尊崇自然、绿色发展的生态体系,推动实现全球可持续发展。任何一国都无法置身事外、独善其身。习总书记强调:“我们建设现代化国家,走美欧老路是走不通的,再有几个地球也不够中国人消耗。‘走老路,去消耗资源,去污染环境,难以为继!’” + +我国已成为全球生态文明建设的重要参与者、贡献者、引领者,主张加快构筑尊崇自然、绿色发展的生态体系,共建清洁美丽的世界。要深度参与全球环境治理,增强我国在全球环境治理体系中的话语权和影响力,积极引导国际秩序变革方向,形成世界环境保护和可持续发展的解决方案。要坚持环境友好,引导应对气候变化国际合作,要推进“一带一路”建设,让生态文明的理念和实践造福沿线各国人民。 + +2020年9月22日,习总书记在第七十五届联合国大会一般性辩论上宣布:“中国将提高国家自主贡献力度,采取更加有力的政策和措施,二氧化碳排放力争于2030年前达到峰值,努力争取2060年前实现碳中和。” 2020年12月12日,习总书记在气候雄心峰会上指出:“到2030年,中国单位国内生产总值二氧化碳排放将比2005年下降65\%以上,非化石能源占一次能源消费比重将达到25\%左右,森林蓄积量将比2005年增加60亿立方米,风电、太阳能发电总装机容量将达到12亿千瓦以上。”2021年4月22日,习总书记在领导人气候峰会上指出,“气候变化带给人类的挑战是现实的、严峻的、长远的。但是,我坚信,只要心往一处想、劲往一处使,同舟共济、守望相助,人类必将能够应对好全球气候环境挑战,把一个清洁美丽的世界留给子孙后代。” + +\subsection{底线思维:“坚守资源上限、环境底线、生态红线”} +2018年5月18日,习总书记在全国生态环境保护大会上指出,“之所以反复强调要高度重视和正确处理生态文明建设问题,就是因为我国环境容量有限,生态系统脆弱,污染重、损失大、风险高的生态环境状况还没有根本扭转,并且独特的地理环境加剧了地区间的不平衡。”要加快形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,把经济活动、人的行为限制在自然资源和生态环境能够承受的限度内,给自然生态留下休养生息的时间和空间。 + +2018年5月18日,习总书记在全国生态环境保护大会上指出:“要加快划定并严守生态保护红线、环境质量底线、资源利用上线三条红线。对突破三条红线、仍然沿用粗放增长模式、吃祖宗饭砸子孙碗的事,绝对不能再干,绝对不允许再干。”在生态保护红线方面,要建立严格的管控体系,实现一条红线管控重要生态空间,确保生态功能不降低、面积不减少、性质不改变。在环境质量底线方面,将生态环境质量只能更好、不能变坏作为底线,并在此基础上不断改善,对生态破坏严重、环境质量恶化的区域必须严肃问责。在资源利用上线方面,不仅要考虑人类和当代的需要,也要考虑大自然和后人的需要,把握好自然资源开发利用的度,不要突破自然资源承载能力。 + +\subsection{民本思维:“良好生态环境是最普惠的民生福祉”} +我国社会主要矛盾转化为人民日益增长的美好生活需要和不平衡不充分的发展之间的矛盾,人民群众对优美生态环境需要已经成为这一矛盾的重要方面。 + +良好生态环境是最普惠、也是最基本的民生福祉。2013年4月,习总书记在海南考察时指出:“对人的生存来说,金山银山固然重要,但绿水青山是人民幸福生活的重要内容,是金钱不能代替的。你挣到了钱,但空气、饮用水都不合格,哪有什么幸福可言。” + +2015年,习总书记参加江西代表团审议时指出:“环境就是民生,青山就是美丽,蓝天也是幸福。”要积极回应人民群众所想、所盼、所急,大力推进生态文明建设。要坚持生态惠民、生态利民、生态为民,重点解决损害群众健康的突出环境问题,加快改善生态环境质量,提供更多优质生态产品,努力实现社会公平正义,不断满足人民日益增长的优美生态环境需要。 + +每个人都是生态环境的保护者、建设者、受益者,要增强全民节约意识、环保意识、生态意识,培育生态道德和行为准则,开展全民绿色行动,动员全社会都以实际行动减少能源资源消耗和污染排放,为生态环境保护做出贡献。 + +\subsection{整体思维:“坚持人与自然和谐共生”} +2018年5月4日,习总书记在纪念马克思诞辰200周年大会上指出,学习马克思,就要学习和实践马克思主义关于人与自然关系的思想。“自然物构成人类生存的自然条件,人类在同自然的互动中生产、生活、发展,人类善待自然,自然也会馈赠人类,但‘如果说人靠科学和创造性天才征服了自然力,那么自然力也对人进行报复’。自然是生命之母,人与自然是生命共同体,人类必须敬畏自然、尊重自然、顺应自然、保护自然。” + +“天地与我并生,而万物与我为一。”生态环境没有替代品,用之不觉,失之难存。《吕氏春秋》中说:“竭泽而渔,岂不获得?而明年无鱼;焚薮而田,岂不获得?而明年无兽。”这些关于对自然要取之以时、取之有度的思想,有十分重要的现实意义。当人类合理利用、友好保护自然时,自然的回报常常是慷慨的;当人类无序开发、粗暴掠夺自然时,自然的惩罚必然是无情的。人类对大自然的伤害最终会伤及人类自身,这是无法抗拒的规律。 + +2018年5月18日,习总书记在全国生态环境保护大会上指出:“在整个发展过程中,都要坚持节约优先、保护优先、自然恢复为主的方针,不能只讲索取不讲投入,不能只讲发展不讲保护,不能只讲利用不讲修复,要像保护眼睛一样保护生态环境,像对待生命一样对待生态环境,多谋打基础、利长远的善事,多干保护自然、修复生态的实事,多做治山理水、显山露水的好事,让群众望得见山、看得见水、记得住乡愁,让自然生态美景永驻人间,还自然以宁静、和谐、美丽。” + +\subsection{系统思维:“山水林田湖草是生命共同体”} +习总书记深刻指出:“生态是统一的自然系统,是相互依存、紧密联系的有机链条。人的命脉在田,田的命脉在水,水的命脉在山,山的命脉在土,土的命脉在林和草,这个生命共同体是人类生存发展的物质基础。一定要算大账、算长远账、算整体账、算综合账,如果因小失大、顾此失彼,最终必然对生态环境造成系统性、长期性破坏。” + +2013年11月9日,习总书记在《关于〈中共中央关于全面深化改革若干重大问题的决定〉的说明》中指出:“用途管制和生态修复必须遵循自然规律,如果种树的只管种树、治水的只管治水、护田的单纯护田,很容易顾此失彼,最终造成生态的系统性破坏。由一个部门负责领土范围内所有国土空间用途管制职责,对山水林田湖进行统一保护、统一修复是十分必要的。” + +要从系统工程和全局角度寻求新的治理之道,统筹兼顾、整体施策、多措并举,全方位、全地域、全过程开展生态文明建设。2014年3月14日,习总书记主持召开中央财经领导小组第五次会议时指出:“在经济社会发展方面我们提出了‘五个统筹’,治水也要统筹自然生态的各要素,不能就水论水。要用系统论的思想方法看问题,生态系统是一个有机生命躯体,应该统筹治水和治山、治水和治林、治水和治田、治山和治林等。” + +2018年5月18日,习总书记在全国生态环境保护大会上指出:“要从系统工程和全局角度寻求新的治理之道,不能再是头痛医头、脚痛医脚,各管一摊、相互掣肘,而必须统筹兼顾、整体施策、多措并举,全方位、全地域、全过程开展生态文明建设。比如,治理好水污染、保护好水环境,就需要全面统筹左右岸、上下游、陆上水上、地表地下、河流海洋、水生态水资源、污染防治与生态保护,达到系统治理的最佳效果。” + +2019年9月18日,习总书记在郑州主持召开黄河流域生态保护和高质量发展座谈会时指出:“治理黄河,重在保护,要在治理。要坚持山水林田湖草综合治理、系统治理、源头治理,统筹推进各项工作,加强协同配合,推动黄河流域高质量发展。” + +\subsection{辩证思维:“绿水青山就是金山银山”} +回望40年的改革开放,我国提供农产品、工业品、服务产品的能力显著增强,但是,我国在提供生态产品的能力上是下降的,这成为当前要素供给中的突出短板,当自然资源成为稀缺性资源和产业资本投资获利的对象时,生态产品就具有了商品性质,成为高使用价值和高资产价值的统一体。以此为前提,“绿水青山”就有可能转化为“金山银山”,人类也就此步入生态文明新时代。 + +2020年4月21日,习总书记在陕西安康市平利县老县镇蒋家坪村考察时指出:“人不负青山,青山定不负人。绿水青山既是自然财富,又是经济财富。希望乡亲们坚定不移走生态优先、绿色发展之路,因茶致富、因茶兴业,脱贫奔小康。” + +“两山理论”核心是保护与发展间良性互动、对立统一的辩证关系。经济发展不能超越资源环境的承载力底线,不应是对资源环境的“竭泽而渔”;生态保护应当是顺应经济发展规律的积极、主动保护,而不是舍弃经济发展的“缘木求鱼”。“两山理论”揭示了保护生态环境就是保护生产力、改善生态环境就是发展生产力的道理,指明了实现发展和保护协同共生的新路径。绿水青山既是自然财富、生态财富,又是社会财富、经济财富。保护生态环境就是保护自然价值和增值自然资本,就是保护经济社会发展潜力和后劲,使绿水青山持续发挥生态效益和经济社会效益。 + +要以体制机制改革创新为核心,推进生态产业化和产业生态化,加快完善政府主导、企业和社会各界参与、市场化运作、可持续的生态产品价值实现路径,着力构建绿水青山转化为金山银山的政策制度体系,推动形成具有中国特色的生态文明建设新模式。 + +\subsection{法制思维:“用最严格制度最严密法治保护生态环境”} +2015年,习总书记参加江西代表团审议时指出:“要像保护眼睛一样保护生态环境,像对待生命一样对待生态环境。对破坏生态环境的行为,不能手软,不能下不为例。” + +保护生态环境必须依靠制度、依靠法治。习总书记指出:“要加快制度创新,增加制度供给,完善制度配套,强化制度执行,让制度成为刚性的约束和不可触碰的高压线。要严格用制度管权治吏、护蓝增绿,有权必有责、有责必担当、失责必追究,保证党中央关于生态文明建设决策部署落地生根见效。” + +2016年11月28日,习总书记就做好生态文明建设工作作出重要批示指出:“要深化生态文明体制改革,尽快把生态文明制度的‘四梁八柱’建立起来,把生态文明建设纳入制度化、法治化轨道。要加大环境督查工作力度,严肃查处违纪违法行为,着力解决生态环境方面突出问题,让人民群众不断感受到生态环境的改善。” + +制度的生命力在于执行,对于已出台的一系列改革举措和相关制度,要像抓中央环境保护督察一样抓好落实。要落实领导干部生态文明建设责任制,严格考核问责。对那些不顾生态环境盲目决策、造成严重后果的人,必须追究其责任,而且应该终身追责。 + +\section{生态文明建设的总体路径} +迈入新发展阶段,意味着高水平保护、高质量发展、高品质生活、高效能治理的协同并进,社会、经济、生态、治理发展的方方面面也将实现由量到质、由大到强的一次大跨越。 + +\subsection{高水平保护——框定生态资源环境安全底线} +生态文明建设是关系中华民族永续发展的根本大计,是实现人与自然和谐发展的新要求。 + +要尊重自然规律,树立底线思维,全面贯彻落实生态文明思想,坚持总体国家安全观,筑牢国家生态安全屏障。 + +要建立以国家公园为主体的自然保护地体系,推进自然保护地整合优化、统一设置、分级管理、分区管控,系统保护陆地和海洋重要自然生态系统,保护生物多样性;严格划定生态保护红线,将整合优化后的自然保护地、生态极度重要和极度脆弱区域以及国家一级公益林、重要湿地、饮用水源地一级保护区、冰川及永久积雪、红树林、珊瑚礁等重要生态系统等划入生态红线。 + +要按照山水林田湖草整体保护、系统修复、综合治理的要求,抓住重点区域、重点流域、重点海域的突出生态问题,统筹山水林田湖草系统保护修复、大规模国土绿化、海洋生态修复、荒漠化治理等重大工程。立足我国国情,探索基于自然的生态保护修复解决方案,提高生态修复的科学性和有效性。 + +耕地是国家粮食安全的根本保障,要严守耕地保护红线,实行严格的耕地用途管制,将中国人的饭碗牢牢端在自己手上。要强化耕地数量、质量、生态“三位一体”保护理念,实行严格的耕地占补平衡制度,促进形成保护更加有力、执行更加顺畅、管理更加高效的耕地保护新格局。 + +要立足本地自然资源条件,在建设过程中保护、传承历史文化和特色风貌,持续改善人居环境,协同推进经济高质量发展和生态环境高水平保护,切实增强人民群众生态环境获得感、幸福感和安全感。 + +\subsection{高质量发展——促进要素向优势地区集聚} +实现高质量发展要完整、准确、全面贯彻新发展理念,以创新发展解决发展动力问题,以协调发展解决发展不平衡问题,以绿色发展解决人与自然和谐问题,以开放发展解决发展内外联动问题,以共享发展解决社会公平正义问题。 + +要尊重经济规律,促进产业和人口向优势区域集中,形成以城市群为主要形态的增长动力源,进而带动经济总体效率提升;破除资源流动障碍,使市场在资源配置中起决定性作用,促进各类生产要素自由流动并向优势地区集中,提高资源配置效率。 + +同时,高质量发展不是仅对经济发达地区的要求,而是对所有地区无论处于何种发展阶段都需要践行的要求。我国国内各地区的资源禀赋、区位条件、经济基础、发展阶段各不相同,要发挥比较优势,推动生态和文化产品转化,探索差异化、特色化发展道路,加快动力转换、效率提升、结构优化。 + +总体上看,要加快构建高质量发展的动力系统,增强中心城市和城市群等经济发展优势地区的经济和人口承载能力,增强其他地区在保障粮食安全、生态安全、边疆安全,弘扬地域特征、民族文化、时代风貌等方面的功能,形成优势互补、高质量发展的国土空间格局。 + +\subsection{高品质生活——满足人民美好生活需要} +我国社会主要矛盾已经转化为人民日益增长的美好生活需要和不平衡不充分的发展之间的矛盾,以前我们要解决的是有没有的问题,现在则是要解决好不好的问题。 + +要尊重社会规律,紧扣人民对美好生活向往呈现出的多元化、多层次、多方面的特点,推动空间的供给侧改革,从关注量的多少转向重视质的提升。 + +要顺应人口结构变化趋势,建设全龄友好型城市。推进义务教育和学龄前教育设施均衡发展,促进儿童友好型社会建设;增加养老、医疗服务设施有效供给,提升老年人的幸福感和安全感;完善面向新青市民的生活、工作服务设施。以完善社区基本治理单元为重点,打造“15分钟社区生活圈”,以“共同缔造”为核心,创新完善社区治理机制,构建“纵向到底、横向到边、协商共治”的社会治理体系。 + +要坚持城乡一体、区域协同发展,推进全体人民共同富裕,通过完善住房保障体系、推进城镇基本公共服务均等化等方式,实现幼有所育、学有所教、劳有所得、病有所医、老有所养、住有所居、弱有所扶,保证全体人民在共建共享发展中有更多获得感。 + +\subsection{高效能治理——推进空间治理体系和治理能力现代化} +要破解规划类型过多、内容重叠冲突,审批流程复杂、周期过长,地方规划朝令夕改等问题,建立全国统一、责权清晰、科学高效的国土空间规划体系,整体谋划新时代国土空间开发保护格局。 + +要坚持事权对应原则,对应市场经济为主体下的有为政府事权,确定规划内容;对应各级政府行政事权,区分各级规划内容清单。以行政主体事权“清单”确定规划内容“清单”,明确规划的实施、管理、监督的责任主体。 + +要坚持有效行政原则,建立各级规划内容之间的刚性传递关系,避免任何一个环节的“断链”导致整体约束性的丧失;同时区分定性、定则、定量、定构、定界等不同精度的刚性内容,以对应不同层级政府事权,在确保规划管控“基因”延续的前提下为下位规划预留深化细化空间。 + +要坚持层次最简原则,在有效行政前提下实现规划层次的最简化,从而最大化地降低行政成本,并降低“刚性断链、整体失效”的概率。 + +要通过完善法规政策体系、完善技术标准体系、完善基础信息平台等方式强化规划法规政策与技术保障;通过强化规划法律地位、改进规划审批、健全用途管制制度、监督规划实施、推进“放管服”改革等方式强化规划实施与监管;通过加强组织领导、落实工作责任保障规划实施。 + +\section{生态文明下的人居环境与国土空间和谐共存} +成立自然资源部和推动国土空间规划都是源自生态文明建设这个最关键、最重要的时代背景之下,自然资源部贯彻落实党中央关于自然资源工作的方针政策和决策部署,在履行职责过程中坚持和加强党对自然资源工作的集中统一领导,国土空间规划是国家空间发展的指南、可持续发展的空间蓝图,是各类开发保护建设活动的基本依据。 + +“绿水青山就是金山银山”“人与自然和谐共生”“良好生态环境是最普惠的民生福祉”“山水林田湖草是生命共同体”“中华民族永续发展的根本大计”等习近平总书记关于生态文明建设的系列科学论断深刻地回答了为什么建设生态文明、建设什么样的生态文明、怎样建设生态文明等重大理论和实践问题,构成了习近平新时代中国特色社会主义思想的重要组成部分,也是中国生态文明建设的根本指导思想,也为自然资源部的职能定位、国土空间规划编制实施提供了最重要的理论支撑和实践依据。 + +\subsection{探索以生态优先、人居环境绿色发展为导向的新路子} +(1)坚持“生态优先、人居环境绿色发展”,是积极应对全球气候变化、共建人类命运共同体、以一个负责任的大国对全球做出的庄严承诺。从全球竞争力视角看,推进绿色低碳发展将成为衡量一个国家是否能够被其他国家所接受和认同、融入全球共同价值观的重要标准,将推动一个国家占据道义制高点和战略制高点。 + +(2)坚持“生态优先、人居环境绿色发展”,是在资源环境紧约束条件下、秉持立足自身的资源安全观、实现两个一百年中国梦的必由之路。通过资源、能源的集约高效循环利用,实现单位消耗的产出提升,并逐步实现资源环境消耗与经济社会发展脱钩。 + +(3)坚持“生态优先、人居环境绿色发展”,是满足人民对美好生活需要、建设美丽中国的前提和基础。良好生态环境是最公平的公共产品,也是最普惠的民生福祉,既要创造更多物质财富和精神财富以满足人民日益增长的美好生活需要,也要提供更多优质生态产品以满足人民日益增长的优美生态环境需要。城市发展的逻辑从过去“人跟着产业走”,转变为“人才跟着环境走,产业跟着人才走”,山清水秀的诗意栖居之地成为容纳新人才、孕育新经济的载体,成为城市的核心竞争力。 + +\subsection{生态文明下的国土空间导向} +\subsubsection{1.国土空间是山水林田湖草“生命共同体”} +习近平总书记指出:“生态是统一的自然系统,是相互依存、紧密联系的有机链条。”必须从系统工程和全局角度寻求新的治理之道,更加注重综合治理、系统治理、源头治理,实施好生态保护修复工程,加大生态系统保护力度,提升生态系统稳定性和可持续性。统筹山水林田湖草沙系统治理,深刻揭示了生态系统的整体性、系统性及其内在发展规律,为全方位、全地域、全过程开展生态文明建设提供了方法论指导。 + +国土空间是以自然生态环境为基底、承载人类多样化经济社会活动的综合性空间载体。从自然资源的整体性与系统性角度合理统筹国土空间规划,达到人与自然之间的相互平衡关系,要求我们统筹好局部与整体、开发与保护、近期与远期的关系,实现人与资源之间和谐共生,经济社会可持续发展。 + +\subsubsection{2.生态文明建设是国土空间规划的灵魂} +生态文明建设是关系人民福祉、关乎民族未来的长远大计,是建设美丽中国、实现中华民族永续发展的根本保障,也是各级人民政府以及全社会的思想指南和根本标杆,生态文明建设是中国特色社会主义事业的重要内容,关系人民福祉,关乎民族未来,事关“两个一百年”奋斗目标和中华民族伟大复兴中国梦的实现,同时,生态文明建设也构成了国土空间规划最重要的时代背景,为国土空间规划注入了基于“绿水青山就是金山银山”的生态文明观和“山水林田湖草是生命共同体”的自然资源观,这两个科学观点在理论上构成了国土空间规划的灵魂和基石,在实践上则为国土空间规划编制实施提供了可操作、可应用的工作支点。可以预见,生态文明建设不仅能实现“既要金山银山,又要青山绿水”的战略目标,又必然能为中华民族永享集约高效的生产空间、优美宜居的生活空间、山清水秀的生态空间提供科学的世界观和方法论,其必将促进生产方法和生活方式的根本改变,进而促进中国经济和社会发展、自然生态环境保护的全新转型,从而为实现真正的可持续发展夯实基础。 + +在资源环境紧约束的条件下,统筹山水林田湖草沙系统治理,加强生物多样性保护,提升生态系统质量和稳定性,着力建设健康美丽的人居环境。唯有完整、准确、全面贯彻习近平生态文明思想,牢牢把握全面推动高质量发展的根本遵循,探索以生态优先、国土空间与人居环境和谐发展为导向的高质量发展新路子,方能实现中华民族的伟大复兴,也方能成为全球生态文明建设的重要参与者、贡献者、引领者。 + +第1章生态文明下的人居环境和国土空间 1 + +1.1我国人居环境发展历程 1 + +1.1.1原始时期 1 + +1.1.2古代时期 1 + +1.1.3近代时期 2 + +1.1.4现代时期 3 + +1.2我国传统人居环境的理念与人居环境学科发展 9 + +1.2.1人居环境的核心理念 9 + +1.2.2人居环境的科学发展 11 + +1.3生态文明演进与我国国土空间的生态安全问题 12 + +1.3.1生态文明的演进 12 + +1.3.2我国生态资源的基本情况 13 + +1.3.3我国生态资源环境挑战 13 + +1.4生态文明建设的基本观念 15 + +1.4.1历史思维:“生态兴则文明兴,生态衰则文明衰” 16 + +1.4.2全球思维:“共谋全球生态文明建设” 16 + +1.4.3底线思维:“坚守资源上限、环境底线、生态红线” 17 + +1.4.4民本思维:“良好生态环境是最普惠的民生福祉” 17 + +1.4.5整体思维:“坚持人与自然和谐共生” 17 + +1.4.6系统思维:“山水林田湖草是生命共同体” 18 + +1.4.7辩证思维:“绿水青山就是金山银山” 18 + +1.4.8法制思维:“用最严格制度最严密法治保护生态环境” 19 + +1.5生态文明建设的总体路径 19 + +1.5.1高水平保护——框定生态资源环境安全底线 20 + +1.5.2高质量发展——促进要素向优势地区集聚 20 + +1.5.3高品质生活——满足人民美好生活需要 21 + +1.5.4高效能治理——推进空间治理体系和治理能力现代化 21 + +1.6生态文明下的人居环境与国土空间和谐共存 21 + +1.6.1探索以生态优先、人居环境绿色发展为导向的新路子 22 + +1.6.2生态文明下的国土空间导向 22 + + + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +时期 & 特征 & 人居环境情况 & 影响 \\ +\hline +先秦 & 源起与发轫 & 中国人居雏形初现;“聚——邑——都”的居住演化;人居环境整体经营体系已大致形成 & 先秦时期人居的演进,从聚落到国家,反映出“世界”的变迁以及“世界观”的形成与发展,在中国人居史上,先秦时期具有开篇的意义 \\ +秦汉 & 统一与奠基 & “天下人居”支撑体系构建形成。中国开始在世界人居体系中发挥影响和作用(丝绸之路与世界沟通),人居发展中文化的影响加大 & 秦汉时期在前所未有的大一统的局面下,在人居建设的多方面进行了探索和创造,奠定了此后两千年中国人居环境的大框架和基础 \\ +魏晋南北朝 & 交融与创新 & 重视自然之美、多元人文融合创新。都城人居模式继承秦汉,并进行新的探索(轴线在都城中的使用) & 魏晋南北朝时期虽然社会动荡不安,但是南方与北方不同民族在分裂中进行人居文化的交融与创新,呈现出勃勃生机 \\ +隋唐 & 成熟与辉煌 & 中国人居走向成熟与辉煌。逐步形成“建筑——规划——园林”制度。“礼乐教法”营造秩序成熟 & 隋唐人居是在秦汉开创的基础上,继承了魏晋南北朝的遗产,广泛吸纳世界优秀文明的人居精华后,进行了新的融合,中国人居走向成熟与辉煌,走向世界,影响深远 \\ +宋元 & 变革与涌现 & 古代科技经济的快速发展,市民第一次作为城市的主导。人口增长影响城市格局 & 宋代是古代文化发展的黄金时代或“文艺复兴”时代,政治、经济、文化、科技等多重变化共同激发人居环境建设发生变革,从都城到地方都涌现出新的格局,达到了新的高度,整体呈现出“分水岭”的局面 \\ +明清 & 博大与充实 & 农业社会人居环境成就达到巅峰。中心文化交流,激发原有人居活力 & 明清时期是统一的多民族国家形成和巩固的重要时期,中国人居按照汉唐奠定的框架,继承宋元人居成就,进一步充实和完善,伴随着社会文化的发展达到了极致,形成了完备的人居体系。适应统一多民族国家的天下人居空间秩序在这一时期定型 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +城市类型 & 影响因素 & 城市 \\ +\hline +由帝国主义侵略、外国资本输入、本国资本的发展而产生较大变化或新兴起的城市 & 长期受某个帝国主义国家的控制 & 青岛、广州湾、哈尔滨、旅大等 \\ +由帝国主义侵略、外国资本输入、本国资本的发展而产生较大变化或新兴起的城市 & 处在几个帝国主义占据下,有特殊的租界地 & 上海、天津、汉口等 \\ +由帝国主义侵略、外国资本输入、本国资本的发展而产生较大变化或新兴起的城市 & 中国官僚资本或民族资本开办的新的工矿企业而兴起的新城市 & 河北唐山、河南焦作、湖南锡矿山、湖北大冶、玉门等 \\ +由帝国主义侵略、外国资本输入、本国资本的发展而产生较大变化或新兴起的城市 & 现代化交通影响下的城市发展 & 郑州、徐州、石家庄、蚌埠、浦口等 \\ +原来的封建城市受到帝国主义的侵入及本国资本主义的发展 & 长期作为封建统治中心的城市 & 北京、西安、成都、太原、南昌、长沙、兰州等 \\ +原来的封建城市受到帝国主义的侵入及本国资本主义的发展 & 由于资本主义工商业的发展而发生变化的城市 & 南通、无锡、内江、自贡等 \\ +原来的封建城市受到帝国主义的侵入及本国资本主义的发展 & 辟为商埠或设有租界的沿江沿海城市 & 南京、济南、沈阳、宁波、福州、芜湖、九江、重庆、万县、烟台等 \\ +原来的封建城市受到帝国主义的侵入及本国资本主义的发展 & 传统的手工业商业中心或位于交通要道的城市 & 临清、淮阴、淮安、扬州、浏河、嘉定等 \\ +\hline +\end{tabular} +\end{table} + diff --git a/data/book/chapter02.tex b/data/book/chapter02.tex new file mode 100644 index 0000000..3240e55 --- /dev/null +++ b/data/book/chapter02.tex @@ -0,0 +1,343 @@ +\chapter{自然资源与土地利用} +\section{自然资源的概念、构成与属性} +\subsection{自然资源的概念} +资源与自然资源是相互包含又有一定区别的一对概念,1972年联合国环境规划署(UNEP)把资源定义为“资源,特别是自然资源,是一定时间、一定空间条件下能产生经济价值以提高人类当前及将来福利的自然环境的因素和条件”。20世纪90年代学术界认为资源的内涵应当包括现存的各种自然要素及由其组合而生成的自然环境,既包括人类利用自然要素加工、改造、生产出的各种经济物品及由其组成的各种经济环境,也包括人类在上述基础上形成并不断增长的人口、知识、技术、文化、管理体制等均可称为资源。一般意义上认为,自然资源是指存在于自然界中,在现有生产力发展水平和研究条件下,为了满足人类的生产和生活需要而被利用的自然物质和能量。 + +以上对自然资源的诠释互有区别,但都包含了以下几方面的含义:一是自然资源不是脱离生产应用的抽象对象,而是在不同时空组合范围内有可能为人类提供福利的物质和能量;二是自然资源的概念、范畴不是一成不变的,随着社会的发展和科学技术的进步,人类对自然资源的理解不断加深,对自然资源开发利用的广度和深度不断提高;三是自然资源不同于自然环境,自然环境指人类周围所有的外界客观存在物,自然资源则是从人类的需用角度来理解这些因素存在的价值。从具体的对象看,它们往往是同一种物质,但又是两个不同的概念。 + +综合以上各种阐述,我们可以对自然资源做如下的定义:自然资源是指在一定的社会经济发展条件下,自然界中一切能够为人类所利用并产生使用价值的、能够提高人类当前或可预见未来生存质量的自然诸要素的总和。 + +\subsection{自然资源的类型} +由于自然资源的广泛性和多宜性,以及对自然资源理解的深度和广度的差异,学界目前还缺乏统一的自然资源分类系统。按照不同的目的和要求,自然资源有许多不同的分类方法和分类系统,下面列举几种常见的分类: + +\subsubsection{1.按自然资源的地理特性分类} +根据自然资源的形成条件、组合状况、分布规律及与地理环境各圈层的关系等地理特性,通常把自然资源划分为矿产资源(岩石圈)、土地资源(地球表层)、水资源(水圈)、生物资源(生物圈)和气候资源(大气圈)五大类。随着海洋地位的日益突出,海洋资源已开始作为第六类资源进入资源科学的研究领域。 + +\subsubsection{2.按自然资源的赋存条件及特征分类} +按照自然资源的赋存条件及特征分类的方法将自然资源分为两大类:地下资源和地表资源。地下资源赋存于地壳中,也可称之为地壳资源,主要包括矿物原料和矿物质能源等矿产资源。地表资源赋存于生物圈中,也可称之为生物圈资源,主要包括由地貌、土壤和植被等因素构成的土地资源,由地表水、地下水构成的水资源,由各种植物和动物构成的生物资源,以及由光、热、水等因素构成的气候资源等。 + +\subsubsection{3.按自然资源的特征分类} +按照自然资源的再生性特征进行分类的方法最为通用。按照自然资源的持续利用性,可将其分为耗竭性资源、非耗竭性资源两大类。耗竭性资源又可细分为可更新资源、不可更新资源两类。可更新资源主要是指由各种生物和非生物要素组成的生态系统,如土地资源、森林资源、水产资源等,在正确的管理和维护下,该类资源可以不断地被更新和利用;反之,则会遭到破坏乃至消耗殆尽。不可更新资源主要是指各种矿物和化石燃料;非耗竭性资源是指在目前的生产条件和技术水平下,自然界中的一些资源不会在利用过程中导致明显的消耗。非耗竭性资源又可细分为恒定性资源、易误用性资源两类,前者如风能、原子能、潮汐能、降水等,它们不会因人类活动而发生明显变异,故称之为恒定性资源;后者如大气、水能、广义景观等各种资源,当人们对它利用不当时会发生较大变异并污染环境,因此称之为易误用性资源。 + +上述几种分类体系中,对于自然资源研究和规划利用而言,更多地会采用自然资源的地理特性分类和自然资源的特征分类两种方法。 + +\subsubsection{2.1.3自然资源的特性} +自然资源具自然属性与社会属性。自然资源均具有一定的使用价值,是自然资源的天然属性,是人类开发利用自然资源的前提条件,具备了自然属性,从而形成明显的自然特征与社会特征相互依存的状态,通过人类的加工并使其成为商品进入流通领域,从而产生一定的经济价值。 + +\subsubsection{1.自然特征} +(1)有限性 + +自然资源具有一定的有限性,也可称之为稀缺性,也就是自然资源的数量供给与人类不断增长的需求存在着持续的矛盾。从这个意义上讲,世界上任何一种自然资源都存在相对有限性。不可再生的自然资源的有限性是绝对的;可再生的自然资源虽然可随时间的推移不断地再生或更新,但在一定的时间和空间内也是有限的,如一个地方单位面积上年平均太阳辐射量是一定的,一条河流上的水力资源是一定的,每亩地的粮食产量在一定时间及空间上也是一定的,过度开发和利用却会带来一定的问题,因此,从可持续发展的角度出发,合理利用和保护自然资源就显得尤为重要。 + +(2)系统性 + +各种自然资源在自然界中互相依存、互相制约,构成了完整的资源生态循环系统。系统中每个要素都承担着特定的作用,都是系统不可或缺的组成部分。其次,系统各要素之间互相联系,任何一种资源的改变都会影响到其他资源,子系统的变化不可避免地引起大系统的动态变化。对自然资源的开发利用要充分认识自然资源系统的系统性和整体性特点,不能只考虑某一要素或局部地区,要从区域资源的整体出发,树立系统论的思想,使系统结构比较稳定均衡地朝着有利于人居环境生活和生产的方向发展。 + +(3)地域性 + +地域性可称为自然资源具有的空间属性。地球生态环境中各自然资源在空间分布上都是不均匀的,在数量上或质量上都有显著的地域差异。各种自然资源都有其自身的地域分布规律,既受地带性因素影响,又受非地带性因素影响,有的同时受地带性、非地带性两种因素影响,如气候、水文、土壤和生物的地域分布主要受地带性因素的影响,但同时也受非地带性因素的制约;地质条件、矿产、地形与地貌等主要受非地带性因素的影响。在历史因素影响下,自然资源开发利用的社会经济条件和技术工艺水平也具有地域性差异,因此,自然资源系统的开发与利用要从资源的区域特点出发,因地制宜,发挥优势,形成具有区域特色的资源可持续开发利用系统。 + +(4)多元性 + +自然资源都具有多种文化和使用功能,各类用途很广。以森林资源为例,森林具有保护环境的功能,可以提供多种原料,产生多种不同的货币效益和土地利用效益,也具有文化旅游价值,它还是重要的物种基因库,在自然界物质和能量的循环交换中具有重要的生态作用等等,同时也要认识到,并非自然资源所有的功能及用途都具有同等重要的地位。在自然资源开发利用时要全面权衡,必须按经济效益、社会效益和生态效益相统一的原则,通过科学的优化方式选择最佳的综合利用方案,做到物有所值、地尽其利。 + +\subsubsection{2.社会特征} +(1)动态性 + +自然资源系统的动态性,一方面表现为自然资源在大自然各种因素下数量、空间、组成、时间的动态变化;另一方面表现为人类开发利用过程中产生的动态变化。为此,对自然资源系统的开发过程中要随时掌握其动态变化情况,适当的评价并采取相应的干预措施维护自然系统正常运转。 + +(2)社会性 + +自然资源与人居环境相互融合促进是人类持续利用自然、改造自然的结晶,是自然资源中的社会因素。人类通过生产活动,把自然资源加工成有价值的物质财富,从而使自然资源具有广泛的社会属性。自然资源是与一定的社会经济、技术水平相联系的,人类对自然资源的认识、评价和开发利用,都受特定时间、特定空间所制约,使自然资源的社会属性愈加突出。 + +\section{土地定义与土地管理制度} +\subsection{土地的定义} +\subsubsection{1.土地的定义} +“土地”是一个使用范围广、外延广泛的概念,自然科学(如地理学、农学等)认为广义的土地概念泛指整个自然界的自然资源,狭义的土地概念指地球表层陆地,上、下一定幅度内的三维空间;经济学认为未经人类加工过的自然土地资源以及人类在开发、改造、利用土地过程中形成的土地固定资产都是土地资产。 + +“土地”通常包括土地及其上生长的树木和多年生植物,也包括建造于土地之上并长久定着于土地上的人工构筑物(包括桥梁、涵洞、隧道、道路、各种建筑物等)。 + +综上所述土地的概念,认识“土地”的角度不同,对土地的定义和认识差别很大,到目前为止,关于“土地”的概念,得到认同并较流行的有以下四种观点: + +(1)认为“土地”是一切自然生成的及其生成源泉的环境因素。其中,自然生成的包括土壤、岩石、地貌、气候、水文和动植物等。 + +(2)认为“土地”是地球表层上、下幅度内的三维空间,即“土地”是由土壤、岩石、地貌、气候、水文及其动植物组成的自然综合体。 + +(3)认为“土地”是指地球的陆域表层,即除海水以外的地表,包括淡水资源(江、河、湖泊、沼泽等)。 + +(4)认为“土地”和“土壤”是同义词,其自然特性包括客观存在性、数量有限性、位置固定性、永续利用性。其经济特性包括土地所有制的重要性、土地的广阔性、造成农业生产的分散性、土地利用方向变更的困难性、供应的稀缺性。 + +\subsubsection{2.土地的经济特性与城市土地使用} +土地使用中积淀了丰富的城市活动内涵,是各类城乡活动的基础,社会、经济、政治、技术和环境要素等都会具体制约城乡土地使用的运行。对于城乡土地的使用,我们不能仅仅看到其各种物质空间的构成,更应看到在土地上人们所从事的丰富而复杂的活动,并透过这些活动看到其中的经济社会关系。 + +(1)城乡土地使用最显著的是区位性 + +城乡土地使用的区位揭示了城乡活动在空间地域上的相互关系,影响城乡土地使用区位的因素主要如下(见表2.1)。 + +表2. 1影响城乡土地使用区位的因素 + +(2)与土地使用密切相关的是土地使用强度 + +土地使用强度是单位面积的土地上承载城乡设施及各类活动数量的多少。土地使用强度不仅反映了城乡土地的环境质量,也显示了土地的可利用程度。不同的活动内容其要求的空间质量和开发程度有所不同,如办公、工业、住宅、商业、休憩等对城乡土地的使用强度都有其自身的不同要求,城乡土地使用及其区位和强度的分布,在城乡范围内形成了特定的空间关系,当其与交通路线和有关设施等相结合后,即构成了城乡的具体空间结构与形态。 + +\subsection{土地制度} +\subsubsection{1.土地制度及其模式} +中国传统文化认为“人脉在田、田脉在水、水脉在山、山脉在土、土脉在水,水脉在林草”。土是自然之本,土地制度是国家的政治、经济、文化、社会等制度的组成部分,也是国家各类政治经济构成制度中最为基础的制度。纵观世界,土地制度及其模式在内容上因各国历史沿革、土地所有制的性质和国情发展的不同而有所区别并无固定的模式。一般土地制度有广义和狭义之分,广义土地制度与土地所有判定、使用、管理等有关的一切制度;狭义的土地制度则指由土地所有判定、使用和管理的土地经济相关制度,以及相应法权制度所构成的土地产权管理制度。 + +概括而言,世界各国的土地使用制度一般有如下几种模式: + +完全市场经济模式 + +土地主要属于私人所有,土地可以在市场上自由买卖,其价值取决于市场的供与求的关系。这种模式以一些欧洲、美国、日本等国为代表,例如美国约60\%的土地为私人所有,而日本则是约70\%的为私人所有。这种土地的完全市场模式,较为准确地体现出土地的经济价值,对活跃土地市场有利,但也给各类国土空间规划的编制管理与实施带来困难。因此,完全市场模式国家对土地一般都有规定:在某些特定原因下,依照有关程序,国家或城市政府可以依法征用私人土地,如美国区划法中的一些规定,当然其实际征用难度往往是比较大的。 + +非市场模式 + +这主要是在沿革于近代苏联为代表的社会主义国家,当然包括计划经济时期的中国施行的土地制度。土地所有权归国家或集体所有,国家或集体可对土地使用进行统一调配,不允许私自转让或对土地买卖。据了解目前朝鲜、古巴等国仍然实行的是土地非市场化模式。 + +国家主导下的市场模式 + +按照相应国家法律的规定,土地的最终所有权全部归国家或国家的象征(如皇室)所有,市场主体或私人通过土地批租获得土地的占有权和使用权,国家从总体主导控制土地市场,当然控制的方式和程度各有不同,这种模式主要是在英国及其英联邦成员国(地区)中使用,我国目前的土地制度经过系列的改革,整体上也是属于国家主导控制下的市场经济模式。 + +\subsubsection{2.中国的城乡二元土地制度及其问题} +回顾中国上下5000年历史,土地制度的变迁与朝代兴亡密切相关。从古至今,中国的土地制度大致经历了氏族共有制、国家所有制、私人所有制、公有制等所有制形态的变迁。新中国成立后,在计划经济时期实行的是土地非市场模式,长期实行城市土地无偿使用的行政划拨制度造成了诸多的弊端(见表2.2)。 + +表2. 2土地无偿使用的弊端 + +鉴于以上种种问题,改革开放后我国启动推行农村与城市土地使用制度的全面改革,核心改革方向就是将土地所有权与使用权相分离,实行土地的有偿使用。《中华人民共和国宪法修正案》(1988年)中明确指出,“土地的使用权可以依照法律的规定转让”。除一些因特殊需要国家行政划拨的土地以外,大部分实行有偿、有限期出让的办法。经过长期的探索,从改革开放至今已逐步形成以公有制为基础,以保护耕地和节约用地为主线,以产权保护、用途管制和市场配置为主要内容的具有中国特色的土地使用制度。但是,由于中国城市和乡村发展的巨大鸿沟和长期的制度积累,目前,土地制度仍然存在二元分割状态。 + +(1)土地所有制 + +中国现行的土地所有制是社会主义制度下的土地公有制,即全民所有制和广大劳动群众集体所有制,土地的全民所有制采取国家所有制的形式,简称土地国有制,大部分存在于城市区域内,这种所有制的土地称之为国有土地,由国务院代表国家行使土地所有权。 + +土地的劳动群众集体所有制采取的是农民集体所有的形式,简称土地集体所有制,大部分位于乡村地区内,这种所有制的土地称之为农民集体所有的土地,简称集体土地,由农民集体行使土地所有权。农民集体是指有一定范围的农民集体,具体分为村农民集体,村内两个以上农民集体、乡镇农民集体等三种形式。农民集体所有的土地依法属于村农民集体所有的,由村集体经济组织或者村民委员会代表集体行使土地所有权;分别属于村内两个以上农民集体所有的,由村内各该集体经济组织或者村民小组代表集体行使土地所有权;属于乡镇农民集体所有的,由乡镇集体经济组织代表集体行使土地所有权。 + +(2)土地使用制 + +首先是城市土地使用制度,目前我国城乡国有土地实行有偿、有期限使用制度,把城乡国有土地使用权从所有权中分离出来,全面开放国有土地使用权市场。 + +国有土地使用权流转包括以下两种方式: + +方式一,土地使用权出让,即土地一级市场,可采取协议、挂牌、招标、拍卖、划拨等方式。其中,经营性建设用地、工业用地必须采用招标、拍卖、挂牌方式出让。 + +方式二,土地使用权转让、出租、抵押、授权经营、作价出资等。土地有偿使用制度的健全与完善,推动了土地市场的发展和经济发展方式的转变。 + +其次是农村土地使用制度,1982年发布的“中央一号文件”以及1988年《中华人民共和国土地管理法》,逐步确立了家庭联产承包责任制,农村土地实行集体所有、家庭承包的统分结合双层经营体制,这一制度有力促进了农村经济的发展,为改革开放初期的城镇化、工业化快速发展奠定了经济与社会基础。然而,随着市场经济的不断发展,农村土地制度开始面临新的问题,包括农业规模化、现代化发展的新需要,农村劳动力大量转移进入城镇、农村土地荒废问题等等。为此,2008年中共十七届三中全会确立了农村土地承包权长久不变的基调,同时农地三权分置(落实集体所有权、稳定农户承包权、放活土地经营权)的趋势加强。2019年1月1日施行的《中华人民共和国农村土地承包法》,使三权分置制度实现了从政策层面到法律层面的推进,同年通过的新《中华人民共和国土地管理法》修正了农村集体经营性建设用地进入市场的法律障碍,进一步明确了土地征收的公共利益范围,确定了征收补偿的基本原则,改革了土地征收程序,强化了农村宅基地权益保障。中共十八届三中全会要求加快建立城乡统一的建设用地市场和完善的现代市场体系,2019年中央全面深化改革委员会第八次会议审议通过《关于完善建设用地使用权转让、出租、抵押二级市场的指导意见》,对促进土地市场协调发展、加快建立城乡统一的建设用地市场具有重要意义。这些农村土地制度改革方面的重大突破,有力地促进了乡村振兴和美丽乡村战略的实施,但是破除城乡二元土地制度是一个长期、复杂的过程,需要谨慎、务实、切合国情的探索。 + +\subsubsection{3.土地产权特性与构成} +土地产权是指存在于土地之中的排他性权利,是以土地所有权为核心的土地财产权利的总和,土地产权问题是土地制度的核心问题。主要包括土地所有权、土地使用权、土地发展权、土地租赁权、土地抵押权、土地继承权、地役权等多项权利,具有如下特性和内容构成。 + +\subsubsection{4.土地产权的基本属性与构成} +(1)土地产权具有排他性 + +土地产权既可以是个体独立拥有,也可以是由某些人共同享有而排斥所有其他人对该项财产的权利。因此,土地的产权界定十分必要。 + +土地产权客体必须具有可占用性和价值性 + +土地产权客体是指能被占用而且可以带来经济利益的土地。在全球陆地上有近50\%的土地面积是永久冰盖物、干旱、沙漠地、岩石、沼泽、高寒地等难以利用或无法利用的土地,这些土地的财产界定问题就是价值性的问题。 + +土地产权的合法性 + +土地产权必须经过登记、得到法律的承认,才能受到法律的保护。例如,市场上土地产权合法流转时,必须依照法律规定程序到土地产权管理部门办理产权变更登记手续。 + +土地产权具有相对性 + +土地产权具有排他性,但并不代表就是绝对的权利,还要受到来自国家层面、社会层面的控制和制约。由于社会经济与政治制度的差异、法律体系的不同,每个国家都各自具有不同的财产权权利体系,但即使在土地私有制的国家,土地所有者的权利也必须受到政府一定的规制和约束,如国家重大发展规划的要求。 + +\subsection{土地利用规划与管理} +\subsubsection{1.土地利用规划概念} +作为一种资源,土地是以空间形态存在的。土地面积有限性和土地需求增长性是土地资源管理中永恒的主题,对土地利用实施科学的规划、管理有其客观的必要性,土地利用规划管理是为了合理利用和保护土地资源,维护土地利用的社会整体利益,组织编制和审批土地空间规划,并依据规划对城乡各项土地利用进行控制、引导和监督的行政管理活动。土地利用管理贯穿于国土空间规划编制、审批和实施的全过程,规划是管理的前提和依据,管理是规划依法科学制定和有效实施的保证。由此可见,土地利用规划管理也是面向社会的一种公共管理活动。 + +\subsubsection{2.土地用途管制} +土地用途管制是指国家为保证土地资源的合理利用,促进经济、社会和环境的协调发展,通过编制土地相关的空间规划,划定土地的不同功能用途分区并确定相应土地使用限制条件,土地所有者、使用者都必须严格遵守规划确定的用途来使用土地的制度体系。 + +土地用途管制是政府为了保障全社会的整体利益和长远利益,消除土地利用中的各种非理性现象,处理好土地利用中的各种矛盾,保证土地资源的可持续利用而采取的一种公共干预措施。从规划管理角度,土地用途管制的目标应包括以下几个方面: + +土地利用整体效益最大化 + +不同利益相关者的土地利用的价值取向是有较大差异的,土地所有者追求的是全社会土地利用整体利益最大化,政府一般从大的行政区域,统筹生态效益、经济效益与社会效益,实质就是要达到区域土地利用结构的最优化,即土地在各种不同用途之间的布局和有效配置。土地用途管制就是要解决在各种竞争性用途之间合理分配土地资源并提高土地的利用效益问题,既要考虑具体土地使用者的切身利益,也要从宏观全盘考虑社会整体利益,通过规划谋求两者之间的平衡。 + +协调“粮食安全”与“城乡建设”的矛盾 + +我国是一个人多地少、人均土地资源相对短缺的国家,土地利用矛盾十分突出,特别是随着人口不断增加、经济的高速发展和城镇化程度的不断提高,农业与非农业各类建设之间争地的矛盾十分突出。必须通过土地用途管制,强制性地控制建设用地的数量与区位,对耕地实行特殊保护,如土地粮食生产面积红线等以保障国家的粮食安全。当然,土地利用的根本目的是满足人们的各种合理需要、对美好生活的向往,土地用途管制的目的就是要对有限的土地资源在数量上、时间上和空间上进行合理的分配,以统筹保障城乡各种用途的土地供给需求。 + +尽力避免土地利用中的外部性影响,保护生态环境,实现土地的可持续利用 + +土地在空间上互相连接在一起,不能移动和分割,但由于自然界和人为因素导致土地明显受到外部各类冲击。对于土地利用产生的积极外部性应该充分加以利用,对于不利的外部性影响必须加以避免和限制。因此,必须通过土地用途管制,来达到保护和改善生态环境、实现广大土地资源可持续利用的目标。 + +\section{国土空间土地用途管制} +\subsection{空间用途管制的源起与发展} +中共十九大以后,国家提出了建立国土空间规划体系并监督实施的要求,相应也就出现了国土空间用途管制。国土空间用途管制是土地用途管制的延展,从发展过程分析,可划分为土地用途管制(耕地)、生态要素用途管制、自然生态空间用途管制、国土空间用途管制四个递进式逐步全要素管制的发展阶段。 + +土地用途管制阶段 + +1980年之前,空间管制主要是土地用途管制,是对生产性耕地进行管制。 + +生态要素用途管制阶段 + +1980年代开始,在国家强化土地用途管制特别是耕地用途管制后,地方政府为规避监管或实现耕地总体占补平衡,开始占用重要的生态用地和低丘级坡地进行城乡建设,挤占了大量的绿色生态空间,危及了区域的生态环境。为解决林地、耕地、草原、湿地等生态和生产用地减少等问题,国家逐步加大了对部分生态用地按要素分门别类开展用途管制,建立生态要素用途管制制度。这种制度有利于突出管制重点,但对大范围的生态系统的整体性、全面和系统性考虑不足,用途管制政策的协调性也不够。 + +自然生态空间用途管制阶段 + +2013年中共十八届三中全会首次提出“建立空间规划体系,划定生产、生活、生态空间开发管制界限,落实用途管制”,以及“完善自然资源监管体制,统一行使所有国土空间用途管制职责”的总体要求。2017年国土资源部印发《自然生态空间用途管制办法(试行)》,提出建立覆盖全部自然生态空间的用途管制制度,加强“山水林田湖草”整体保护、系统修复、综合治理,标志着空间用途管制进入自然生态空间用途管制的阶段。 + +国土空间全用途管制阶段 + +2017年中共十九大报告首次明确要求对全部国土空间均实行用途管制。由于土地空间管理的权限分散在不同管理部门,“权责不清”“九龙治水”的现象十分普遍,导致行政效率低下,用途管制政策缺乏协同,难以对空间进行有效管理。为了解决生态要素管制的部门分割,提高国土空间用途管制的效能,中央决定设立国有自然资源资产管理和自然生态监管机构,统一行使所有国土空间用途管制和生态保护修复职责。2018年将国土资源部的主要职责、住房和城乡建设部的城乡规划管理职责、国家发展和改革委员会的主体功能区规划职责、水利部的水资源调查和确权登记管理职责、农业部的草原资源调查和确权登记管理职责、国家林业局的森林和湿地等资源调查和确权登记管理职责、国家海洋局的职责、国家测绘地理信息局的职责等进行整合,新组建自然资源部,统一对自然资源开发利用和保护进行监管,建立空间规划体系并监督实施。国土空间规划以空间治理和空间结构优化为主要内容,是实施国土空间用途管制和生态保护修复的重要依据。2019年5月中共中央、国务院印发《关于建立国土空间规划体系并监督实施的若干意见》,进一步指出要以“空间规划体系为基础,国土空间用途管制为手段,实现国土空间治理体系与治理能力的现代化”,“多规合一”使国土空间用途管制的机构、依据、权责等内容基本明确。 + +\subsection{国土空间用途管制的方法} +针对不同利益群体之间国土空间开发与保护目标取向的多重性,政府会使用行政权力介入国土开发利用的各环节,保证国土空间规划意图和管控要求的传导,实现保护资源环境、保障经济发展的目标。国土空间用途管制,是指在国土空间规划确定的空间用途、开发利用限制条件等的基础上,在国土空间准入许可、用途转用许可、开发利用监管等环节对各类国土空间用途或功能进行监管。用途管制是实施国土空间规划的核心机制和手段。国土空间用途管制是在摸清国土空间范围内自然资源现状的基础上,划定“三区三线”管控要求,实施差别化的区域准入制度,明确城乡全域各种土地用途转换规则,最终建立起从国土空间资源现状到规划蓝图的管理机制,国土空间用途管制要用规则规范各主体的行为和利益约束,主要方法包括以下方面: + +(1)设置空间准入条件。不同类型国土空间的自然与经济属性是有较大差别的,要根据保护目标和开发利用特点,制定不同的空间准入和用途转用规定。上级政府通过制定符合未来发展要求的开发利用与保护条件(如土地用途、建设性质、强度、布局、生态环境保护等),并要求各级政府、职责部门严格依法进行项目预审和审批,确保使用者具有依据管制规则开发利用国土空间的能力和意识。 + +(2)限制国土空间用途转用。统筹各类国土空间保护与合理利用,实现“耕地保有总量、森林覆盖率、自然岸线保有率、环境品质质量”等同步提升。通过严格限制国土空间用途转用,维护国土空间规划的严肃性,保证各类开发利用活动符合资源环境承载力和国土空间开发适宜性等基本评价要求。增强刚性约束力和弹性调节灵活性,总量严格管控与年度规模动态调整相结合,以保障国家需要的项目落地;建立严格用途转用下的弹性调节方法。对基本农田、自然资源岸线、生态红线内区域要强化其管制刚性,原则上禁止改变用途;对其他一般性农用地、生态空间等,允许各地根据所在地区社会经济发展需求进行合理调整,但必须设置严格的调整规定,同时,对土地要探索以“盘活存量”取代“占补平衡”的调节方式,鼓励以“盘活存量”的方式来满足城乡新发展空间的需求。 + +(3)强化土地利用监督。从实现国家国土空间开发与保护的核心目标出发,必须加强对国土开发利用的严格监管,对开发利用者各种偏离国家利益的倾向形成威慑,约束开发利用行为,使国土空间开发利用符合国土空间规划预期的目标,从区域、功能区、地块三个层次加强监管(见表2.3)。 + +表2. 3土地利用监管内容 + +\subsection{国土空间用途管制的内容} +\subsubsection{1.城镇开发边界内外的管控} +城镇开发边界是一条有形的界限,边界内属于城镇空间,是实施城市规划、建设和管理的主要区域;边界外属于生态空间和农业空间,是我国实施乡村振兴战略、落实生态保护与国家耕地保护政策的主要区域。城镇开发边界概念源于20世纪70年代美国提出的“城市增长边界”,为了抑制城市无序蔓延、实现精明增长而采取的一种“增长管理”手段,可被视为一种城市土地管理和空间治理的政策集成工具,划定和实施城镇开发边界的目的,在于控制城市发展的规模和引导其空间发展方向,保护自然资源和生态环境,进而实现城镇与整个国土空间的可持续发展。划定城镇开发边界是实施新型城镇化战略的有效举措,是推动生态文明建设、落实最严格耕地保护制度和节约集约用地制度的重要保障,亦是国土空间规划管制的重要内容。 + +(1)管控要求 + +城镇开发边界内的管控应以“严控增量、盘活存量、集约复合、弹性适应”为原则,建设用地管理应符合城镇规划用途管制要求,协调刚性管控与弹性管理的关系。城镇开发边界外,除因规划需要确需建设的线性工程用地(交通、水利)、能源等基础设施用地、特殊用地,原则上不能组织开展城市市政基础设施和公共服务设施建设,不得颁发城镇建设用地规划许可,不可安排土地征转、提供建设用地指标,另外,城镇开发边界外的农村建设活动,应符合村庄规划和农民建房的相关规定。 + +城镇开发边界内外建设用地的差异化政策。对于城镇开发边界内的建设用地管控,实施刚性约束和弹性管控相结合。对边界内城镇空间规模的刚性约束是管控的重点内容;同时,城镇规划建设用地规模边界作为弹性控制线被引入,即允许城镇规划用地的布局在规模不变的前提下根据实际发展情况进行一定的微调,以提高城镇规划建设用地的弹性;建设项目在有条件建设用地内的选址,应符合一定的程序和条件,确保选址的合理性。 + +对城镇开发边界外的建设用地实施分类管控:一方面,对于现状建设用地原则上应逐步迁出、不再新建;另一方面,对于新的建设需求严格管控。由于未来发展具有不确定性,有些项目如物流建设等项目有可能需要在城镇开发边界外进行,对于这类项目应可制订差别化的管控措施,依据其开发建设需要对规模、功能、程序等进行规定,一定规模以下的特定功能区的建设,可以经法定程序批准即可建设;而超过一定规模的建设活动,则需先修改城镇开发边界才能进行。 + +(2)管控机制。城镇开发边界内应建立对用地使用主体的发展引导机制。根据土地的自然条件、区位条件、经济社会条件和城市各类发展规划,将城镇开发边界内的可开发建设区域按主要功能区的方式划分为优先发展区、允许发展区、限制发展区等;不同的发展区域在用地指标供给、建设条件控制、转让交易限制、管理税费等方面实施差异化政策,以促进开发边界内的可利用土地空间更为有序、有效利用。而在城镇开发边界外,依据生态保护、耕地保护优先原则,积极构建生态补偿机制。一方面,通过分区管控,将城镇开发边界外的区域划分为核心生态保护区、一般农林资源区、其他用地区、城市发展备用区等,既体现了生态保育的底线思维,也为城镇开发边界机动有序地调整做好准备;另一方面,城镇开发边界以外的地区应在保护之外更强调生态奖励政策,如通过生态补偿奖励跨地区转移支付等政策措施,平衡一些地区因生态保护、耕地保护而导致的发展权损失,激发地方生态保育、保护耕地、优化格局的积极性。 + +\subsubsection{2.永久基本农田管控} +耕地即专门种植农作物并能够正常收获的土地,广义上是指维持人类生存及农业可持续发展的基本资源,我国《土地利用现状分类》(GB/T21010-2017)中,将其划分为熟地、新开发、复垦、整理地和休闲地等不同类型。土地管理中一般将农田分为永久基本农田与一般农田。 + +永久基本农田,指能保障一定时期人口及经济社会稳定发展的农产品需求,在国土空间规划中所确定的不得占用的耕地,相应的,除永久基本农田以外的其他农田则为一般农田。永久基本农田是优质、连片、稳定、永久的耕地,一旦划定就要实施永久性保护,是保障国家粮食安全、促进绿色农业和精品农业发展,以及实施乡村振兴战略的重要载体。我国的永久基本农田与许多国家的优质农地、重要保护农地等概念相似,皆在农业生产保护中发挥重要作用。 + +划定永久基本农田并实行高标准保护,是我国贯彻落实最严格的耕地保护制度的基本要求,是维护国家层面粮食安全和社会稳定的关键举措。加强永久基本农田控制线管控,对生态文明建设阶段实施,乡村振兴战略和优化城镇空间布局等方面都具有重要意义,对于永久基本农田的保护与管制,主要包括统筹管控性保护、建设性保护、激励约束性保护等方面。 + +(1)管控性保护,即要求落实严格保护永久基本农田要求,从严管控非农建设活动占用永久基本农田。永久基本农田一经划定,任何单位和个人不得擅自占用或者擅自改变用途,禁止破坏和闲置荒芜永久基本农田。 + +坚决防止永久基本农田“非农化”,除法律规定的国家重点能源、交通、水利、军事设施等建设项目选址无法避让的之外,其他任何建设都不得占用。加强永久基本农田保护红线管控,在开展城镇建设活动和基础设施布局等相关规划过程中,不得突破永久基本农田保护红线;确有重大工程、特殊项目无法避让永久基本农田的,必须经过充分的可行性论证和依法审批,按照“保护优先、布局优化、优进劣出、提升质量”的原则和永久基本农田保护调整程序进行。 + +(2)建设性保护,加大永久基本农田及其配套设施的建设力度,开展高标准永久基本农田建设,改良土壤质量,提高永久基本农田的质量和品质等级,完善耕地质量监测体系,开展相关的耕地质量评定与评价工作。因地制宜地划定永久基本农田整备区,将土地整治补充的优质耕地、新建成的高标准农田优先纳入永久基本农田补划储备库,为永久基本农田补划和布局微调整创造条件。 + +(3)激励约束性保护,即要求完善永久基本农田保护激励约束机制,落实永久基本农田保护责任。重点是落实政府考核评价机制和耕地保护激励机制,严格考核审计,严肃执法监督。建立和完善耕地保护激励机制,充分调动农村集体经济组织、农民管护和建设永久基本农田的积极性,建立健全永久基本农田社会共管体系。 + +\subsection{城乡建设用地的统筹管控} +城乡建设用地涉及内容、类型十分广泛,其规模、分布与地区经济社会发展状况密切相关,同时也受到规划用途管制,并存在总量和增量的约束性限制。城乡建设用地是区域发展、城镇与乡村人口、经济社会发展的重要载体,其总量和增量规模既受到人口规模和经济发展水平的影响,又会反向促进或制约人口规模和经济发展。目前,虽然我国总体上已度过城镇规模扩张阶段,进入城镇更新阶段,处于城乡扩展与存量土地低效并存的情况,因此,城乡建设用地节约集约利用仍然是我国建设用地用途管制的重点。 + +当城乡建设用地总规模接近甚至突破土地利用规划限定的“天花板”时,城乡发展必须由“外延式扩张”转向“内部更新式发展”,通过实施“存量”用地挖潜和盘活机制(诸如城乡建设用地增减挂钩、农村建设用地整治、城市更新等),以控制建设用地“总量”、减少建设用地“增量”盘活城乡建设用地“存量”并提升用地“质量”、用好城乡建设用地“流量”,即通过“五量”协同,多途径共同实施对城乡建设用地的有效管控,以实现建设用地节约集约利用的目标。 + +实施城乡建设用地的用途管制,实行城市建设用地总量、增量、存量、流量和质量“五量”协同管控(见表2.4)。 + +表2. 4城市建设用地管控原则和措施 + +\subsection{土地用途分区} +\subsubsection{1.土地用途分区} +国土空间规划是实施土地用途管制的依据,土地用途管制是落实和实施国土空间规划的手段。土地用途分区是土地用途管制的重要内容和核心。土地用途分区,是对土地利用类型区的划分,一般分为地域分区、用地分区。地域分区是指依据规划区域的自然条件、资源的区域特征、土地利用现状、社会经济发展水平与发展前景差异等情况,确定不同区域土地利用的方向、结构与布局的宏观分区;用地分区则是指依据具体土地的适宜性特点,结合国民经济和社会发展的需求与条件,确定具体地块未来用途的微观分区(一般是在城镇开发边界内与村庄建设区进行)。划分土地用途分区时,应该考虑如下原则: + +原则一:宏观分区应针对各地的具体情况,留有余地,使分区具有一定的战略性、灵活性。 + +原则二:微观分区应以主导用地类型为主,同时有条件、有限制地允许一些其他利用类型的存在,以保证实际操作中有一定的应变弹性。 + +原则三:应当体现空间层次性,用途类型的划分要在同一尺度、同一层次上进行。按土地主导用途的一致性进行一级分区,将同一主导用途下的差异性在二级分区中体现出来。 + +原则四:应当体现并满足政府对土地利用控制的需要,保证分区控制具有法律化、制度化的支撑。 + +针对不同用途的分区制定相应的管制规则,是土地用途管制的重要内容。要依据分区管制规则,制定不同层面、不同类型的国土空间规划。城镇用地的分区管制规则,应包括土地用途的规定、地块规模限制、土地利用强度(容积率、建筑密度、建筑物高度、人口容量等)限制、环境条件(空地率、绿化率)限制、安全间距(防火间距、消防通道等)限制、相邻关系限制、红线(道路红线、建筑后退红线)限制等。乡村土地的分区管制规定,应包括土地用途的规定、用途变更的规定、非主导用途使用规定、地块面积规模与设施水平限制、土地利用中的禁止行为(如农业用地分区内不得建窑、建坟、挖沙、采石、取土、堆放固体废弃物等)。 + +\subsubsection{2.土地用途管制的实施管理} +所谓土地用途转变,是指土地利用从一种现状用途转变为另一种用途的过程。对于符合分区管制目标的用途应予以引导,对于不符合者应加以限制或否决,土地用途转变要执行规划许可制度,也就是采取颁发规划许可证的办法以控制土地用途的改变。 + +农用地转移的管制可分为限制转移管制、许可转移管制两类。所谓限制转移管制,即依据国土空间规划,划定一定数量的农用地(主要是耕地)作为特殊保护区域严格加以管制,如划定永久基本农田保护区,对于这类特殊保护区域不得进行转用,或必须经过严格审批程序并满足占补平衡等要求后方可转用,以保持农用地保有量的平衡和稳定,所谓许可转移管制,即根据规划布局的要求,允许一部分农用地进行规定用途的转用。 + +非农用地用途管制主要包括增量非农业建设用地、存量非农业建设用地的用途管制,其中增量非农业建设用地的用途管制与农用地许可转移管制密不可分,存量非农业建设用地的用途管制是指存量建设用地土地利用结构调整和土地利用方向置换的管制。当前存量土地用途管制的对象主要有以下几个方面: + +一是土地使用用途因用地功能的改变而发生的调整,如旧城改造、污染企业搬迁、产业“退二进三”等;二是土地使用用途和方式因土地使用、经营方式的改变而发生的调整,如原地翻建等;三是因土地资产处置方式发生变化的调整,如划拨土地入市、企业改制土地资产的处置等;四是对低效使用或闲置土地的再利用。 + +除此之外,对生态用地也应该实行用途管制,以明确保护和适当使用的规则。需要指出的是,土地用途管制并不意味着规划的土地用途是绝对不可改变的。因为,影响土地利用的经济社会条件及其他条件随着时间的推移而在不断地发展变化,人们对未来发展的预见能力、认识能力是有限的,规划内容与实际发展之间的偏差不可避免,客观上对国土空间规划、土地用途管制也提出了必要的动态调整要求。 + +第2章自然资源与土地利用 24 + +2.1自然资源的概念、构成与属性 24 + +2.1.1自然资源的概念 24 + +2.1.2自然资源的类型 24 + +2.2土地定义与土地管理制度 26 + +2.2.1土地的定义 27 + +2.2.2土地制度 28 + +2.2.3土地利用规划与管理 31 + +2.3国土空间土地用途管制 32 + +2.3.1空间用途管制的源起与发展 32 + +2.3.2国土空间用途管制的方法 33 + +2.3.3国土空间用途管制的内容 34 + +2.3.4城乡建设用地的统筹管控 36 + +2.3.5土地用途分区 37 + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 特征 & 构成 \\ +\hline +1 & 空间环境 & 每一项土地使用都会对城市及特定位置的自然条件和人文环境提出特有的要求 \\ +2 & 空间可达性 & 这些土地位置在城市活动中的交通方便程度,不同的活动会选取特定的交通方式,对空间可达性的具体要求也不一样 \\ +3 & 费用 & 从事一项土地使用活动所需花费的成本,包括区域配套的基础设施的投入以及资金的时间成本 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +序号 & 问题 & 表现 & 影响 \\ +\hline +1 & 土地产权模糊 & 土地名义上归国家或集体所有,划拨使用以后却归各用地单位实际上所有 & 导致土地的所有权与使用权相模糊、混淆 \\ +2 & 土地资源浪费 & 计划经济体制由于实行行政划拨土地,否定了土地价值与价格的差异,因此往往造成用地单位“圈而不用”“少用多圈”等极为浪费土地的行为 & 进一步加剧了土地资源的紧张局面 \\ +3 & 土地资源配置不当 & 土地的经济特性无法在行政划拨中表现出来 & 导致土地资源配置不当,各种用地行为相互掺杂,功能分区混乱,低效益的用地往往占据着城市中优越的区位,土地效能发挥不出来 \\ +4 & 土地所有者管理主体不明确,土地收益流失 & 由于否认城市土地价值的存在,且土地所有权与使用权不清,国家无法获得由土地带来的相应收益,而这部分收益却往往成为用地单位的无偿所得 & 进一步导致了城市建设资金无法得到有效的保障,城市配套设施难以改善,环境质量恶化 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 层面 & 内容 \\ +\hline +1 & 区域 & 加强对各级行政区域范围内城镇建设、农业生产、生态保护三类国土空间的综合监管,侧重对约束性指标数量和质量的双重考核 \\ +2 & 功能区 & 加强对各类功能区内开发与保护现状的监管,尤其是对城镇空间、农业空间、生态空间的实际开发与保护绩效进行评价和监管 \\ +3 & 地块 & 重视对项目落地实施情况的监管,完善建设项目用地或用海控制指标,加强对使用者执行空间准入前置条件的考核(包括建设项目容积率、投资强度、绿地率等具体指标,以及各类生态修复项目的实施成效等) \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +序号 & 原则 & 措施 & 备注 \\ +\hline +1 & 总量控制 & 在不突破土地利用规划总量的前提下,可适度增加区域建设用地规模并用于城乡基础设施建设、区域产业发展和生态环境保护等功能 & 在发展过程中,应合理确定各区域土地开发强度控制目标,严格落实建设用地空间管制制度,科学划定城镇开发边界、优化空间结构转变,有效控制建设用地总量 \\ +2 & 增量递减 & 利用差别化与市场化方式配置新增建设用地,优先支持重大基础设施建设、保障性住房和战略性新兴产业发展 & 加大存量用地在供地中的比重,建立增量用地计划与存量用地盘活的指标配比机制,逐渐降低年度增量用地,稳定总量规模 \\ +3 & 存量优化 & 查清城镇低效用的范围,明确可盘活存量用地规模、空间分布、利用方向和开发时序;着力开展闲置土地专项清理,依法加大查处力度或予以收回,有效提高建设用地批后供地率和使用率 & 依法依规有序开展农村集体经营性建设用地的流转,逐步建立城乡统一的建设用地市场,通过存量用地盘活促进区域内涵发展 \\ +4 & 流量增效 & 流量增效。通过建设用地“减量瘦身”来倒逼城市功能提升,鼓励城镇空闲土地再开发,盘活农村建设用地和推进工矿废弃地复垦利用 & 规范有序开展城乡建设用地增减挂钩与城市更新工程,确保城乡建设用地总量不增加、结构更优化;探索农村宅基地退出条件和补偿机制,促进城乡协调发展 \\ +5 & 质量提升 & 健全城镇建设用地产业准入和建设项目用地节地评价制度,依据节地评价结果确定供地规模 & 探索土地使用权退出机制,以及工业用地长期租赁、先租后让、租让结合等供地方式;引导土地立体开发、功能复合利用,逐步实现区域零增量供地和空间高效发展 \\ +\hline +\end{tabular} +\end{table} + diff --git a/data/book/chapter03.tex b/data/book/chapter03.tex new file mode 100644 index 0000000..bebc675 --- /dev/null +++ b/data/book/chapter03.tex @@ -0,0 +1,600 @@ +\chapter{城乡空间规划思想与理论发展} +阳光是万物之源,土地是万物之本,土地资源是人类生存的基础,也是生态环境可持续发展的重要保障。伴随着人类认识和科学技术的发展,对土地的了解和研究也在不断地深化,随着国土空间规划的推进,土地资源管理与利用成为国家生态文明建设的重要组成部分之一,对于土地资源的认识和学习是国土空间规划原理的重要构成。 + +\section{我国城乡规划思想与理论发展} +长期以来,基于我国城乡发展规划与各类建设管理的需要,各级各类部门及相关法律法规政策衍生了一系列自上而下的规划体系,其中最具有代表性的除城乡规划体系和土地利用规划体系外,尚有主体功能区规划和生态环境保护规划类型,从“多规合一”需求出发,有必要理清各类规划在历史沿革核心理论与时间上的异同及核心目标。 + +\subsection{中国古代城市规划思想与理论} +\subsubsection{1. 雏形城市时期} +考古证实,中国最早的城市雏形产生于原始社会末期的龙山文化时代。这一时代出现了中国第一批古城邑——由夯土墙或石墙围绕起来的大型聚落,但是由于它并不具备城市的实际职能与文化形态,因此只是一种“带围墙的村庄”。直到公元前1500年左右,随着奴隶社会的较大发展,商代产生了第一批相对完整意义上的早期城市。 + +(1)居民点产生于第一次劳动大分工——农业、畜牧业的发展 + +原始社会,人类主要依附于自然生活,过着穴居、树居等群居生活,然而这时并没有形成固定的居民点。在原始社会后期,随着社会生产力以及农业、畜牧业的发展,人类不再需要长期的迁徙奔波,可以定居生活,因此原始群落中就产生了从事农业与从事畜牧业的分工,也就是人类的第一次劳动大分工。到了新石器时代的后期农业成为主要的生产方式,此时逐渐产生了固定的居民点。人们的生活与农业均离不开水,所以原始的居民点大都靠近河流、湖泊,大都处于“山之阳”、“水之阴”的台地上,为了防御野兽的侵袭和其他部落的袭击,往往在原始居民点外围挖筑壕沟,或用石、土、木等材料筑成墙及栅栏,这些沟、墙是一种防御性构筑物也是城池的雏形,我国的黄河中下游、埃及的尼罗河下游、西亚的两河流域都是农业发展较早的地区,在这些地区的农业居民点以及在居民点的基础上发展起来的城市也出现得最早。 + +(2)城市形成于第二次劳动大分工——手工业、商业的发展 + +金属工具的使用,进一步提高了生产力,原始部落生产水平的提高,也促进了需求的多样化,使手工业从农业中分化出来,即产生了第二次劳动大分工,出现了一些专门的手工业者。与此同时,随着交换量的增加及交换次数的频繁逐渐出现了专门从事交易的商人以及物品交换的场所,也就是固定的市场。原来的居民点也逐渐融合,人口更加聚集,逐渐发展成为城市,居民的生活条件逐渐提升从而有了剩余产品,有了剩余产品就产生私有制,原始社会的生产关系也就逐渐解体,出现了阶级分化,人类开始进入奴隶社会。所以也可以说,城市是伴随着私有制和阶级分化在原始社会向奴隶制社会过渡时期出现的。世界上几个古代文明的地区城市产生的时期有先有后,但都是这个社会发展阶段中产生的。 + +\subsubsection{2.古典城市时期} +中国古代文明中有关城镇修建和房屋建造的论述,总结了大量生活实践的经验,其中经常以阴阳五行和堪舆学的方式出现。虽然至今尚未发现有专门论述规划和建设城市的中国古代书籍,但有许多理论和学说散见于《周礼》、《商君书》、《管子》和《墨子》等政治、伦理和经史书中。 + +夏代(公元前21世纪起)就对“国土”进行全面的勘测,国民开始迁居到安全处定居,居民点开始集聚,向城镇方向发展。夏代留下的一些城市遗迹表明,当时已经具有了一定的工程技术水平,如陶制的排水管的使用及夯打土坯筑台技术的采用等,但总体上,在居民点的布局结构方面都尚原始,夏代的天文学、水利学和居民点建设技术为以后中国的城市建设规划思想的形成积累了物质基础。 + +在西周至战国时期(约公元前11世纪至公元前2世纪末),中国城市逐步形成了“城郭分野相依”的古典形态格局。春秋战国是中国历史上第一个“筑城运动时期”,也是第一次城市建设的高潮。西周作为中国奴隶制社会发展的重要时代,形成了完整的社会等级制度和宗教法礼关系,对于城市形制也形成了相应的严格规则。《周礼·考工记》记载的“匠人营国,方九里,旁三门,国中九经九纬,经涂九轨,左祖右社,前朝后市,市朝一夫”。成为影响中国几千年古代城市营建的基本范式,对中国传统城市的礼制风格产生了重大的影响。《周礼·考工记》中对于不同城市营建的等级也有严格的规范,如“建国立城邑,有定所,高下大小,存乎王制”、 “大都不过三国之一,中五之一,小九之一”等等,这同样也是礼制规范的体现。 + +春秋战国时代是古代中国从奴隶制向封建制的过渡时期,群雄纷争和战乱频繁,也是各种社会变革思想蓬勃发展的“诸子百家”时代,这个时代也是中国古代城市规划思想的多元化时代,既有以《周礼·考工记》为代表的礼制营城规范;也有以《管子·乘马》为代表的山水有机营城思想,强调“因天材,就地利,故城郭不必中规矩,道路不必中准绳”的自然至上理念。例如,后来明代都城南京的规划就充分体现了管子的山水营城思想。在管仲的论著《管子·乘马第五》立国中有这样的描述,“凡立国都,非于大山之下,必于广川之上。高毋近旱而水用足,下毋近水而沟防省。因天材,就地利,故城郭不必中规矩,道路不必中准绳”。从中可知,当时已经非常重视城池规划选址。会注意利用山川地利之便,让城市有险可依,除了根据具体的地理条件因地制宜,城池建设还要讲究经济性。这些理论对后来城市规划都有着重要的影响。 + +\subsubsection{3.中期传统城市时期} +中期传统城市时期大约从公元前2世纪末的秦汉到唐代末期。汉武帝时代为巩固皇权统治,“废黜百家,独尊儒术”,儒家的核心思想就是社会等级、宗法关系,从此,《周礼·考工记》所代表的礼制思想开始对中国封建社会城市的规划建设产生了主体性的影响。从曹魏邺城、唐长安城到元大都、明清北京城,《周礼·考工记》对城市形制尤其是都城的影响极其深远。这一时期城市规划建设的主要特征有三点城市的整体性加强,组合成一个紧密的整体;受“尊儒崇礼”思想的影响,城市内部各功能要素在布局上呈现出尊卑有别的礼制秩序;具有严格的功能分区和“里坊”制度。 + +\subsubsection{4.后期传统城市时期} +后期传统城市时期大约从北宋到 19世纪末的晚清。由于商品经济的发展,城市的功能日渐增多,尤其是经济、生活功能的强化,使得城市的世俗化特征日益明显,这一时期的城市规划一方面表现为对传统城市主体礼制风格的继承和发展,另一方面也开始出现了对严格的里坊结构、封闭的城垣形制的重大变革,这在一定程度上形成了适应商品经济发展而相对自由的城市风格。北宋时期,商品经济和世俗生活的发展开始冲破《周礼·考工记》的礼制约束,首都汴梁城(开封)出现了如《清明上河图》所描绘的那样熙熙攘攘的商业大街,封闭的“里坊”制度开始解体。 + +总体而言,中国古代城市规划建设的思想、理论主要受到以下因素的影响: + +(1)早期的耕作制度。“井田制”奠定了中国早期城市方格网状的空间格局的基本形式,如《周礼·考工记》中所用的“夫”就是井田的丈量单位。 + +(2)传统的营建技法。如中国早期的城市大多出现在北方平原地区,受当时当地的气候与建筑材质的影响,出现了封闭的院墙体系及方正平直的格局。 + +(3)特有的文化观念。如天圆地方说、天人感应等思想,表现在城市中象征性的构图和布局;阴阳五行思想和易学说,表现在城市布局中对方位、数字、对偶等的应用;相土形胜风水说,尤其表现在城市规划的选址与总体格局中。 + +(4)封建政治制度。封建政治制度所形成的特有文化价值观念也左右着城市规划的思想,如《礼记·乐记》中讲道:“礼者,天地之序也;乐者,天地之和也。序,故群物兼别;和,故百物兼化。”所以,我国古代城市规划尤其强调等级尊卑、序列感。 + +(5)社会经济发展形态。不同经济社会发展时期,城市功能的变化会导致城市形态,营建风格的相应变化。例如,北宋汴梁城出现里坊解体和沿街买卖的现象,就是市场经济和市民阶层发展壮大的结果。 + +\subsection{中国近代城市规划思想与理论} +近代中国受到西方社会经济与思想文化的强烈冲击,具有典型的半殖民地、半封建社会的特征,城市规划发展围绕两条基本脉络展开:一是西方外来资本主义社会经济形态及其相伴随的新的城市物质要素和结构形式的渗入,由点及面、由渐及盛的扩展过程;二是本土传统的封建社会经济形态在外来资本主义社会经济形态的强大影响下逐步解体,并被动地重构新型城市的艰难过程——表现为对西方模式的照搬或“中国化处理”。可以说,中国近代城市规划的发展演变始终围绕着中国传统城市规划的近代化,以及西方城市规划思想的本土化而展开。 + +这一时期,中国城市规划开始受到西方城市规划思想的广泛影响。起初主要是向租界、殖民城市学习,洋务运动后开始直接派遣中国留学生学习西方城市建设技术与规划方法,诞生了第一批具有西方留学背景的市政、公共卫生、建筑与城市规划专业人才,极大地推动了中国城市规划向近代科学的转型,在半殖民地半封建的时代背景下,一部分中国城市的发展与建设始于帝国主义的殖民活动,殖民者在其长期占领的城市中围绕其掠夺和侵占目的展开规划建设,这一类型的典型城市包括青岛、哈尔滨、大连和长春等;近代交通的快速发展催生了一批因区位优势而得到发展建设的城市,以郑州、蚌埠、石家庄等为代表;此外,还有随着民族资本工商业的发展而进行的城市规划与建设活动,如南通、无锡、汕头等。 + +近代中国城市规划的理论与实践表现为两大类:一类完全套用当时西方所流行的规划思想和手法,甚至直接由西方人进行规划,例如大量的租界城市;另一类引入西方的学说并进行“中西结合”的应用,哈尔滨早期俄国人做的“新城规划”在世界上代表了最先进的规划理念,它融合了霍华德的规划思想和巴洛克风格,形成的方格网与放射状的路网格局、有轨交通、绿化系统以及独有的建筑特色使哈尔滨成为具有多元文化特色的国际性城市。 + +\subsection{新中国成立后城市规划思想与理论} +新中国成立后,社会体制的巨大变革影响到社会经济发展的方方面面,城市规划与建设也进入一个新的发展阶段,但是过程曲折,中国的城市规划根据国家和社会的需要在逐渐演进,以推进生产力布局为核心目标,城市规划思潮的演变可以划分为以下五个阶段: + +\subsubsection{1.建国初期的城市规划} +1949年至1960年代初,新中国刚刚成立,百废待兴,这时城市规划的核心任务是落实生产力的布局。这一时期国家经济由于多年战争濒临崩溃,又同时受到西方资本主义阵营的孤立与排挤,内忧外患的发展环境迫使新中国选择全面倒向苏联,在政治、经济、社会等各个领域建立了以自上而下计划为特征的运行体制,中央政府通过统一的计划对国民经济社会发展实行全面管理,并通过城市规划向地方政府分配建设资源。在城市规划的理论与实践中,停止引用西方规划理论,转而全面学习苏联规划理论与模式。将城市作为主要用于工业生产的载体,强调“变消费型城市为生产型城市”,生活空间被极度压缩,城市生活设施被作为工业生产的配套则按照最简单、最经济的原则进行,以尽可能地降低工业化、城市化的成本。这一时期的规划被作为在空间上落实国民经济建设计划和重大项目布局的工具,其主要职责是服务于工业生产和计划落地的需要,规划思维体现出强烈的自上而下、计划性、指标性和工程技术性色彩。 + +在新中国成立初期的10年间,城市规划被纳入计划经济体系,成为国民经济和社会发展计划的延续与空间落实,作为指导生产项目布局和城市建设的技术工具,与国家经济社会发展需求紧密结合,在支撑短时间内建立社会主义工业体系方面做出了巨大贡献。 + +\subsubsection{2.文化大革命时期的城市规划} +1960年代初至“文化大革命”结束这段时期,我国的城市规划深受极左主义思潮的影响。1960年代后,在“极左”思想影响下政治运动席卷全国,经济社会事业多处于废弛停顿状态。城市规划被视为“扩大城市差别”的“修正主义”而受到了批判,曾经作为落实发展计划重要工具的城市规划也走向低潮,只有在应对国家重大工业项目建设需求时,才有限地开展城市规划工作。这一时期的城市规划思想仍然深受苏联模式的影响,计划经济色彩依旧较为明显。 + +\subsubsection{3. 改革开放初期的城市规划} +1970年代末至1990年代初,我国的城市规划向科学理性主义回归。“文化大革命”结束后,国家迎来改革开放浪潮,西方国家的规划思想与理论随同资本、技术等一并进入中国,科学主义的社会思潮在当时的中国蔚然成风,城市规划研究与实践也显著表现出对“科学化”的强烈追求。城市空间被抽象为点、线、面组合而成的系统,数学模型等计量方法被运用于对城市空间演化过程及规律地模拟,在城市规划领域得到积极应用。这一时期的城市规划非常注重对城市空间演化规律的研究,引入了西方许多关于城市研究、城市规划的理论和方法。尤其是经济地理(城市地理)等理科力量的介入,将综合思想、科学分析思维引入中国规划界,为城市规划提供了崭新的研究领域、研究视角和研究方法,开启了中国城市规划多元化发展的局面。 + +\subsubsection{4.全球化初期的城市规划} +1990年代中期至2010年代初,随着全球化进程的快速发展,我国的城市规划更加趋近于用地扩张的增长主义思潮。随着全球化的深度和广度不断拓展,1990年代初中国顺应时代浪潮进一步扩大对外开放,明确提出建立社会主义市场经济体制。1990年代推进了分税制、分权化、城乡土地使用制度、住房市场化等一系列重大的改革,中央政府在赋予地方政府更多权力、更多可支配资源的同时,也将更多的增长压力转移至地方,促成了“增长主义”政策体制与城市扩张式的发展特征。国家和社会治理思想的变化、央地关系的调整及市场化转型,都深刻地影响了这一时期中国城乡规划的理论与实践选择,这一时期的城乡规划在相当程度上扮演了支撑政府实现增长主义目标的手段,成为地方政府经营土地等城市各类资产、管控空间秩序和营造景观环境的重要工具,更承担了提高城市竞争力、促进城市发展的重要任务。 + +单一增长目标导向下的经济高速发展与快速的城镇化进程,迅速暴露出种种问题:城市空间无序扩张,城乡之间、区域之间发展不平衡加剧,经济增长与社会、文化、生态等多元发展目标之间极度失衡……有鉴于此,2003年后中央提出了“科学发展观”“五个统筹”“和谐社会”等一系列思想,对GDP 为中心的经济发展方式进行修正,促进经济、社会、生态等各个方面的统筹,更加重视民生、区城和乡村等方面,规划的工作领域也真正开始从“城市规划”拓展至“城乡规划”。在2008年新实施的《中华人民共和国城乡规划法》中,城乡规划的属性明确实现了从“工程技术”向“公共政策”的转变。然而,增长主义模式的巨大惯性难以在短期内根本扭转,地方政府仍然奉行增长主义的发展策略,中央政府与地方政府之间的发展价值取向、关注的核心利益产生了越来越大的偏差,城乡规划在服务国家新发展理念与满足地方增长主义诉求之间艰难平衡,缺乏一以贯之的内在价值体系和行为准则,表现出比较明显的“价值观—行动分裂”。 + +代表性纲领:北京宪章1999年,由吴良镛起草的《北京宪章》,以人居环境科学理论为基础,在国际建筑师协会第20届世界建筑师大会上通过,标志着人居环境学说被世界建筑学界普遍接受和推崇,扭转了长期以来西方建筑理论占主导地位的局面。 + +《北京宪章》指出“可持续发展”是人类共同的选择,它不仅表现在它对环境问题的科学分析,更重要的是提出了可持续发展的城市规划原则,即将“规划建设、新建筑设计、历史环境保护、一般建筑的维修与改建、古旧建筑合理地重新使用、城市和地区的整治、更新与重建、以及地下空间的利用和地下基础设施的持续发展等纳入一个动态的、生生不息的循环体系之中”。 + +《北京宪章》发挥了东方系统思想的优势,在深入了解未来的发展态势、广泛吸收现代科学理论的基础上,提出了“广义建筑学”理论框架。它认为:对建筑学有一个广义的、整合的定义是新世纪建筑学发展的关键; 反对将建筑学这一“共同的问题”分割成单独论题的做法,它提倡“从局部走向整体,并在此基础上进行新的创造”思维方式。运用科学的认识论和方法论揭示了建筑历史发展规律,建立了当代建筑科学理论体系,它将发挥重大的理论指导作用,提出用辩证系统思维作为基本方法论,既肯定了分析的作用,更强调有机综合的科学价值。 + +《北京宪章》提出了符合生态原理的建筑设计原则,即用新陈代谢的客观规律和循环体系的观念,将建筑的生命周期的概念,融入人居环境建设过程之中——不仅结合建筑的生产与使用阶段,还要基于“最小的耗材、少量的‘灰色能源’消费和污染排放、最大限度地循环使用和随时对环境加以运营、整治”。 + +\subsubsection{5. 新型城镇化时期的城市规划} +2010年后,全球进入后金融危机时代,全球生产、贸易分工格局及金融体系发生深刻变化,中国发展的内外环境日益严峻,中共十八大、十九大做出中国经济步入“新常态”的判断,提出深化改革、美丽发展、创新发展等一系列新目标,以及“五大发展理念”生态文明建设、高质量发展、国内国际双循环等新要求。国家发展的价值取向、模式与路径都发生了重大转变,持续了近20年的增长主义模式走向终结,新时代的国家发展纲领不仅仅是应对和消化增长主义时期所累积的种种问题,而且要在更高的目标征程中解决“美好生活需要和不平衡不充分的发展之间的矛盾”,实现中华民族伟大复兴的中国梦。在此背景下,城乡规划的功能角色、社会认知及其思想方法均发生了显著的变化,并开始启动与国土空间规划相融合的工作。 + +(1)需要从治国理政的高度来认识、理解城乡规划。城乡规划不仅从工程技术明确转向了公共政策,而且成为国家实现治理体系和治理能力现代化的重要组成部分,要在国家多层级治理架构下发挥对国土空间的规范、协调等重要作用,同时也将在“政府—市场—社会关系”调整中发挥更加突出的作用。 + +(2)城乡规划的价值取向发生重大转变。从长期以来强调(或者事实上)促进城市经济增长、城镇化数量水平提高等“数字目标的增长”,转变为关注以人为中心的新型城镇化,促进高质量发展、区域协调发展、城乡可持续发展、社会和谐共享等一系列“综合目标”的实现,国土空间规划要求中央、地方各级政府承担起更加综合有力的资源与空间管控职能,实现对资源的更好保护与更高效利用,促进形成更加均衡、美丽、永续的国土空间格局。 + +(3)城乡规划的内容重点发生重大调整。从长期保障城市发展增长的需求,转变为生态优先、引导发展、刚性管控,不再是“以需求定空间供给”,而是首先要明确生态环境保护的基底、耕地保护的底线,以有限的空间供给来约束无限的空间增长需求。 + +(4)更加强调中国本土规划的理论与实践探索。由于过去长期照搬苏联和西方的理论、经验,中国城乡规划在过去发展中出现了“一手的规划实践,二手的规划理论”的尴尬现象。中共十八大以后,在“四个自信”的指引下,中国城乡规划的理论与实践发生了明显转向,强调构建中国本土规划的理论体系,增强民族自信、传承中国文化、总结中国经验,进而向世界贡献解决问题的“中国方案”,在雄安新区规划、北京通州新行政中心区规划等工作中,得到了鲜明的体现。 + +(5)更加强调城乡规划的引领地位、科学性、严肃性与持续性。中央对城乡规划高度重视,提出要认识、尊重、顺应城市发展规律,科学决策、科学规划;明确了城乡规划(国土空间规划)要发挥“战略引领、刚性管控”的作用;提出要坚守规划要求,要坚持“一张蓝图干到底”,要有“功成不必在我”的持之以恒的精神等等。 + +\subsubsection{6.全面推进国土空间规划以来的城市规划} +2019年5月,中共中央、国务院印发《关于建立国土空间规划体系并监督实施的若干意见》,标志着我国开始全面推进并实施国土空间规划。这是我国未来推进生态文明建设、实现高质量发展和高品质生活的关键举措,也是促进国家治理体系和治理能力现代化的必然要求,国土空间规划的实施不但要实现“多规合一”,更提出了全域全要素的管控要求,国土空间规划与传统意义上以发展建设为主体导向的城乡规划有所差异,也不同于注重管控思维的土地利用规划,而是在生态文明理念下对空间规划的重构,将传统规划的内容从建成环境扩展到全域全要素,体现了国土空间规划的战略性、约束性、系统性和权威性等特征。 + +改革开放以来,中国工业化和城镇化取得了举世瞩目的成就,但也带来了一系列可持续发展的问题,如社会经济和资源环境的矛盾日益突出、区域发展差距不断扩大、土地利用粗放严重等,尤其是随着城乡建设用地不断扩张,农业和生态用地空间受到挤压,城镇、农业、生态空间矛盾加剧,不同空间尺度都存在着人和自然之间、生产和生活活动之间、自然生态系统内部关系不尽协调的矛盾。在新型城镇化与城乡统筹发展的背景下,解决经济高速增长、社会快速转型中存在的国土开发秩序混乱和资源环境代价沉重等问题一直是可持续发展领域的重大科学命题。 + +2018年4月,中华人民共和国自然资源部正式成立,城乡规划的相关职责也由建设部调整到自然资源部之中。2019年5月23日,中共中央、国务院《关于建立国土空间规划体系并监督实施的若干意见》正式公布,标志着国土空间规划体系顶层设计和“四梁八柱”基本形成。机构合并为国土空间规划体系的构建奠定了基础,但体系的构建还需要思维方式转变和过往经验总结的有效结合,要做到水乳交融、知行合一,才能真正确保构建“全国统一、责权清晰、科学高效”的国土空间规划体系。 + +构建国土空间规划体系是我国推进生态文明建设的客观要求,是关系到国民经济与社会能否长期、持续、健康发展的重要工作,是国家推进生态文明建设、全面统筹经济社会发展、合理高效配置资源、协调发展与保护及解决规划“打架”问题的重要手段,也是实现国家治理体系和治理能力现代化的重要路径。 + +\section{西方城市规划思想与理论发展} +人类经济社会发展的阶段性特征使得城乡规划思想与理论同步发展。一般将自古希腊到18世纪下半叶工业革命前称为“古代城市规划时期”,其中又将古希腊、古罗马时期称为“古典城市规划时期”,将中世纪及文艺复兴前后称为“中古城市规划时期”;将工业革命以后至20世纪初称为“近代城市规划时期”,这是城乡规划思想理论层出不穷并逐步走向独立学科建设的重要时期;将20世纪初以后至今的时期统称为“现代城市规划时期”。 + +\subsection{西方古代城市规划思想与理论} +从公元前5世纪到公元17世纪,欧洲先后经历了从以古希腊和古罗马为代表的奴隶制社会,到封建社会的中世纪、文艺复兴和绝对君权等几个重要的历史时期。随着经济社会和政治背景的变迁,不同的政治势力占据着社会主导地位,不同的思想、价值观占据着文化主导地位,不仅带来了不同城市的兴衰,而且也深刻地影响着城市规划的思想和实践,透过西方古代城市发展的复杂过程,可以看出城市规划思想演化的一条基本脉络,即人文主义思想与君权(神权)思想的穿插交锋。 + +\subsubsection{1.古希腊时期的城市规划思想} +古希腊是欧洲古典文明的圣地,也是西方文明的基础。在爱琴海边的希腊半岛及其周边地中海沿岸等地方,逐步形成了数十个相对稳定的奴隶制城邦国家,其中最繁荣的有雅典(Athens )、斯巴达(Sparta )、米利都(Miletus )、科林斯(Corinth )等。在公元前5世纪古希腊经历了奴隶制的民主政体,形成一系列城邦国家,并从政权体制上确立了民主共和的思想,这一思想甚至深刻影响着现代西方的社会与政治体系,古希腊的城市规划思想体现出如下一些特征: + +(1)城邦与公共空间精神。古希腊人认为社区的规模和范围应当使其中的居民既有节制而又能自由自在地享受轻松的生活。古希腊人在城市的艺术、文化、体育等领域的全面拓展,建设了卫城(圣地),成为希腊城邦精神的化身和有形体现。公元前5世纪,雅典卫城就已成为希腊人宗教与公共活动的中心,希波战争胜利以后其更被视为国家、民族的象征场所,强调给公民以平等的居住条件,包括雅典在内的许多希腊城市都以方格网划分街坊,贫富住户混居在同一街区,仅在用地大小与住宅质量上有所区别。古代希腊人基本的生活方式以公共生活为特征,这种生活方式塑造了古代希腊城市的基本特征,反映在空间格局上,是每个城邦的中心都是一个开放的中心广场。以雅典为例,它的中心广场位于卫城的北坡下面,城市中还要体育场、剧场等的公共空间。各种公共场所一道构成了丰富多彩的城市公共空间体系,成为希腊人多姿多彩的户外生活的载体,进一步激发了古希腊人的公共意识与思辨精神。 + +(2)宗教与人本思想并存。在古希腊的宗教中,表现的是对多个自然神的崇拜,神、人“同形同性”。古希腊人在崇拜众神的同时,更承认人的伟大和崇高,笃信人的智能和力量,重视人的现实生活。城市中大量的公共活动促进了市民平等、自由和荣誉的增长。雅典卫城以及其他圣地建筑并非膜拜神灵的禁地,而更是市民公共活动的中心,是古希腊人本主义的象征。 + +古希腊建筑中通过柱廊所围合出的半公共场所、许多开敞的城市广场空间一道构成了丰富多彩的城市公共空间体系,成为希腊人多姿多彩的户外生活的载体。特别是圣地建筑的重要性,已经远远超越了传统的宗教祭祀职能、防御职能而成为城邦公民举行礼仪活动的场所和公共活动的中心,成为古希腊公共生活的反映、公众鉴赏的对象。 + +\textbf{代表性城市规划:}\textbf{希波丹姆斯模式} + +在古希腊的城市规划中,随着古希腊美学观念的逐步确立和自然科学、理性思维发展的影响,也产生了另一种显现强烈人工痕迹的城市规划模式—希波丹姆斯模式。 + +希腊哲学家Pythagoras(前580一前500)认为:“数为万物的本质,宇宙的组织在其规定中是数及其关系的和谐体现。”亚里士多德则说:“美是由度量和秩序所组成的”,建筑物各部分间的度量关系就是比例,他主张对城市的规模和范围应加以限制,使城市居民既有节制又能自由自在地享受轻松的生活。基于柏拉图、亚里士多德等人有关社会秩序的理想,公元前5世纪的法学家希波丹姆斯在希波战争后的城市规划建设中,提出了一种深刻影响后来西方二千余年城市规划形态的重要思想—希波丹姆斯模式,他因而也被誉为“西方古典城市规划之父”。希波丹姆斯模式遵循古希腊哲理,探求几何与数的和谐,强调以棋盘式的路网为城市骨架并构筑明确、规整的城市公共中心,以求得城市整体的秩序和美。在历史上,希波丹姆斯模式被大规模地应用于希波战争后城市的重建与新建以及后来古罗马大量的营寨城,古希腊的海港城市米利都城(Miletus),普南城等都是这一模式的典型代表,影响了近代西方许多殖民城市的规划形态。 + +\subsubsection{2.古罗马时期的城市规划思想} +古罗马时代是西方奴隶制发展的繁荣阶段,古罗马先后经历了城邦时代、共和时代与帝国时代,在此过程中,古罗马是完全依靠强大的武力(罗马军队为代表的国家行政机器)而存在的,所有这些都保障了一个强大的中央集权国家的建立,城市风格明显表现出君权化、军事化的特征。 + +罗马共和国后期和帝国建立以后,城市更成为统治者、帝王宣扬他们功绩的工具,广场、铜像、凯旋门和纪功柱等成为城市空间秩序组织的核心和焦点,古希腊时期那种纯粹的市民公共活动,已经基本让位于有组织渲染的种种歌颂“伟大罗马”的整体性纪念活动,诸多广场也由最初的集会场所演变成了纯粹的纪念性空间。罗马城是君权化特征最为集中体现的地方,重要公共建筑的布局、城市中心的广场群乃至整个城市的轴线体系,一起透射出王权至上的理性与绝对的等级、秩序感,象征着君权神圣不可侵犯,这与东方帝国的城市特征有着本质的一致。 + +古罗马城市规划、建筑设计的指导思想和重要任务之一,就是体现罗马国家强大的政治力量和严密的社会组织性。彰显繁荣与力量的大比例模数建设思想,是为了使城市和建筑显现出一种具有征服力的崇高感和震撼感,罗马人在实践中通常热衷于选择大比例模数,许多建筑的空间尺度与规模远超其功能需要。例如古罗马的许多广场、斗兽场、公共浴室、宫殿等都达到了超人的空间尺度和规模。古罗马在城市的总体空间创造方面重视空间的层次、形体和组合,并使之达到宏伟与富于纪念性的效果,高超的空间设计手法以及对建筑群体秩序的把握,成为了后世城市规划设计的典范。 + +\textbf{代表性著作:}\textbf{《建筑十书》} + +维特鲁威是古罗马杰出的规划师、建筑师,公元前27年其撰写的《建筑十书》力求依靠当时的唯物主义哲学和自然科学的成就,对古罗马城市建设的辉煌业绩、大量先进的规划建设理念和技术进行历史性总结。《建筑十书》分十个篇章,分别总结了自古希腊以来的城市规划、建筑经验,对城址选择、城市形态、城市布局、建筑建造技术等方面提出了精辟的见解,是一本百科全书式的成果。《建筑十书》奠定了欧洲建筑科学的基本体系,在文艺复兴以后更作为西方建筑学的基本教材达三百余年之久。维特鲁威继承了古希腊的许多哲学思想和城市规划理论,提出了他的理想城市模式,在这个理想城市模式中,他把理性原则和主观感受结合起来,把理想的美和现实生活的美结合起来,把以数的和谐为基础的毕达哥拉斯学派的理性主义同以人体美为依据的希腊人文主义思想统一起来,强调建筑物整体、局部以及各个局部之间和整体之间的比例关系,充分考虑城市防御和方便使用的需要。 + +\subsubsection{3.中世纪欧洲城市的规划思想} +西罗马帝国灭亡后,欧洲进入漫长的中世纪,欧洲分裂成许多小的封建领主王国,封建割据和战争不断,社会生活中心转向农村,手工业和商业萧条,城市处于衰落状态。在这一时期,教会势力变得十分强大,教堂占据了城市的中心位置,教堂的庞大体量和高耸尖塔成为城市空间布局和天际轮廓的主导因素。在中世纪的欧洲,宗教神权思想占据了绝对统治地位,人性受到压抑,君权也受到牵制,战争频繁,城市建设极为有限,人们一般称之为“黑暗的中世纪”。 + +由于中世纪的城市发展缓慢,缺乏大规模的人工规划干预,所以形成了十分自然有机的城市形态、亲切的空间尺度、宜人的景观环境,使得中世纪的欧洲城市景观具有独特的魅力,常常得到我们今天的赞誉。10世纪以后,西欧的手工业和商业逐渐兴起,一些区位优越、工商业经济发达的城市逐渐摆脱了封建领主的统治。在这些城市中,公共建筑(如市政厅、关税厅、行业会所等)开始占据城市空间的主导地位,中世纪后期,随着手工业和商业的持续繁荣,一些市民的思想与精神在逐步复苏。 + +\subsubsection{4.文艺复兴与绝对君权时期的城市规划思想} +14世纪初开始的文艺复兴是欧洲资本主义,人本主义的萌芽时期,艺术、技术和科学都得到飞速发展,文艺复兴实际上是早期资本主义对其价值观的一种宣扬,但限于当时政治力量的对比格局,只得打出复兴“古希腊、古罗马”文化的旗帜,其核心是宣扬人性解放,实质是为了建立资产阶级的价值观和秩序,但由于资产阶级此时还没有真正登上统治社会的舞台,因此,在城市规划建设中主要还是集中于对单个建筑或城市片区的小规模营建与改造。 + +在17世纪后半叶,新生的资本主义迫切需要强大的国家机器提供庇护,而君主政权又需要利用资产阶级强大的物质力量和积极的斗争精神来约束和对抗教会。资产阶级与国王结成联盟,共同反对封建割据和教会势力,这一时期在欧洲建立了一批统一而强大的中央集权、绝对君权国家,进行了大规模的城市改造和城市建设运动。随着君主政权的强大,古典主义与唯理主义在欧洲的文学、艺术等方面占据绝对统治地位,城市规划思想也追求抽象的对称和协调,寻求纯粹几何结构和数理关系,强调轴线、放射和主从关系,以凸显永恒、王权至上的主题。 + +\subsection{西方近代城市规划思想与理论} +\subsubsection{1.近代城市规划产生的历史背景} +16世纪末至17世纪初,欧洲爆发的资产阶级革命将整个西欧都推上了资本主义制度的发展轨道,资本主义制度代表了一种更为先进的生产关系,带来17世纪后半叶至18世纪生产力的大飞跃,并最终引发了18世纪下半叶席卷欧洲的工业革命。到了19世纪,整个西方社会基本上都建立了资本主义制度并迎来了机器大生产的时代,人类的文明与社会发展从此掀开了新的历史篇章。 + +由于工业生产方式的改进和交通技术的发展,传统的古典城市空间结构已经无法适应新的发展现实,农业生产劳动率的提高和资本主义制度的建立,导致大量破产农民向城市集中,各大城市都面临着人口的爆发性增长,人口的快速增长使得城市原有的居住设施严重不足,旧的居住区不断沦为贫民窟,提供给工人的新建廉价住房更是粗制滥造,不仅设施严重缺乏,基本的通风、采光不能满足,而且居住密度极高,服务配套设施不全,导致了传染疾病的大范围流行,这种糟糕的城市环境卫生状况加剧了社会矛盾,引起了社会各阶层人士的关注,从19世纪中叶开始,西方国家出现了大量有关寻求解决城市问题方案的讨论,诸如霍华德的“田园城市”、玛塔的“带形城市”、戈涅的“工业城市”、西谛的城市形态研究等等,成为现代城市规划思想和理论形成的重要基础。 + +\subsubsection{2.近代城市规划的探索实践} +(1)空想社会主义的启蒙。早在资本主义社会早期,面对资本家对农民、工人极端残酷的剥削,很多怀有社会良知的先驱们已经开始质疑资本主义制度的合理性,并思考和探索理想的国家、城市形态,他们普遍认为,推翻、埋葬资本主义制度,建立以公有制为主体、消灭剥削的民主社会,是解决剥削问题的根本途径,这些思想家们的各种理论与概念被统称为“空想社会主义”。 + +近代历史上的空想社会主义思想最初起源于英国人文主义者托马斯·莫尔(Thomas More,1478-1535)的“乌托邦”概念,随后又影响了圣西门(Saint-Simon, 1760-1825)、查尔斯·傅立叶(Charles Fourier,1772-1837)、罗伯特·欧文(Robert Owen,1771-1858)等多位空想社会主义者。这些空想社会主义者不仅通过著书立说来宣传和阐述他们对理想社会的坚定信念,同时还通过一些实验来推广和实践自己的理想。虽然空想社会主义者的理论、实践在当时的西方世界中几乎没有产生实际的影响,但是这种先进的思想和理念却对后来城市规划思想理论(包括霍华德的“田园城市”理论)的发展产生了重要的作用。 + +(2)英国关于城市卫生和工人住房的立法。1842年英国政府提出了《关于英国工人阶级卫生条件的报告》,这一报告成为政府开始关注城市卫生状况和工人住房问题的转折点。1848年英国通过《公共卫生法》,规定了地方当局对污水排放、垃圾堆积、供水、道路等方面应负的责任。由此开始,英国通过一系列卫生法规建立起一整套对城市卫生问题的干预和控制手段。对工人住宅的重视促成了如1868年的《贫民窟清理法》、1890年的《工人住房法》等一系列法规的出台。英国改善城市居住环境的行动对欧洲国家产生了巨大影响,19世纪中叶后“公司城”作为资本家就近解决工人的居住需求,提高工人的生产力而出资建设和管理的小型城镇,开始在西方各国大量出现。 + +(3)城市美化运动。通常所说的“城市美化运动”,主要是指19世纪末至20世纪初欧美许多城市为缓解日益严峻的城市病、恢复城市的良好环境和吸引力而进行的一系列景观改造活动。城市美化运动首先开始于美国,其前奏是1850年代末开始的“公园运动”,在奥姆斯特德(Olmsted)的率领下,纽约在1859年首先建设了第一个现代意义的城市开敞空间—纽约中央公园。城市美化运动的目的是通过创造一种新的物质空间形象和秩序,恢复城市中由于工业化的破坏性发展而失去的视觉美与和谐生活,从而改进人们的生存环境。后在芝加哥等地持续进行了大量实践,这种景观环境改造理念改善了城市运行机能,开创了促进城市中人与自然相融合的新纪元,并催生了后来景观建筑学、园林规划和城市绿地规划等学科的兴起与发展。 + +\subsubsection{3.现代城市规划的奠基:田园城市理论} +在19世纪中期以后的种种社会改革思想和实践的影响下,英国人霍华德(E. Howard)于1898年出版了《明天:通往真正改革的平和之路》(Tomorrow:a Peaceful Pathto Real Reform)的论著,提出了著名的“田园城市”(Garden City)理论。“田园城市”的提出,既标志着近现代城市规划学科出现了比较完整的理论体系和实践框架,也标志着现代城市规划的诞生。 + +针对当时城市(尤其是像伦敦这样的大城市)所面对的城市问题,霍华德提出用一个兼有城市和乡村优点的理想城市—“田园城市”作为解决方案。“田园城市”是为健康、生活以及产业而设计的城市,它的规模足以提供丰富的社会生活,但不应超过这一程度;四周要有永久性的农业地带围绕:城市的土地归公众所有,由委员会受托管理。霍华德“田园城市”理论的整体思路形成过程大致如下(见表3.1)。 + +表3. 1田园城市理论整体思路形成过程 + +“田园城市”是一个综合的城市规划、发展、建设模式,不同于我们常说的以景观营建为主的“花园城市”。“田园城市”也不同于“卫星城市”,虽然“田园城市”是“卫星城市”的思想渊源,而且结构有类似之处,但本质区别在于:“卫星城市”中的中心城市与卫星城市的规模、功能相差极为悬殊,是对大城市、特大城市空间与功能进行疏解的一种手段;而“田园城市”是一组中心城市与周边田园城市规模、功能相差不大的平衡组群,强调的是城乡统筹发展形态。 + +概要而言,霍华德的“田园城市”对近现代城市规划发展的重大贡献在于以下方面: + +(1)在城市规划指导思想上,摆脱了传统规划用来显示统治者权威或张扬规划师个人审美情趣的旧模式,提出了关心人民利益的宗旨,这是城市规划思想立足点的根本转移。 + +(2)针对工业社会中所出现的严峻、复杂的城市问题,摆脱了就城市论城市的狭隘观念,从城乡结合的角度将其作为一个体系来解决。 + +(3)设想了一种先驱性的模式,一种比较完整的规划思想与实践体系,对现代城市规划思想及其实践的发展都起到了重要的启蒙作用。 + +(4)首开了在城市规划中进行社会研究的先河,以改良社会为城市规划的目标导向,将物质规划与社会规划紧密地结合在一起。 + +\subsection{ 20世纪以来西方现代城市规划思想与理论} +\subsubsection{1.西方现代城市规划思想与理论发展的总体分期} +20世纪以来,西方现代城市规划思想、理论发展可以划分为四个时期。 + +(1)1900年代至二战前,这是一些精英分子对现代城市规划思想进行各种探索、实践的时期,为战后功能主义思想垄断地位的确立奠定了基础。 + +(2)二战后至1960年代末,以现代建筑运动为支撑的功能主义规划思想,在战后西方城市重建和快速发展过程中发挥了积极且重要的作用,从而最终完成了现代城市规划思想体系的确立并达到其认知的顶峰。 + +(3)1970年代至1980年代末,西方社会在这个时期经历了巨大的社会转型,也就是进入了通常所说的“后现代社会”,社会价值观体系处于混沌交织的过程中,社会文化论在城市规划思想中占据了主导地位。 + +(4)1990年代后,西方社会基本恢复了平静和秩序,但是随着经济、政治全球化的深入以及通信、互联网等技术的发展,人们不得不深刻地思考一些至关人类未来发展的重大问题,例如全球化的影响、可持续发展、增长与发展、以人为本、治理(Governance)、智慧城市、生态城市等等,城市规划思想的探索面对着一幅崭新的社会图景。 + +\subsubsection{2.二战前西方重要的城市规划思想与理论} +19世纪末至20世纪初是西方城市规划思想与理论繁盛发展的时期,下面主要介绍几个重要的规划思想与理论: + +(1)格迪斯的区域规划思想及学说 + +苏格兰生态学家格迪斯注意到工业革命、城市化对人类社会的影响,他通过对城市进行生态学的研究,强调人与环境的相互关系。在1915年出版的著作《进化中的城市》中,他通过周密分析地域环境的潜力和限度对于城市布局形式与地方经济体系的影响关系,突破了当时常规的城市概念,提出把自然地区作为规划研究的基本框架。他指出,工业的集聚和经济规模的不断扩大已经造成了一些地区的城市发展显著集中,使城市结合成巨大的城市集聚区(Urban Agglomeration)或者形成组合城市(Conurbation)。在这样的条件之下,原来城市规划应当首先是城市地区的规划,即将城市、乡村的规划纳入统一的体系之中,使规划包括若干个城市以及它们周围所影响的整个地区。 + +格迪斯认为城市规划要取得成功,就必须充分运用科学的方法来认识城市。他综合运用哲学,社会学和生物学的观点,揭示了城市在空间和时间发展中所展示的生物学和社会学方面的复杂性。他强调在进行城市规划前要进行系统的调查,取得第一手的资料,通过勘察了解所规划城市的历史、地理、社会、经济、文化、美学等因素,把城市的现状和地方经济、环境发展潜力以及限制条件联系在一起进行研究,在此基础上进行城市规划工作。他的名言是“先诊断后治疗”,由此而形成了影响至今的现代城市规划经典过程,即“调查—分析—规划”。格迪斯被公认为现代区域综合研究和区域规划的创始人,是使城市、区域研究由分散走向综合的第一人。 + +(2)作为微观社区组织的邻里单位理论 + +美国建筑师C.佩里很早就认识到居住地域作为一种场所空间的内在社会文化含义,他借用社会学中的“社区”思想,于1929年提出了“邻里单位”(Neighbourhood Unit)的概念,将其作为构成居住区乃至城市的细胞。“邻里单位”以一个不被城市道路分割的小学服务范围作为邻里单位的尺度,讲求空间宜人景观的营建,强调内聚的居住情感,重视居民对居住社区的整体文化认同和归属感。佩里认为这不仅是一种创新的设计概念,而且是一种社会工程,它将帮助居民对所在的社区和地方产生一种乡土观念。邻里单位模式对后来直至今天世界各国的居住区规划(或社区规划)都产生了重大的影响。 + +(3)分散主义、集中主义的争论与统一 + +针对大城市、特大城市因为过度聚集而产生的城市问题,许多人给出了不同的解决方案,其中最主要的两种思想冲突就是应该采取“分散主义”还是“集中主义”。霍华德的田园城市体现了一种分散主义的思想,而美国建筑师赖特提出的“广亩城市”更是分散主义思想的代表。广亩城市依托小汽车、通信等技术支撑而彻底解体了城市,发展出一种完全分散的、低密度的生活居住形态。这种空间形态虽然满足了中产阶级、高收入人群对田园环境的向往,但是却牺牲了城市的规模经济和集聚活力,更对资源环境造成了巨大的压力和破坏,是一种并不值得提倡的规划思想。 + +与分散主义思想相反,现代建筑与城市规划运动的领军人物柯布西埃则希望通过对大城市结构的重组、内部改造,使这些城市能够重新适应社会发展的需要。1922年柯布西埃发表了“明日城市”的规划方案,从功能合理性角度出发阐述了集中主义城市的解决方案:城市的平面是严格的几何形构图,矩形和对角线的道路交织在一起,核心思想是提高市中心的建设强度,建立大运量、立体化的交通系统,全面改造老城区,提供充足的绿地、空间和阳光。1931年的“光辉城市”规划方案是集中主义城市的进一步深化。柯布西埃认为城市是必须集中的,只有集中的城市才有生命力,由于拥挤而带来的城市问题是完全可以通过技术手段进行改造而得到解决的,所有的城市应当是“垂直的花园城市”,而不是水平向的田园城市。 + +作为现代城市规划原则的倡导者和执行的中坚力量,柯布西埃的上述设想充分体现了他对现代城市规划的一些基本问题的理解,并形成了理性功能主义的城市规划思想。这种思想集中体现在由他主导撰写的《雅典宪章》(1933年)之中,深刻地影响了二战后全世界的城市规划和城市建设,而他本人的实践活动一直到了1950年代初应邀主持印度昌迪加尔规划时才得以充分施展,该项规划当时由于严格遵守《雅典宪章》的原则、布局规整有序而得到普遍的赞誉。1960年代以后,随着城市规划领域对人文、社会因素的重视,柯布西埃的功能理性规划思想受到了越来越多的批判。 + +集中主义、分散主义这两种规划思路,也显示了两种完全不同的规划思想和规划体系:霍华德的规划理念基于社会改革的理想,在其论述的过程中更多地体现出人文关怀和对社会经济的关注;柯布西埃则从建筑师的角度出发,对工程技术的手段更为关心,并希望以物质空间的改造来改造整个社会。集中主义、分散主义这两种规划思路的冲突,直到沙里宁的“有机疏散理论”Organic Decentration)出现才得以统一。 + +1943年美国建筑师伊利尔·沙里宁在著名的《城市:它的发展、衰败和未来》一书中详尽地阐述了有机城市、有机疏散的思想。沙里宁认为,城市与自然界的所有生物一样,都是有机的集合体,因此城市规划建设应努力实现有机的秩序。为了缓解城市机能过于集中所产生的弊病,使城市逐步恢复有机的秩序,沙里宁提出了有机疏散理论,认为城市作为一个有机体,和生命有机体的内部秩序一致,不能任由其无限集聚,而要把城市的人口和工作岗位有机分散到合理的地方。他将城市活动划分为日常性活动和偶然性活动,通过“对日常活动进行功能性的集中”和“对这些集中点进行有机地分散”,使原先密集的城市得以实现有机疏散。他指出,前一种方法能给城市的各个部分带来适于生活和安静的居住条件,而后一种方法则可以给整个城市带来功能秩序和工作效率。换个角度讲,有机疏散就是把传统大城市的拥堵区域分解成若干个集中单元,并把这些单元组织成为“在活动上相互关联的有功能的集中点”,再将它们彼此之间用保护性的绿化地带隔离开。有机疏散思想对二战后欧美各国改善大城市问题,尤其是通过卫星城建设来疏散特大城市的功能与空间产生了重要影响。 + +\subsubsection{3.二战后至1960年代末西方主要的城市规划思想与理论} +(1)卫星城理论与新城运动 + +1920年代,恩温(R.Unwin)进一步推进霍华德的思想并提出了“卫星城”的概念(见图8)。卫星城既是一个经济上、社会上、文化上具有现代城市性质的独立城市单位,同时又是从属于某个大城市的派生产物。卫星城的概念强化了其与中心城市(又称母城)的依赖关系,在功能上强调对中心城的疏解,因此往往被视作中心城市某一功能疏解的接受地,由此出现了工业卫星城、科技卫星城甚至卧城等不同功能类型,并成为中心城市功能组的一部分。1944年阿伯克隆比(P,Abererombie)完成的大伦敦规划,通过在伦敦周围率先建设卫星城以疏解伦敦的人口和职能,对现代城市规划产生了深远的影响。从二战后的战后恢复重建,到西方经济和城市快速发展时期,大多数国家都有不同规模的卫星城建设,其中尤以英国最为典型(一般称之为“新城运动”)。如今,卫星城(新城)已经成为分散大城市过于集聚的功能和人口,在更大的区域范围内优化城市空间结构、解决环境问题、实现功能协调的重要规划手段。 + +(2)环境行为研究与城市设计 + +1960年代以后,随着城市大规模物质空间建设的结束,人们对空间内在社会、文化、精神方面的要求不断提高,生态环境保护、历史文化保护城市更新等成为西方城市规划的重要内容。城市规划中越来越多地引入环境科学、行为科学的内容,这与现代科学尤其是人文科学的发展有着重要的关系,反映了人们对城市发展、城市规划的理解愈趋综合化。城市环境不再仅仅被视为一个视觉艺术空间的问题,而且更被理解为一种综合的社会交往场所。1960年代在美国出现了现代“城市设计”(Urban Design)的概念,城市设计将城市视作一个包括三维空间、时间变化在内的四维空间,强调人与空间的内在互动,强调景观设计对人们活动、心理感知的重要意义。《大不列颠百科全书》中对城市设计的定义是:“城市设计是对城市环境形态所做的各种合理处理和艺术安排。”但正如当时城市设计的提出者所言:“城市设计的出现并不是为了创造一门新的学科,而是对以前忽视空间人性关怀的一种弥补”。城市设计作为一种观念,应该渗透到城市规划建设的全过程中去。 + +\subsubsection{4.1970年代至1980年代末西方主要的城市规划思想与理论} +1960年代末以后,西方资本主义社会发生了深刻的变化,这种深刻的转变与经济发展的阶段、产业结构的调整、社会结构的变动、人们需求的转变、国际形势的变化等等都密切相关,集中体现为社会生活的各个领域变化节奏加快,冲突加剧、不确定性增强。这一时期,西方资本主义社会矛盾异常复杂,引发了西方思想家们对人、对社会、对未来的深切关注和思考,并形成和发展了丰富多元的现代(后现代)社会思潮。 + +总体上说,1970年代至1980年代是一个西方社会生活各个领域思潮都处于混沌交锋的大转型时期。在对现代主义的反思和批判过程中,城市规划由单纯的物质空间塑造逐步转向对城市社会文化的关注;由城市景观的美学考虑转向对具有社会学意义的城市公共空间及城市生活的创造;由巴洛克式的宏伟构图转向对普遍环境感知的心理研究。总之,开始从社会、文化、环境、生态等各种视角,对城市规划进行新的解析和研究。新马克思主义热潮在城市研究、城市规划领域再度兴起,强调运用政治经济观来深入分析资本主义社会的结构性矛盾,主要表现为:对规划中社会公正问题的关注;对社会多元性的重视;强调人性化的城市设计;注重对城市空间现象背后的制度性思考。 + +按照新马克思主义的视角来理解,城市规划的本质更接近于政治,而不是技术或科学,城市规划被视为以实现特定价值观为导引的政治活动。由此,西方的城市规划学科,研究与实践也开始了从工程技术向公共政策的重大转向。 + +\subsubsection{5.《雅典宪章》与《马丘比丘宪章》} +现代城市规划发展基本经历了两个阶段:第一阶段从霍华德的“田园城市”理论开始,经过1920年代、1930年代现代建筑运动的推进,以《雅典宪章》(1933年)的发布为代表,其实践活动主要集中于战后西方城市重建和快速发展阶段;第二阶段自1960年代末以来,以《马丘比丘宪章》(1977年)的发布为代表,逐渐建立了新的规划思想与方法。 + +《雅典宪章》依据科学理性主义的思想方法,对城市中普遍存在的问题进行了全面分析,提出了城市规划应当处理好居住、工作、游憩和交通的功能关系,并把该宪章称为现代城市规划的大纲。1970年代后期,面对世界城市化趋势和城市规划过程中所出现的新内容、新问题,发布了《马丘比丘宪章》。该宪章申明,《雅典宪章》仍然是这个时代的一项基本文件,它提出的一些原理今天仍然有效;但是随着时代的进步,城市发展面临着新的环境,而且人类对城市规划也提出了新的要求,《雅典宪章》的一些指导思想已不能适应当前形势的发展变化,因此需要进行修正。而《马丘比丘宪章》所提出的内容,正是“理性派所没有包括的,单凭逻辑所不能分类的种种一切”,《雅典宪章》和《马丘比丘宪章》都是对当时的规划思想进行总结,并对未来发展指出方向的现代城市规划发展历史纲领性文件。通过这两部文件内容的对比,我们可以总览现代城市规划发展的基本趋势。 + +(1)由物质空间规划走向综合空间规划 + +《雅典宪章》的思想方法是奠基于物质空间决定论基础之上的。这一思想认为,在城市规划中通过对物质空间变量的控制,就可以形成良好的环境,而这样的环境就能自动地解决城市中的社会、经济、政治问题,促进城市的发展和进步,这是《雅典宪章》所提出来的功能分区及其机械联系的思想基础。虽然认识到影响城市发展的因素是多方面的,但《雅典宪章》仍将城市规划视为一种“基于长、宽、高三维空间……的科学”。《马丘比丘宪章》则摒弃了《雅典宪章》机械主义和物质空间决定论的思想基石,宣扬社会文化论的基本思想。《马丘比丘宪章》认为,物质空间只是影响城市生活的一项变量,而且这一变量并不能起决定性的作用,起决定性作用的应该是城市中各人类群体的文化、社会交往模式和政治结构。城市规划“必须对人类的各种需求作出解释和反应”,并“应该按照可能的经济条件和文化意义,提供与人民要求相适应的城市服务设施和城市形态”。 + +(2)由功能分割走向系统综合 + +《雅典宪章》最为突出的内容就是提出了城市的功能分区,将城市中的各种活动划分为居住、工作、游憩和交通四大类,各自都有其最适宜发展的条件,以便给生活、工作和文化分类与秩序化。功能分区在当时有着重要的现实意义和历史意义,它对于当时大多数城市无计划、无秩序发展过程中所出现的问题,确实可以起到缓解和改善的作用。《马丘比丘宪章》则指出,《雅典宪章》所崇尚的功能分区“没有考虑城市居民人与人之间的关系,结果使城市患了贫血症,在那些城市里建筑物成了孤立的单元,否认了人类的活动要求流动的、连续的空间这一事实”。过度强调纯粹功能分区,导致人情冷漠、空间单调、缺乏生气等等社会问题。因此,《马丘比丘宪章》明确提出,“在今天,不应当把城市当作一系列的组成部分拼在一起考虑,而必须努力去创造一个综合的、多功能的环境”。 + +(3)由描绘终极状态步入动态循环过程 + +《雅典宪章》认为,城市规划的基本任务就是制定规划方案,而这些规划方案的内容都是关于各功能分区的“平衡状态”和建立“最合适的关系”,鼓励对城市发展终极状态下各类用地关系进行描述,并“必须制定必要的法律以保证其实现”。《马丘比丘宪章》则认为城市是一个动态系统,要求“城市规划师和政策制定人必须把城市看作在连续发展与变化过程中的一个结构体系”。1960年代以后,系统思想和系统方法在城市规划中得到了广泛的运用,直接改变了过去将城市规划视作对终极状态进行描述的观点,更强调城市规划的过程性和动态性。《马丘比丘宪章》在对这一系列理论进行总结的基础上做了进一步的发展,提出“区域和城市规划是个动态过程,不仅要包括规划的制定,而且要包括规划的实施。这一过程应当能适应城市这个有机体的物质和文化的不断变化”。城市规划就是一个不断模拟、实践、反馈的循环过程,只有通过这样不间断的连续过程才能更有效地与城市发展相协同。 + +(4)由表达专家意志转向鼓励公众参与 + +受传统精英主义思维的影响,《雅典宪章》对规划师、专家等社会精英的主导作用尤为重视,强调“规划师必须以专家所做得准确研究为依据”。在此思想的指导下,城市规划就成为一种少数专业人员表达他们意志,并以此来规范城市社会各类群体和个人行为的手段。1960年代中期以后,随着西方社会的转型,公众参与成为城市规划的一个重要内容。大卫多夫在1960年代初提出的“规划的选择理论”和“倡导性规划”概念,成为城市规划公众参与的理论基础:规划不应当以一种价值观来压制其他多种价值观,而应当为多种价值观的体现提供可能,规划师就是要表达这些不同的价值判断并为不同的利益团体提供技术帮助。在规划的过程中要让广大的市民参与规划的编制和讨论,并让公众能真正参与到规划的决策过程之中。《马丘比丘宪章》不仅承认公众参与对城市规划的极端重要性,而且更进一步提出“城市规划必须建立在各专业设计人员、城市居民以及公众和政治领导人之间的系统的、不断地互相协作配合的基础上”,并“鼓励建筑使用者创造性地参与设计和施工”,指出“人民的建筑是没有建筑师的建筑”。如今,公众参与被包括中国在内的世界许多国家的城市规划立法和制度所保障。 + +\subsubsection{6. 1990年代以来的多元规划观} +进入1990年代,国际环境的转变、技术与生产方式的变化、生活方式的转型等等,都使得城市问题变得更加复杂、变化莫测,已经没有一种理论、方法能够被用来整体地认识城市、改造城市,多元思潮蓬勃兴起,城市规划的理论与实践探索已经进入了一个更为广阔的背景之中。全球化、治理、生态、可持续、文化、智慧等等,成为主导新时期城市规划思想的关键词。泰勒(Taylor)曾经将这段时期西方城市规划领域所关注的重要议题列为五个方面:城市经济的衰退和复苏;超出传统阶级视野并在更广范围内讨论社会的公平;应对全球生态危机和响应可持续发展要求;回归对城市环境美学质量以及文化发展的需要;地方的民主控制和公众参与要求。其中既有新环境催生的对新规划思想的探索,也有对传统规划思想、规划价值观的螺旋性上升认识。世纪之交,美国的《规划专员杂志》(Planning Commissioners Journal)(1999年)提出了21世纪现代城市规划发展的九大趋势,主要包括以下方面: + +(1)开发者与环境保护主义者的合作。城市规划由以前的开发型规划走向环境整治型的规划,如划定各种鼓励开发区、引导开发区、限制开发区、禁止开发区等等,强调开发与保护相结合。 + +(2)对公众参与的日益重视。随着城市社团力量的壮大,非政府力量对城市规划的干预作用增强,城市治理(Urban Governance)等思潮日益壮大。 + +(3)网络空间对土地利用的影响。随着信息网络技术的发展,城市空间正在发生着新的、根本性的演变,这对传统的城市空间、城市规划提出了巨大的、全新的挑战。 + +(4)更加紧凑的开发与混合使用的空间。随着资源环境的趋紧,紧凑发展成为越来越主动的需求。随着城市复兴、创新创意活动的发展,传统单一的商业中心转变为综合中心,传统单一的用地与空间组织模式日益被混合功能用地与空间所取代。 + +(5)开放空间网络与绿色通道。网络化的空间、开放空间、绿色通道可以给城市发展、布局带来更大的弹性。郊区化、逆城市化的过程及信息、交通技术的发展,也使得开放空间网络成为可能,并成为一种主动的需求。 + +(6)交通和土地利用整体规划的拓展。交通是构成城市物质环境结构的框架,现代城市受交通及其方式的发展而变化,必须在规划中将交通与城市土地利用、空间规划进行整体的协同考虑。 + +(7)贫困人群和老龄人的需求不断增长。随着社会极化的加剧以及老龄化社会的到来,城市规划必须考虑这种社会环境的变化,并满足不同人群尤其是弱势群体产生的种种要求。 + +(8)城市中心区的复苏。1980年代以后,一些国家实施了有力的“再城市化”策略,通过对原有市中心地区的功能与环境改造,努力复苏、创造一个充满活力的城市中心。 + +(9)区域合作不断受到重视。在经济全球化的今天,城市要增强竞争力,就必须通过与其他城市的协作来实行双赢、多赢,区域合作更加受到重视。 + +\subsection{ 21世纪的城市规划思想与理论变革} +\subsubsection{1.由单向的封闭型思想转向复合开放型思想} +封闭型思想主要包含了两层涵义:其一,思维的单向性,它否定了思维过程中后一阶段成果对前一阶段成果的作用;其二,封闭型,就是指思想过程中单系统的思维方式,它否定了该系统外的环境对系统的作用。 + +城市的开发、改造成效很大程度上取决于管理部门的组织,同时管理工作会对规划设计工作起到反馈作用,这才能使规划设计工作的成果得以实现。思维的单向性使人们忽视了管理工作对规划工作本身的作用,造成规划成果与实际需求脱离。与此同时,城市规划受到社会、经济等诸多因素的共同作用,因此需要必要的弹性,然而封闭型思想使得部分规划忽视了本系统之外的因素,造成了规划编制的不合理。城市规划需要更加复合开放的思想,需要广泛地听取社会学、心理学、经济学、管理学等方面的建议。 + +\subsubsection{2.由最终理想状态的静态思想转向过程导控的动态思想} +所谓最终理想状态的静态思想就是忽视了发展过程中的协调性,缺乏运行概念,使规划成为了“乌托邦”。这种最终理想状态的静态思想干扰着规划的发展,使规划脱离了城市建设发展的实际。 + +城市规划的目的就是要使城市在发展的各个阶段上其整个系统运行保持良性运转,不应该只是强调最终的理想状态。在规划执行的若干年内,城市各系统之间的关系是否协调、合理运行,城市经济效益、社会效益和环境效益是否提高,这是规划中需要重视的问题。动态过程的思想方法要求把城市规划工作的对象确定为动态过程,规划成果是一种动态的过程的控制和引导方法,城市规划管理的控制手段也是一种动态过程。 + +\subsubsection{3.由刚性规划的思想转向弹性规划的思想} +刚性规划思想缺乏多种选择性,欲求唯一的最佳方案。然而,由于刚性的规划成果很难适应城市这个综合复杂的巨系统。造成刚性规划思想的原因是机械的社会观,以机械性代替社会的综合性,同时是把规划与设计混为一谈,以设计工作的思想方法代替规划工作的思想方法。 + +弹性规划思想首先需要明确城市的发展是一个社会发展过程。在社会发展进程中,构成社会的各系统之间是互相作用的,其中由社会经济水平决定的社会意识形态具有最重要的决定性意义。规划是否合理根本上取决于整个社会意识形态和社会经济水平,所以说城市规划只是以政府意愿形式出现的反映社会经济水平的,维护城市社会发展过程平衡中的诸多力量之一。城市社会意识和社会经济水平构成的多样性、发展时间上的摆动决定了为其服务的城市规划必须是提供多种的可能性和选择性即弹性的规划思想方法。 + +\subsubsection{4.由指令性的思想转向引导性的思想} +指令性的思想方法认为城市系统的发展是由某一中心枢纽控制,而城市规划编制及管理就是这个枢纽,它控制了整个城市诸多系统的发展。这种思想方法使城市规划工作从城市诸系统中孤立出来。规划并不是城市发展中起指令性控制作用的中心枢纽。规划编制阶段应该集思广益,广泛综合各方面的分析成果。在指令性思想方法指导下的总体规划,容易随意地变动城市用地现状,不顾客观情况,造成规划成果肤浅、脱离实际。 + +引导性的思想方法强调各系统发挥自身的选择性,强调规划在城市发展进程的引导性控制作用,城市规划是向各系统提供正确的发展选择的引导者。例如城市发展方向的选择就要受到城市的经济效益的检验,经济效益和社会效益也起着重大作用。因此,引导性的思想方法首先要了解城市发展的需求以及开发者的价值观,其次根据布局结构关系拟定出城市发展的引导性措施,充分利用经济规律、社会规律等将城市的发展引入良性轨道。 + +\section{我国土地利用规划理论与实践} + +我国古代已出现土地利用规划的萌芽,《禹贡》是中国古代文献中最古老和最有系统性的地理观念的著作,也是中国历史上最早的“土地利用规划”。《禹贡》以自然地理实体为标志,将全国划分为九州,并对疆域、山脉、河流、植被、土壤、物产、贡赋、少数民族、交通等自然和人文地理现象作了简要的描述。井田制是中国古代社会的土地国有制度,出现于商朝,井田规划是我国早期土地利用规划的雏形,它反映了当时田赋管理对组织土地利用的需要。《周礼》创立了“土会”“土宜”“土均”“土圭”的工作方法,进行土地规划、土壤研究和管理等方面的工作。 + +新中国成立后,随着与苏联全面合作,以“土地整理”为代表的现代土地利用规划引入我国,主要理论是承袭计划经济模式,1950—1970年代末,以农业土地利用为主,围绕国营农场和人民公社的发展提供土地条件和政策保障,1950年代后期改称为“土地规划”。 + +1950年代—1970年代末,我国的土地利用规划理论基本沿袭苏联的计划模式;1980年—1986年,国家土地管理局成立,全面开展了土地资源调查、农业区划、土地利用总体规划、农村土地利用规划等工作,土地利用规划理论与实践进入新的发展时期;1987年,《中华人民共和国土地管理法》颁布实施,正式确立了土地利用规划的法律地位,逐步建立起国家、省、地(市)、县、乡(镇)五级土地利用规划体系,全面落实“十分珍惜和合理利用每寸土地,切实保护耕地”的基本国策。 + +改革开放以后全国进行了三轮国家级土地利用规划,土地利用规划理念与实践不断丰富完善。 + +\subsection{第一轮土地利用总体规划(1986-1996年)} +规划编制正处于市场经济发展初期,全国城市建设处于全面发展的高峰时期,为服务经济发展,本轮土地利用规划围绕保障各类建设,初步确定了土地利用规划的体系、内容、方法与编制审批程序。 + +\subsection{第二轮土地利用总体规划(1996-2006年)} +第一轮土地规划编制完成后,我国城镇化发展迅速,经济全面开花的同时,耕地面积减少超过2000万亩,人口众多,耕地质量不高,后备资源紧缺逐步显现,1997年,《进一步加强土地管理切实保护耕地的通知》提出了实施基本农田保护和耕地总量平衡制度,以此为指导,本轮土地利用规划,以耕地总量动态平衡为目标,对耕地现状、建设占用总量逐级控制,确定了“指标+分区”的土地利用规划模式,土地利用规划编制模式与审批程序进一步完善。 + +\subsection{第三轮土地利用总体规划(2006—2020年)} +2006年,基于保障耕地总量,加强土地管理的目标,以当时土地普查的情况,提出了“18亿亩”保护底线的概念,这是国家统计局与原农业部按当时全国人口、粮食单产与复种指数等综合因素计算提出来的目标,确保2010—2030年粮食自给率达到95\%。 + +2006年启动的本轮土地利用规划更加突出了“节约和集约用地”的核心理念,突出以下几点: + +(1)土地利用规划更加强调公共政策属性。强调编制与实践并重,重视保障措施与政策设计,开展了土地利用战略研究,提出了土地利用的约束性和预期性两类指标。 + +(2)土地利用规划更加强调空间管制与指标并重,针对性地提出了各类用地空间、基本农田、建设用地布局与管制分区的要求,更增加了规划弹性思想。 + +(3)土地利用更加强调综合性,以保护耕地和土地节约与集约为核心,从控制各类用地出发,兼顾经济发展、生态环境保护与土地利用之间的关系,同时,引入了环境影响评价的内容。 + +2018年起,随着建立国家统一的国土空间规划体系,土地规划利用与城乡规划和主体功能区等规划一道纳入国土空间规划中,我国土地规划工作理念内容和方法取得了良好的连续与发展。 + +\section{我国主体功能区规划理论与实践} +我国主体功能区划的发展历史进程较短,在“十一五”期间提出了主体功能区划的概念,即指在不同区域的资源环境承载能力、现有的开发密度和发展潜力等要素进行综合分析的基础上,以自然环境要素、社会经济发展水平、生态系统特征以及人类活动形式的空间分异为依据,划分出具有某种特定主体功能的地域空间单元。 + +主体功能区划的内容基于是否适宜或如何进行大规模高强度工业化城镇化开发为基准,大致分为以下四类:优化开发区域、重点开发区域、限制开发区域和禁止开发区域。按照主体功能定位调整完善区域政策和绩效评价,规范空间开发秩序,以形成合理的空间开发结构。主体功能区划的意义是促进区域协调发展、实现人口与经济合理分布的有效途径,是实现可持续发展、提高资源利用率的迫切需求,是坚持以人为本、实现公共服务均衡的有利保障。主体功能区划弥补了国土规划对于土地利用规划方面的不足,对于新型城镇规划和国土空间规划起到战略综合的作用。 + +\subsection{主体功能区的发展历程} +我国主体功能区总体上进行了一轮的发展过程,从2005年提出了主体功能区的思想到2011年国务院《全国主体功能区规划》的发布,大致经历了六年的时间。《全国主体功能区规划》是我国国土空间开发的战略性、基础性和约束性规划,对于后来的国土空间开发具有重大战略意义。 + +主体功能区划是我国首创的一种国土空间开发制度。作为一种重要的区域统筹协调发展的思想,主体功能区划基于“效率”与“公平”的规划目标,建立了空间类型和差异政策划分空间的方法,根据一个空间单元的自然资源禀赋、生态环境状况、经济社会发展水平及潜力、现有开发建设强度及情况等,并结合国家和区域未来的发展战略,综合确定该空间单元的主体功能定位,以及确定其开发利用方式,因地制宜,分级分类划分为不同的主体功能区,其主要的发展历程如下所示(见表3.2)。 + +表3. 2我国主体功能区发展历程表 + +\subsection{主体功能区的核心思想} +功能区原属于建筑学的概念,是指根据房屋内部空间的使用功能和各共有建筑部位的服务范围而划分的区域。主体功能区是功能区概念的延伸。其作用主要是促进各地区分工协作,形成合理的空间经济布局和结构,有效解决人与自然和谐发展问题。主体功能区的目的是统筹谋划未来中国人口分布、国土利用、城市化和经济布局,根据不同区域的资源环境承载力,现有开发密度和发展潜力,按区域协调、环境友好、资源节约等原则划定的具有某种主体功能的规划区域。《全国主体功能区规划》将中国国土空间分为4类(见表3.3)。 + +表3. 3全国主体功能区划基础划分表 + +\subsection{主体功能区的理论与技术方法} +为实现区域协调发展的目标,我国在主体功能区规划中将开发与保护的两个基本指标融入“主体功能”这一概念当中。将开发程度高的地区作为开发主导型区域,将保护程度高的作为保护主导型区域。在主体功能区规划传导市县发展规划,推动多规合一的过程中,核心内容就是如何合理准确的划分出城镇、农业、生态三类空间。具体分为以下五个步骤(见表3.4)。 + +表3. 4主体功能区划定步骤 + +\subsection{主体功能区的相关实践} +在国家颁布《全国主体功能区规划》之后,各省市也相应进行了各地的规划实践。作为国家层面的优化开发区域之一,广东省是全国较早开展主体功能区规划研究的省份,在区划方法、规划内容体系以及规划的贯彻与落实等方面进行了诸多探索与尝试。2009年底,广东省的《广东省主体功能区规划(2010-2020)》出台,既符合国家要求又体现广东的科学发展,既有战略高度又具备可操作性,对于其他省区的规划发展具有一定的示范意义。《广东省主体功能区规划(2010-2020)》在区划方法上总体遵循国家颁布的《省级主体功能区划分技术规程》,采用全国统一的10项指标进行综合评价,特别强调战略选择对于区划的决定作用,强化了国土开发战略格局的研究。规划内容体系上,强调规划的战略高度与可操作性,一方面,专门增加了国土开发战略格局的章节,对全省的国土开发总体格局以及城镇化、农业开发、综合交通、生态安全等进行了宏观的战略部署,另一方面,在主体功能区下进一步按流域和地域概念划分出若干片区,制定了各片区以及各地级市的开发指引,大大增强了规划的可操作性。为促进规划在市、县、区层面的贯彻与落实,省委省政府将清远市作为全省主体功能区规划试点,组织编制了清远市主体功能区规划实施纲要,以镇乡、街道为基本单元,进一步细化全市空间布局,并探索全省分类调控的政策经验;清远市的阳山县也围绕其限制开发区域(广东省称生态发展区域)的功能定位,开展了生态发展规划实践,探索了限制开发区生态发展的路径与政策保障,由此在全省形成了“ 省—地级市—县(区)”的主体功能区规划层级体系。 + +贵州省是我国西南地区较早进行主体功能区规划编制的省份,2011年《贵州省国民经济和社会发展第十二个五年规划纲要》明确要求按主体功能区划分和定位来科学规范空间开发。为转变贵州经济的发展方式,促进经济协调发展,贵州省于2013年7月发布了贵州省主体功能区规划方案。贵州省同样结合民族地域资源特点和空间差异,将主体功能区划分为重点开发、限制开发、禁止开发三类,其发展理念主要遵循科学开发理念、构建城镇化战略布局、促进农业战略格局形成、注重生态安全战略格局形成的思路展开。但是贵州省在主体功能区发展的过程中也出现了一些问题,如主体功能区规划与传统规划的重叠与冲突、转移支付不足及生态补偿机制缺失、不同主体功能区经济发展失衡冲突。为有效应对这些问题,贵州省完善了主体功能区划的制定标准,落实财政转移支付,建立生态补偿价格机制及积极探索协调主体功能区域之间的冲突关系。 + +2012年4月,黑龙江省印发首个省级主体功能区规划,标志着主体功能区规划进入了地方推进阶段,各省(区、市)于此后两年内陆续完成本省(市、区)主体功能区规划编制工作。《黑龙江省主体功能区规划》推动形成全省主体功能区,是贯彻落实科学发展观、加快老工业基地振兴的重大举措,是实现地区间公共服务均等化、构建和谐黑龙江的重要途径。规划根据省域内不同区域的资源环境承载能力、现有开发强 度和发展潜力,以县级行政区为基本单元,将全省国土空间按开发 方式划分为重点开发区域、限制开发区域和禁止开发区域;按开发 内容划分为城市化地区、农产品主产区和重点生态功能区;按层级 划分为国家层面和省级层面。确定各区域主体功能定位,明确开发 方向,控制开发强度,规范开发秩序,完善开发政策,推进形成人 口、经济、资源环境相协调的空间开发格局。黑龙江省主体功能区规划是全省国土空间开发的战略性、基础性和约束性规划,是推进形成主体功能区的基本依据,是科学开发全省国土空间的行 动纲领和远景蓝图。 + +\section{我国生态规划理论与实践} +随着19世纪工业革命的不断发展,周边乡村的居民不断涌入城市,导致城市规模持续扩大,人们过度重视生产效能的发展却忽视了对生态环境的保护以及二战之后过度发展经济开发资源更是忽略了生态环境的重要性。20世纪60年代后人们开始重视生态规划的建设及环境保护的问题,生态学引入大众的视野并受到广泛关注,至此之后生态思想在各个城市规划中均有体现。 + +\subsection{国内外城市生态理论研究与实践新动向} +国内外关于城市生态方面的理论和实践研究虽开始较晚,但是发展较快且研究内容也较为丰富。1981年苏联生态学家亚尼茨基提出了生态城市的理想城市模式,按照生态学原理将生态城市的设计和建造分为时间—空间、社会—功能、文化—历史三种知识层次,以及基础研究、应用研究、设计计划、建设实施和有机组织结构的形成5种行动阶段。他认为生态城市应是自组织的建设过程,应由原来的被动变为主动、自发地拥有生态环境意识并实施建造。《绿色城市》于1990年由高尔敦(David Gordon)出版,该书中收录了许多学者关于绿色城市的规划思想,目的在于想要探寻一条有效的能在城市实施的生态建设路径。 + +美国生态学家理查德·雷吉斯特是国际生态城市运动的创始人,1975年创建了“城市生态学研究会”,领导该组织在美国西海岸的伯克利开展了一系列的生态城市建设活动。他认为生态城市应该是三维的、一体化的复合模式,而不是平面的、随意的,同生态系统一样,城市应该是紧凑的,是为人类而设计的,而不是为汽车设计的,而且在建设生态城市中,应该大幅度减少对自然的“边缘破坏”,从而防止城市蔓延,使城市回归自然。 + +我国的生态城市与生态城市规划的研究起步较晚,涉及的学科领域有生态学科、城市规划学科、环境科学及其他领域。目前来看,我国生态城市规划的优点在于在城市规划中整合了中国文化相关的要素,努力打造中国特色的生态城市规划。早在 1984 年,马世骏与王如松先生针对当时生态环境问题日趋严重,人与自然的关系失调等问题,在国际上首次提出了社会—经济—自然复合生态系统理论,并指出城市与区域是以人的行为为主导、自然环境为依托、资源流动为命脉、社会文化为经络的社会—经济—自然复合生态系统。 + +20世纪90年代我国开展了有关“山水城市”的讨论。山水城市的内涵,既包含着丰富的自然生态内容、人文社会生态内容,视山水城市为“超大型园林”等内容,又包含着构想者把建筑科学列为与自然科学、社会科学并列的学科内容。张宇星于“城镇生态空间发展与规划理论”一文中阐述了城镇生态空间发展的一般运行机制,提出应从空间形态、状态、动态和进态几方面入手建立“大规划”的研究体系;胡俊认为生态城市强调通过扩大自然生态容量,调整经济生态结构,控制社会生态规模和提高系统自组织性等一系列规划手法来促进城市经济、社会、环境的协调发展。梁鹤年认为城市规划可以按照城市紧凑度的大小来进行相应规划,若城市形态紧凑,则应适当发展自然生态要素,按照自然生态的完整性进行,如果城市形态疏松,建设用地与绿网绿带交叉纵横,城市化可以按生态或社会各自的需要来进行规划。 + +\subsection{中国生态城市的理论与实践} +\subsubsection{1.我国生态文明建设的发展历程} +在新的历史条件下,我国生态文明建设的理论和实践不断发展与完善。党的十六大提出确立科学发展观战略与生态文明建设,党的十八大以来不仅提出建设美丽中国的目标,这将生态文明建设提高到了一个前所未有的高度;而且党中央领导集体高度关注生态文明建设,明确指出建立系统的生态文明制度,划定生态保护红线,建立资源有偿使用和生态补偿制度等,同时国家以及相关部门出台了相应的法规政策支持生态文明建设,具体的发展历程(见表3.5)。 + +表3. 5我国生态文明建设部分政策 + +\subsubsection{2.生态文明建设的发展内涵} +生态文明是人类文明发展的一个新的阶段,即工业文明之后的文明形态;生态文明是人类遵循人、自然、社会和谐发展这一客观规律而取得的物质与精神成果的总和;生态文明是以人与自然、人与人、人与社会和谐共生、良性循环、全面发展、持续繁荣为基本宗旨的社会形态。面对资源约束趋紧、环境污染严重、生态系统退化的严峻形势,必须树立尊重自然、顺应自然、保护自然的生态文明理念,走可持续发展道路。 + +生态文明建设其实就是把可持续发展提升到绿色发展高度,为后人“乘凉”而“种树”,就是不给后人留下遗憾而是留下更多的生态资产。生态文明建设是中国特色社会主义事业的重要内容,关系人民福祉,关乎民族未来,事关“两个一百年”奋斗目标和中华民族伟大复兴中国梦的实现。党中央、国务院高度重视生态文明建设,先后出台了一系列重大决策部署,推动生态文明建设取得了重大进展和积极成效。 + +\subsubsection{3.中国生态城市建设的理论与方法} +我国的生态城市建设过程中逐步形成了属于自己的理论和技术体系,我国现代城市生态规划受启于西方,一直在引介西方先进理念和技术,在这一过程中,城市规划学、景观生态学、地理学、社会学、经济学、管理学等学科领域的知识与方法不断融入,成为现代城市生态建设的理论武器和实践工具。我国近年来已逐渐开始摸索自己的城市生态建设道路。“低碳生态城市”和“生态文明建设”既是本土化生态规划路径的重要内容,也体现了中国城市生态规划与国家发展战略的紧密关联性——这既是我国城市生态规划的特色,也是其生命力所在。 + +21世纪初,开始有学者注意到城市规划与生态规划融合的必要性,提出了城市规划生态学化的涵义,并对城市规划与城市生态规划的关系进行了探讨。一些学者开始在城市规划与生态规划融合的方向上作出努力。传统城市规划的价值标准和功能设置在改变,过程与方法也逐渐纳入生态容量和生态足迹等分析,城市生态规划开始向具有政策性、法规性属性的成果转变。 + +\subsubsection{4.中国生态城市的发展实践} +在实践层面上,我国的城市生态规划实践脱胎于城市绿地系统规划。1980年代至今,“城市绿地系统”是唯一一项基于生态理念和目标的法定规划,对于合理配置城市生态空间、改善城市生态环境起到了重要的作用。 + +进入21世纪后,出现了更多的城市生态规划类型,如城镇群、生态控制线、生态带、生态网络、生态功能区、非建设用地、新城及新区、街区、社区、大学城、商务区、工业园区、空港城等生态规划,或针对某一种景观类型,如城市森林、水域、湿地、流域、绿化隔离带等所做的生态规划。这些新的规划类型可能在当时尚不成熟也不成系统,但它们从不同角度对城市生态规划体系进行了探索,对我国城市生态规划的发展具有深刻的影响。 + +近期生态规划研究和实践开始将生态理念与控规运行体系相结合,从指标体系的角度对生态理念进行量化和细化;也有研究和实践分别从生态社区、绿色基础设施、绿色建筑等不同层面出发,从更为具体的微观视角探讨生态规划的实现方式。城市生态规划的全域视角为城市生态环境的改善起到了积极的作用。 + +我国较早的城市生态规划实践强调规划管理的刚性控制,即“寸土不让”地守住“红线”,管理手段具有强制性色彩,有时会造成极为激烈的矛盾冲突。例如:深圳基本生态控制线规划的实施初期实行“铁腕手段”,两年间采取了2000余次清拆行动,对于查违队伍也进行严格整治,监管不力者予以通报批评或辞退撤换,在行政责任追求方面一查到底。但结果是违法建筑屡禁不止,甚至引起了部分基层组织和个人的不满,造成对基本生态控制线的排斥和对抗。到了2010年代,屡禁不止的违章建筑和层出不穷的管理问题迫使研究者和管理者对“一刀切”的刚性管理模式进行反思,积极探索保护与经济发展共赢之路,将社区经济效益、基层民众诉求和生态补偿机制等弹性思维与弹性管制纳入考虑,尊重社区发展权,建设自下而上的反馈渠道,制定社区发展计划,重点解决民生问题。从刚性控制到弹性管制,表征了我国对城市生态规划内涵的认识经历了一个全面蜕变优化的过程。 + +江西省宜春市是我国第一个生态城市的试点,采用了复合的生态建设规划,它以复合生态系统学说、智力圈学说、环境科学学说为理论,以生态工程为方法,以系统工程为手段,结合经济建设、社会发展、生态保护等方面,构建一个调控自如的市政范围的复合。 + +\section{多规合一与国土空间规划} +习近平总书记提出:“一个城市首先看规划,规划科学是最大的效益、规划失误是最大的浪费,规划折腾是最大的忌讳。”规划是龙头,是履行政府行政职能的重要手段,是政府科学决策、可持续发展的重要保障。但长期以来由于规划政出多门,规划矛盾冲突、各类规划中存在体系混乱、层次不清,同类规划上行下效,部门规划相互矛盾,专项规划各行其是,致使规划出现编制难、实施难、考核难的多重困境。 + +我国发展已进入新时代,踏上新征程。传统规划方式方法、体系路径不能解决的实际问题,需要系统进行解决。我国在体制机制、体系规范、评价方法等方面进行了“多规合一”的尝试。 + +\subsection{“多规合一”的历程} +2003年,国家发展和改革委员会在苏州市、宜宾市、宁波市等6个城市开启规划体制改革试点工作,将国民经济和社会发展规划、城市总体规划、土地利用规划三个规划落实到一个共同的空间规划平台上。之后上海市、广州市、武汉市等城市相继开展“两规合一”、“三规合一”的探索,主要探索城乡规划、土地利用规划的融合协调,与此同时部分城市进行了规划国土相关部门的合并。 + +2013年11月,空间规划体系改革纳入十八届三中全会,出台了《关于全面深化改革若干重大问题的决定》。2013年12月,习近平总书记首次在中央城镇化工作会议上提出,要积极推进市、县规划体制改革,探索能够实现“多规合一”的方式方法,一个市县一本规划、一张蓝图,并以这个为基础,把一张蓝图干到底。 + +2014年8月,由国家发改委、国土资源部、环境保护部、住房和城乡建设部四部委联合下发《关于开展市县“多规合一”试点工作的通知》,明确了开展试点的主要任务及措施,并提出在全国28个市县开展“多规合一”试点。 + +2017年,国家启动开展了9个省级空间规划试点,提出以主体功能区规划为基础统筹各类空间性规划,推进“多规合一”,明确以主体功能区规划为基础作用和各类空间性规划作为合一对象。 + +2018年4月,自然资源部成立,作为统一管理山水林田湖草等全民所有自然资源资产的部门,国土空间规划体系确立,提出将主体功能区规划、土地利用规划、城乡规划等空间规划融合为统一的国土空间规划,也就是以上几个空间性规划的“多规合一”,国土空间规划最终正名。 + +纵观我国“多规合一”发展历程,多规合一试点总结阶段可以概括为三个阶段,2003—2012年为探索试点阶段,着重考虑的是战略布局和用地管控,但如何划定红线、搭建技术平台等尚未出台;2013—2015年为正式试点阶段,提出一张蓝图干到底,坚持实施主体功能区制度,落实生态空间用途管制,突出资源环境承载能力,建立规划协调机制,建立控制线体系,形成一本规划、一张蓝图;2016—2018年为深化试点阶段,多规合一试点范围逐步扩大,空间规划改革逐步展开,改革内容不断深化。 + +\subsection{“多规合一”的目标} +“多规合一”是在一级政府一级事权下,强化国民经济和社会发展规划、城乡规划、土地利用规划、环境保护、文物保护、林地与耕地保护、综合交通、水资源、文化与生态旅游资源、社会事业规划等各类规划的衔接,确保“多规”确定的保护性空间、开发边界、城市规模等重要空间参数一致,并在统一的空间信息平台上建立控制线体系,以实现优化空间布局、有效配置土地资源、提高政府空间管控水平和治理能力的目标。(见表3.6) + +表3. 6“多规合一”主要目标 + +\subsection{多规合一的政策演进} +表3. 7“多规合一”政策演进 + +\subsection{“多规合一”与国土空间规划} +2018年《中共中央国务院关于统一规划体系更好发挥国家发展规划战略导向作用的意见》,明确了“三级四类”的规划体系,在我国规划发展史上具有里程碑的意义。新规划体系下的国土空间规划,需要以发展规划为上位遵循,落实发展规划的战略目标和重大战略任务,强化国土空间规划在新规划体系中的重要作用以及在自然资源保护开发利用上的刚性管控和指导约束作用,为发展规划确定的重大战略任务落地实施提供空间保障,并对其他规划提出的基础设施、城镇建设、资源能源、生态环保等开发保护活动提供指导和约束。 + +从2014年市县“多规合一”试点的多种规划合一, 到2017年省级空间规划试点的以主体功能区规划为基础的空间性规划合一,再到2019年《若干意见》将主体功能区规划、土地利用规划、城乡规划等空间规划融合为统一的国土空间规划,按照“五级三类四体系”的要求建立国土空间规划体系,国土空间规划的正名标志着我国空间发展和空间治理进入了生态文明新时代、规划体制改革进入了建立空间规划体系的新时期、国土空间规划体系建立进入了落地实施的新阶段。 + +第3章 城乡空间规划思想与理论发展 39 + +3.1我国城乡规划思想与理论发展 39 + +3.1.1中国古代城市规划思想与理论 39 + +3.1.2中国近代城市规划思想与理论 41 + +3.1.3新中国成立后城市规划思想与理论 42 + +3.2西方城市规划思想与理论发展 46 + +3.2.1西方古代城市规划思想与理论 46 + +3.2.2西方近代城市规划思想与理论 49 + +3.2.3 20世纪以来西方现代城市规划思想与理论 51 + +3.2.4 21世纪的城市规划思想与理论变革 57 + +3.3我国土地利用规划理论与实践 58 + +3.3.1第一轮土地利用总体规划(1986-1996年) 59 + +3.3.2第二轮土地利用总体规划(1996-2006年) 59 + +3.3.3第三轮土地利用总体规划(2006一2020年) 59 + +3.4我国主体功能区规划理论与实践 60 + +3.4.1主体功能区的发展历程 60 + +3.4.2主体功能区的核心思想 61 + +3.4.4主体功能区的理论与技术方法 61 + +3.4.5主体功能区的相关实践 62 + +3.5我国生态规划理论与实践 63 + +3.5.1国内外城市生态理论研究与实践新动向 63 + +3.5.2中国生态城市的理论与实践 64 + +3.6多规合一与国土空间规划 66 + +3.6.1“多规合一”的历程 67 + +3.6.2“多规合一”的目标 67 + +3.6.3多规合一的政策演进 68 + +3.6.4“多规合一”与国土空间规划 69 + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 步骤 & 内容 \\ +\hline +1 & 调查 & 以伦敦为对象展开了综合而深入的城市问题及原因调查 \\ +2 & 分析 & 利用城市和乡村两者的优点形成一种新的城市形态——“田园城市” \\ +3 & 观念 & 当城市达到一定规模以后应该停止增长,成为更大体系中的一部分,过量部分由附近的另一城市来接纳,即形成多中心复合的城镇群 \\ +4 & 模式 & 包括城市和乡村两个部分:边缘地区设有工厂、企业,每个田园城市的人口限制在3万人,中心城市为5万—6万人,一组城市的总人口规模为25万人左右。若干个田园城市围绕着中心城市呈圈状布置,之间借助铁路等便捷往来,城市之间是永久性保留的绿色空间 \\ +5 & 措施 & 工商业要赋予私营经济发展的条件,不能由公营垄断;城市中的所有土地必须归全体居民集体所有,城市的收入全部来自租金,在土地上产生的增值仍归集体所有 \\ +6 & 实践 & 1899年组织了田园城市协会宣传他的主张。1903年组建了“田园城市有限公司”,建立了第一座田园城市——莱彻沃斯 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|} +\hline +序号 & 发布日期 & 文件名称 & 发布部门 & 发布意义 \\ +\hline +1 & 2005.10.11 & 《中共中央关于制定国民经济和社会发展第十一个五年规划的建议》 & 中共中央 & 提出了主体功能区的思想,各地区要根据资源环境承载能力和发展潜力,按照优化开发、重点开发、限制开发和禁止开发的不同要求,明确不同区域的功能定位,并制定相应的政策和评价指标,逐步形成各具特色的区域发展格局 \\ +2 & 2006.03.14 & 《中华人民共和国国民经济和社会发展第十一个五年规划纲要》 & 全国人大 & 第一次提出了主体功能区的概念,即将国土空间划分为优化开发、重点开发、限制开发和禁止开发四类主体功能区,按照主体功能定位调整完善区域政策和绩效评价,规范空间开发秩序,形成合理的空间开发结构 \\ +3 & 2011.06.08 & 《全国主体功能区规划》 & 国务院 & 是我国国土空间开发的战略性、基础性和约束性规划,对于推进形成人口、经济和资源环境相协调的国土空间开发格局具有重要意义 \\ +4 & 2017.10.26 & 《关于完善主体功能区战略和制度的若干意见》 & 中共中央 & 进一步明确了主体功能区的科学内涵,即主体功能区既是一种战略,又是一种制度,为之后的主体功能区规划发展提供了相关保障 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +序号 & 开发类型 & 适用范围 & 解决方式 \\ +\hline +1 & 优化开发区域 & 是指经济比较发达,人口比较密集、开发强度较高、资源环境问题比较突出的区域 & 向重点开发区域转移产业,减轻人口、资源大规模跨区域流动和生态环境的压力 \\ +2 & 重点开发区域 & 是指有一定经济基础、资源环境承载能力较强、发展潜力较大、集聚人口和经济条件较好的区域 & 促进产业集群发展,增强承接限制开发和禁止开发区域超载人口的能力 \\ +3 & 限制开发区域 & 分为两类,一类是农产品主产区,即耕地较多、农业发展条件较好的区域;一类是重点生态功能区,即生态系统脆弱或生态功能重要,资源环境承载能力较低的区域 & 农产品主产区必须把增强农业综合生产能力作为发展的首要任务的区域;重点生态功能区必须把增强生态产品生产能力作为首要任务的区域 \\ +4 & 禁止开发区域 & 是依法设立的各级各类自然文化资源保护区域,以及其他禁止进行工业化城镇化开发,需要特殊保护的重点生态功能区 & 限制开发、禁止开发区域要通过生态建设和环境保护,提高生态环境承载能力,逐步成为全国或区域性的生态屏障和自然文化保护区域 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 步骤 & 具体内容 \\ +\hline +1 & 划定生态空间 & 和环保部门划定生态空间,包括生态保护红线及禁止开发区域,同时考虑生态缓冲区域,具有水质净化功能的重要湿地(大水面)以及重要生态功能区域联系通道都划入生态空间中,加以保护 \\ +2 & 空间开发适宜性评价 & 进行空间开发适宜性评价,基于地形图构建基础地理信息数据库,以网格为单元,开展资源环境承载力、发展潜力评价,对空间开发适宜程度进行分类 \\ +3 & 初划城镇空间 & 根据资源环境承载力评价和人口及用地情景初划城镇空间,设定城镇开发的禁止边界(政区边界、50米等高线、水库基线等),门槛边界(一般河流、交通干道和铁路)和弹性边界 \\ +4 & 城市总体规划方案调整 & 城市总体规划方案调整,规模城市建设用地压缩,对规划城镇用地进行相应布局调整 \\ +5 & 土地利用规划允许建设区和有条件建设区调整 & 结合国土部门土地利用规划调整完善和永久基本农田划定工作,依据发展规划和城市总体规划确定的城镇空间范围调整允许建设区和有条件建设区边界,根据与各类规划的协调,与各板块的对接和征求意见,形成城镇、农业、生态三类空间布局总图 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|} +\hline +序号 & 发布日期 & 文件名称 & 发布部门 & 发布意义 \\ +\hline +1 & 2011.10.17 & 《国务院关于加强环境保护重点工作的意见》(国发〔2011〕35号) & 国务院 & 这是我国首次以国务院文件形式出现“生态红线”概念并提出划定任务 \\ +2 & 2013.05.24 & 《坚持节约资源和保护环境基本国策,努力走向社会主义生态文明新时代》 & 中共中央 & 提出要按照人口资源环境相均衡、经济社会生态效益相统一的原则,整体谋划国土空间开发,给自然留下更多修复空间,要牢固树立生态红线的观念 \\ +3 & 2013.11.12 & 《中共中央关于全面深化改革若干重大问题的决定》 & 中共中央 & 将划定生态保护红线提升为国家战略 \\ +4 & 2015.04.25 & 《中共中央国务院关于加快推进生态文明建设的意见》 & 中共中央 & 提出把生态文明建设放在突出的战略位置,以健全生态文明制度体系为重点,优化国土空间开发格局,加大自然生态系统和环境保护力度 \\ +5 & 2015.08.17 & 《党政领导干部生态环境损害责任追究办法(试行)》 & 中共中央 & 对于违反主体功能区定位或者突破资源环境红线、城镇开发边界、不顾资源环境承载能力盲目决策造成严重后果的实行生态环境损害责任终身追责制 \\ +6 & 2015.09.21 & 《生态文明体制改革总体方案》 & 中共中央 & 提出平衡好发展和保护之间的关系,按照主体功能定位控制开发强度,调整空间结构 \\ +7 & 2017.02.07 & 《关于划定并严守生态保护红线的若干意见》 & 中共中央 & 文件提出了生态保护红线的总体要求和内容以及组织保障体系 \\ +8 & 2020.03.03 & 《关于构建现代环境治理体系的指导意见》 & 中共中央 & 提出了构建现代环境治理体系的准则 \\ +9 & 2021.10.20 & 《关于进一步加强生物多样性保护的意见》 & 中共中央 & 提出要持续优化生物多样性保护空间格局,推进重要生态系统保护与修复及完善生物多样性迁徙保护体系 \\ +10 & 2021.10.21 & 《关于推动城乡建设绿色发展的意见》 & 中共中央 & 指出我国要促进区域和城市群绿色发展,建立人与自然和谐共生的美丽城市和乡村 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 主要目标 & 内容 \\ +\hline +1 & 完成“一张蓝图” & 统一城市发展目标、发展战略及功能布局,深入梳理并协调消除市县各类规划之间的矛盾,实现市县域“多规合一”,将各类生态管控红线、城乡建设和产业区块、基础设施和公共服务设施、重大项目用地和历史文化保护范围等落实到一张蓝图上 \\ +2 & 构筑管理“一个平台” & 搭建区域统一的信息共享和管理平台,利用卫星遥感等技术实现与规划信息平台结合,对开发边界、自然资源和生态环境状况进行全天候的监测,推动综合执法,为简化行政审批提供重要支撑 \\ +3 & 推行审批“一张表格” & 按照一张蓝图规划、依托一个平台管理,转变审批理念,简化项目审批程序,实施审批制度改革,实现“一份办事指南、一张申请表单、一套申报材料”完成审批 \\ +4 & 完善配套“运行机制” & 建立法律保障机制,将多规合一划定的生态红线、建设用地增长边界等控制线纳入地方立法;以政府规章形式明确“多规合一”控制线管理主体、管理办法,统一技术标准。完善相关配套机制,建立部门业务联动制度、优化建设项目审批制度、建立监控考核制度、建立动态更新维护制度,改进绩效激励机制 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +序号 & 日期 & 法规与会议名称 & 内容 \\ +\hline +1 & 1991年1月 & 《中华人民共和国土地管理法》 & 对经济社会发展规划、城乡规划、水利规划与土地利用总体规划的协调进行了规定 \\ +2 & 2008年1月 & 《中华人民共和国城乡规划法》 & 对城乡规划与其他规划的协调进行了规定 \\ +3 & 2010年12月 & 《中华人民共和国水土保持法》 & 明确了水土保持规划应当与土地利用总体规划、水资源规划、城乡规划和环境保护规划等相协调 \\ +4 & 2013年11月 & 《中共中央关于全面深化改革若干重大问题的决定》 & 要求建立空间规划体系,划定生产、生活、生态空间开发管制界线,落实用途管制 \\ +5 & 2014年3月 & 《国家新型城镇化规划(2014-2020年)》 & 加强城市规划与经济社会发展、主体功能区建设等规划的相互衔接,推动“多规合一” \\ +6 & 2014年8月 & 《关于开展市县“多规合一”试点工作的通知》 +(发改规划[2014]1971号) & 从全国范围内遴选确定了28个“多规合一”试点市县 \\ +7 & 2015年5月 & 《2015年深化经济体制改革重点工作意见》(国发〔2015〕26号) & 要完善国土空间开发,加强生态文明制度顶层设计,开展市县“多规合一”试点 \\ +8 & 2015年10月 & 《生态文明体制改革总体方案》 & 要构建国土空间开发保护制度和空间规划体系;要整合各类空间性规划,编制统一的空间规划;要支持市县推进“多规合一”,明确开发边界和保护边界 \\ +9 & 2015年12月 & 中央城市工作会议 & 要以主体功能区规划为基础,统筹各类空间性规划,推进“多规合一” \\ +10 & 2016年2月 & 《中共中央国务院关于进一步加强城市规划建设管理工作的若干意见》 & 要推进两图合一;要实现一张蓝图干到底 \\ +11 & 2016年3月 & 《2016年深化经济体制改革重点工作意见》(国发〔2016〕21号) & 以主体功能区规划为基础统筹各类空间性规划,推进“多规合一” \\ +12 & 2016年7月2日 & 《中华人民共和国水法》 & 流域综合规划和区域综合规划以及与土地利用关系密切的专业规划,应当与国民经济和社会发展规划等相协调 \\ +13 & 2016年12月 & 《“十三五”生态环境保护规划》(国发〔2016〕65号) & 要强化“多规合一”的生态环境支持,积极推动建立国家空间规划体系,统筹各类空间规划,推进“多规合一” \\ +14 & 2017年2月 & 《全国国土规划纲要(2016-2030年)》(国发〔2017〕3号) & 要统筹各类空间性规划,推进“多规合一”,要编制国家级、省级国土规划,并与城乡建设等规划相协调,要推动市县层面“多规合一” \\ +15 & 2017年4月 & 《国务院办公厅关于同意建立省级空间规划试点工作部际联席会议制度的函》(国办函〔2017〕34号) & 同意建立由国家发改委牵头的省级空间规划试点工作部际联席会议制度 \\ +16 & 2019年5月9日 & 《关于建立国土空间规划体系并监督实施的若干意见》(中发〔2019〕18号) & 从七大方面阐述了国土空间规划体系构建与监督实施的总体安排,是开展国土空间规划的国家层面上的政策文件 \\ +17 & 2019年07月18日 & 《关于开展国土空间规划“一张图”建设和现状评估工作的通知》自然资办发〔2019〕38 号 & 依托国土空间基础信息平台,全面开展国土空间规划“一张图”建设和市县国土空间开发保护现状评估工作 \\ +18 & 2019年9月17日 & 《自然资源部关于以“多规合一”为基础推进规划用地 “多审合一、多证合一”改革的通知》(自然资规[2019]2号) & 合并规划选址和用地预审,合并建设用地规划许可和用地批准,推进多测整合、多验合一,简化报件审批材料 \\ +19 & 2020年5月22日 & 《关于加强国土空间规划监督管理的通知》(自然资办发〔2020〕27号) & 切实把“多规合一”改革精神落到实处。在多规合一基础上全面推进规划用地“多审合一,多证合一” \\ +20 & 2021年9月1日 & 《中华人民共和国土地管理法实施条例》 & 国家建立国土空间规划体系。经依法批准的国土空间规划是各类开发、保护、建设活动的基本依据 \\ +21 & 2021年09月27日 & 《国土空间规划技术标准体系建设三年行动计划(2021—2023年)》(自然资发〔2021〕135号) & 加快建立国土空间规划技术标准体系,研制一批标准,创新标准制定工作机制 \\ +\hline +\end{tabular} +\end{table} + diff --git a/data/book/chapter04.tex b/data/book/chapter04.tex new file mode 100644 index 0000000..d3f3988 --- /dev/null +++ b/data/book/chapter04.tex @@ -0,0 +1,2772 @@ +\chapter{国土空间规划基本原理与体系构成} +国土空间规划是国家空间发展的指南,可持续发展的空间蓝图,是各类开发保护建设活动的基本依据。国土空间规划通过建立全国统一、责权清晰、科学高效的国土空间规划体系,整体谋划新时代国土空间开发保护格局,综合考虑人口分布、经济布局、国土利用、生态环境保护等因素,科学布局生产空间、生活空间、生态空间,是加快形成绿色生产方式和生活方式、推进生态文明建设、建设美丽中国的关键举措,是坚持以人民为中心、实现高质量发展和高品质生活、建设美好家园的重要手段,是保障国家战略有效实施、促进国家治理体系和治理能力现代化、实现“两个一百年”奋斗目标和中华民族伟大复兴中国梦的必然要求。 + +\section{国土空间规划编制总则与基本术语} +\subsection{国土空间规划编制总则} +\subsubsection{1.规划原则} +(1)体现战略性和协调性 + +全面落实党中央、国务院重大决策部署,体现国家意志和国家发展规划的战略性,自上而下编制各级国土空间规划,对空间发展作出战略性系统性安排。落实国家安全战略、区域协调发展战略和主体功能区战略,明确空间发展目标,优化城镇化格局、农业生产格局、生态保护格局,确定空间发展策略,转变国土空间开发保护方式,提升国土空间开发保护质量和效率;强化国家发展规划的统领作用,强化国土空间规划的基础作用;国土空间总体规划要统筹和综合平衡各相关专项领域的空间需求。详细规划要依据批准的国土空间总体规划进行编制和修改。相关专项规划要遵循国土空间总体规划,不得违背总体规划强制性内容,其主要内容要纳入详细规划。 + +(2)提高科学性和操作性 + +坚持生态优先、绿色发展,尊重自然规律、经济规律、社会规律和城乡发展规律,因地制宜开展规划编制工作;坚持节约优先、保护优先、自然恢复为主的方针,在资源环境承载能力和国土空间开发适宜性评价的基础上,科学有序统筹布局生态、农业、城镇等功能空间,划定生态保护红线、永久基本农田、城镇开发边界等空间管控边界以及各类海域保护线,强化底线约束,为可持续发展预留空间。坚持山水林田湖草生命共同体理念,加强生态环境分区管治,量水而行,保护生态屏障,构建生态廊道和生态网络,推进生态系统保护和修复,依法开展环境影响评价;坚持陆海统筹、区域协调、城乡融合,优化国土空间结构和布局,统筹地上地下空间综合利用,着力完善交通、水利等基础设施和公共服务设施,延续历史文脉,加强风貌管控,突出地域特色;坚持上下结合、社会协同,完善公众参与制度,发挥不同领域专家的作用。运用城市设计、乡村营造、大数据等手段,改进规划方法,提高规划编制水平;按照谁组织编制、谁负责实施的原则,明确各级各类国土空间规划编制和管理的要点。明确规划约束性指标和刚性管控要求,同时提出指导性要求;制定实施规划的政策措施,提出下级国土空间总体规划和相关专项规划、详细规划的分解落实要求,健全规划实施传导机制,确保规划能用、管用、好用。 + +(3)强化传导性与权威性 + +规划一经批复,任何部门和个人不得随意修改、违规变更,防止出现换一届党委政府改一次规划的情况,下级国土空间要服从上级国土空间规划,相关专项规划、详细规划要服从总体规划;坚持先规划后实施,不得违反国土空间规划进行各类开发建设活动;坚持“多规合一”,不在国土空间规划体系之外另设其他空间规划;相关专项规划的有关技术标准应与国土空间规划衔接;因国家重大战略调整、重大项目建设或行政区划调整等确需修改规划的,须先经规划审批机关同意后,方可按法定程序进行修改。对国土空间规划编制和实施过程中的违规违纪违法行为,要严肃追究责任。 + +\subsubsection{2.规划依据} +根据国家对国土空间规划的总体要求,其编制的基本依据主要包括相关法律法规、相关政府文件和相关规划等方面。 + +\subsubsection{3.规划范围} +根据国家行政管理层级的结构特点,国土空间规划的规划范围是行政区范围内的全部国土空间。 + +\subsubsection{4.规划期限} +规划期限是规划编制有效执行的时间范围,也是各类规划衔接目标任务、指标测算和进行空间协调的时间节点,党的十九大报告指出“从2020年到2035年,在全面建成小康社会的基础上,再奋斗十五年,基本实现社会主义现代化”,据此把此轮国土空间总体规划的目标年设定为2035年。 + +\subsection{国土空间规划基本术语} +(1)国土空间 + +国家主权与主权权利管辖下的地域空间,包括陆地国土空间和海洋国土空间。 + +(2)国土空间规划 + +对国土空间的保护、开发、利用、修复作出的总体部署与统筹安排。 + +(3)国土空间保护 + +对承担生态安全、粮食安全、资源安全等国家安全的地域空间进行管护的活动。 + +(4)国土空间开发 + +以城镇建设、农业生产和工业生产等为主的国土空间开发活动。 + +(5)国土空间利用 + +根据国土空间特点开展的长期性或周期性使用和管理活动。 + +(6)生态修复和国土综合整治 + +遵循自然规律和生态系统内在机理,对空间格局失衡、资源利用低效、生态功能退化、生态系统受损的国土空间,进行适度人为引导、修复或综合整治,维护生态安全、促进生态系统良性循环的活动。 + +(7)国土空间用途管制 + +以总体规划、详细规划为依据,对陆海所有国土空间的保护、开发和利用活动,按照规划确定的区域、边界、用途和使用条件等,核发行政许可、进行行政审批等。 + +(8)国土空间规划分区 + +根据自然资源部《市县国土空间规划分区与用途分类指南》,国土空间规划分区是以全域覆盖、不交叉、不重叠为基本原则,以国土空间的保护与保留、开发与利用两大管控属性为基础,根据市县主体功能区战略定位,结合国土空间规划发展策略,将市县全域国土空间划分为生态保护区、自然保留区、永久基本农田集中区、城镇发展区、农业农村发展区、海洋发展区等6类基本分区,并明确各分区的核心管控目标和政策导向。同时,还可对城镇发展区、农业农村发展区、海洋发展区等规划基本分区进行细化分类。 + +(9)主体功能区 + +以资源环境承载能力、经济社会发展水平、生态系统特征以及人类活动形式的空间分异为依据,划分出具有某种特定主体功能、实施差别化管控的地域空间单元。 + +(10)资源环境承载能力评价 + +资源环境承载能力评价指的是基于特定发展阶段、经济技术水平、生产生活方式和生态保护目标,一定地域范围内资源环境要素能够支撑农业生产、城镇建设等人类活动的最大规模。 + +(11)国土空间开发适宜性评价 + +国土空间开发适宜性评价,指的是在维系生态系统健康和国土安全的前提下,综合考虑资源环境等要素条件,特定国土空间进行农业生产、城镇建设等人类活动的适宜程度。 + +(12)国土空间开发保护现状评估 + +一般以安全、创新、协调、绿色、开放、共享等理念构建的指标体系为标准,从数量、质量、布局、结构、效率等角度,找出一定区域国土空间开发保护现状与高质量发展要求之间存在的差距和问题所在。同时可在现状评估基础上,结合影响国土空间开发保护因素的变动趋势,分析国土空间发展面临的潜在风险。 + +(13)空间规划实施评估 + +指对现行土地利用总体规划、城乡总体规划、林业草业规划、海洋功能区划等空间类规划,在规划目标、规模结构、保护利用等方面的实施情况进行评估,并识别不同空间规划之间的冲突和矛盾,总结成效和问题。 + +(14)生态空间 + +以提供生态系统服务或生态产品为主的功能空间。 + +(15)农业空间 + +以农业生产、农村生活为主的功能空间。 + +(16)城镇空间 + +以承载城镇经济、社会、政治、文化、生态等要素为主的功能空间。 + +(17)生态保护红线 + +在生态空间范围内具有特殊重要生态功能,必须强制性严格保护的陆域、水域、海域等区域。 + +(18)永久基本农田 + +按照一定时期人口和经济社会发展对农产品的需求,依据国土空间规划确定的不得擅自占用或改变用途的耕地。 + +(19)城镇开发边界 + +在一定时期内因城镇发展需要,可以集中进行城镇开发建设,重点完善城镇功能的区域边界,涉及城市、建制镇以及各类开发区等。 + +(20)城市体检评估 + +依据市级总规等国土空间规划,按照“一年一体检、五年一评估”,对城市发展体征及规划实施情况定期进行的分析和评价,是促进和保障国土空间规划有效实施的重要工具。 + +(21)规划留白 + +为重大项目、重大事件预留空间,旨在应对市县发展的不确定性,运用指标预留、空间预留、功能预留等多种手段做出的弹性安排和机制设计。 + +(22)国土空间规划一张图 + +国土空间规划一张图是指以自然资源调查监测数据为基础,采用国家统一的测绘基准和测绘系统,整合各类空间关联数据,建成全国统一的国土空间基础信息平台后,再以此平台为基础载体,结合各级各类国土空间规划编制,建设从国家到市县级、可层层叠加打开的国土空间规划“一张图”实施监督信息系统,形成覆盖全国、动态更新、权威统一的国土空间规划“一张图”。 + +\subsection{国土空间用地分类} +实施全国自然资源统一管理,科学划分国土空间用地用海类型、明确各类型含义,统一国土调查、统计和规划分类标准,合理利用和保护自然资源具有重要意义。指南喻为辨别方向的依据,也泛指为人们提供指导性资料或情况的文字性指导。《国土空间调查、规划、用途管制用地用海分类指南》包含国土空间领域各类用地用海分类规定,贯穿自然资源管理全过程,是自然资源管理部门、国土单位、技术人员共同的技术指南。 + +国土空间用地分类适用于国土调查、监测、统计、评价,国土空间规划、用途管制、耕地保护、生态修复,土地审批、供应、整治、执法、登记及信息化管理等工作。国土空间用地分类坚持陆海统筹、城乡统筹、地上地下空间统筹;体现生态优先、绿色发展理念;坚持同级内分类并列不交叉,坚持科学、简明、可操作。 + +\subsubsection{1.用地分类原则} +(1)持续丰富留余地 + +为应对城市未来发展的不确定性,针对国土空间规划确定的城镇、村庄范围内暂未明确规划用途、规划期内不开发或特定条件下开发的用地,增设“留白用地”。《用地用海分类指南》为基础通用版,各地在使用过程中,可根据实践经验不断深化、细化,进一步探索和完善,在现有分类基础上制定用地用海分类实施细则。 + +(2)陆海统筹广覆盖 + +《国土空间调查、规划、用途管制用地用海分类指南》实现国土空间的全域全要素覆盖,遵循“陆海统筹”的基本原则,在分类体系设置上,整体考虑用海与用地分类,将陆域国土空间的相关用途与海洋资源利用的相关用途在名称上进行统筹和衔接,好记易懂,也方便操作;遵循“城乡统筹”的基本原则,在陆域实现非建设用地、建设用地全覆盖,满足城乡差异化管理;遵循“地上地下空间统筹”的基本原则,在空间复合分层上实现地上、地下空间全覆盖,满足精细化管理的需求。 + +(3)适应市场强指导 + +为加强基本公共服务设施的服务保障,适应市场需求变化,更好的复合和兼容相关土地使用,为自然资源管理提供重要的技术支撑,构建统一的国土空间规划技术标准体系,修订完善国土资源现状调查和国土空间规划用地分类标准。《国土空间调查、规划、用途管制用地用海分类指南》在整合原《土地利用现状分类》、《城市用地分类与规划建设用地标准》、《海域使用分类》等分类基础上,建立全国统一的国土空间用地用海分类。 + +(4)提质增效保安全 + +指南对必须要加强用途管制、提供用地保障,或对选址布局有特殊要求的用地类型进行进一步的细分;对用途或性质相近、没有布局管制要求或用途间转换不需严格区别、无特别附加条件的,则不再细分用地类型,以此满足新时期差异化与精细化管理需求。为促进城乡统筹协调发展,对于农村社区生活服务之外的公共管理与公共服务用地、商业服务业用地、工矿用地、仓储用地、公用设施用地等用地,不再单独设立农村专用地类,统一使用相应的用地分类,体现城乡一体化。 + +\subsubsection{2.分类一般规定} +用地用海分类应体现主要功能,兼顾调查监测、空间规划、用途管制、用地用海审批和执法监管的管理要求,并应满足城乡差异化管理和精细化管理的需求。《用地用海分类指南》确定的分类按照用地用海实际使用的主要功能或规划引导的主要功能进行归类,具有多种用途的用地应以其地面使用的主导设施功能作为归类的依据。 + +《国土空间调查、规划、用途管制用地用海分类指南》建立全国统一的国土空间用地用海分类,其适用范围覆盖自然资源管理全过程,包括国土调查、监测、统计、评价,国土空间规划、用途管制、耕地保护、生态修复,土地审批、供应、整治、执法、登记及信息化管理等工作环节。并针对自然资源管理中不同的工作环节提供多种使用规则,对应使用不同的分类层级。 + +(1)基本功能 + +依据国土空间的主要配置利用方式、经营特点和覆盖特征等因素,对国土空间的用地用海类型进行归纳、划分、反映国土空间利用的基本功能,满足自然资源管理需要。 + +(2)主要功能 + +用地用海分类设置不重不漏。当用地用海具备多种用途时,应以其主要功能进行归类。 + +(3)使用原则(见表4.1) + +表4. 1国土空间调查、规划、用途管制用地用海使用分类原则 + +\section{国土空间规划体系} +经逐步完善,2019年5月中共中央、国务院印发《关于建立国土空间规划体系并监督实施的若干意见》,标志着我国国土空间规划体系顶层设计“四梁八柱”基本形成(如图4.1所示)。 + +\textbf{图}\textbf{ }\textbf{4.1}\textbf{国土空间规划的“五级级三类四体系”示意图} + +\subsection{国土空间规划体系的“五级”} +国土空间规划分为国家级、省级、市级、县级、乡镇级五级。五级规划分别对应五个行政管理层级,实现一级政府、一级事权、一级规划。五级规划自上而下编制,下级规划服从、服务于上级规划,不得违背上级规划确定的约束性内容。不同层级规划体现不同的空间尺度和编制深度要求。 + +\subsubsection{1.国家级国土空间规划} +国家级国土空间规划由自然资源部会同相关部门组织编制,其功能定位是对全国国土空间作出全局安排,是全国国土空间保护、开发、利用、修复的政策和总纲。全国国土空间总体规划侧重战略性,即落实国家安全战略、区域协调发展战略和主体功能区战略,明确全国国土空间发展目标策略,优化全国国土空间格局,制定和分解规划的约束性指标,确定国土空间开发利用整治保护的重点地区和重大项目,提出空间开发的政策指南和空间治理的总体原则。国家级国土空间规划的重点内容(见表4.2)。 + +表4. 2国家级国土空间规划内容 + +\subsubsection{2.省级国土空间规划} +省级国土空间规划功能定位是落实全国国土空间规划,指导市、县国土空间规划编制,侧重协调性。省级国土空间规划既要落实国家发展战略、主体功能区战略等要求,也要对省域空间发展保护格局进行统筹部署,促进省域城镇化健康发展、城乡区域协调发展,还是指导市县等下层次国土空间规划的基本依据,具有战略性、综合性和协调性。纵向上,要落实上位规划的目标和战略,明确本级规划的底线和重点,提出对下位规划的控制与引导要求;横向上,要统筹省级有关部门的各类空间规划(专项规划),明确各部门的空间使用和管理边界,省级国土空间规划的重点内容(见表4.3)。 + +表4. 3省级国土空间规划内容 + +\subsubsection{3.市级国土空间规划} +市级国土空间规划由相应层级人民政府组织编制,其功能定位是细化落实上级国土空间规划要求,对本行政区域国土空间开发保护作出具体安排,注重保护和发展的底线划定及公共资源的配置安排,重点突出市域中心城市的空间规划,合理确定中心城市的规模、范围和结构。市级国土空间规划发挥空间引导功能和承上启下的控制作用,侧重实施性。市级国土空间规划的重点内容(见表4.4)。 + +表4. 4市级国土空间规划内容 + +\subsubsection{4.县级国土空间规划} +县级国土空间规划除了落实上位规划的战略要求和约束性指标以外,要重点突出空间结构布局,突出生态空间修复和全域整治,突出乡村发展和活力激发,突出产业对接和联动开发。县级国土空间规划,在开发、保护、利用方面提出可操作的实施方案,实现全域全要素规划管控,县级国土空间规划的重点内容(见表4.5)。 + +表4. 5县级国土空间规划内容 + +\subsubsection{5.乡镇级国土空间规划} +乡镇级国土空间规划突出土地用途和全域管控,对具体地块的用途做出确切的安排。乡镇级国土空间规划是乡村建设规划许可的法定依据,重在体现落地性、实施性和管控性,突出土地用途和全域管控,充分融合原有的土地利用规划和村庄建设规划,对具体地块的用途做出确切的安排,对各类空间要素进行有机整合,乡镇级国土空间规划的重点内容(见表4.6)。 + +表4. 6乡镇级国土空间规划内容 + +\subsection{国土空间规划体系的“三类”} +国土空间规划分为总体规划、详细规划、相关专项规划三类。国土空间总体规划是详细规划的依据、相关专项规划的基础,相关专项规划要相互协同,并与详细规划做好衔接。 + +\subsubsection{1.总体规划} +总体规划强调综合性,是对一定区域(如行政区全域)范围所涉及的国土空间保护、开发、利用、修复等进行的全局性安排。 + +国家级国土空间总体规划对国土空间开发、资源环境保护、国土综合整治和保障体系建设等做出总体部署与统筹安排,对涉及国土空间开发、保护、整治的各类活动具有指导和管控作用,对相关国土空间专项规划具有引领和协调作用,是战略性、综合性、基础性的规划。国家级国土空间总体规划由自然资源部会同相关部门组织编制,经全国人大常委会审议后报中共中央、国务院审批。 + +省级国土空间总体规划是对全省国土空间保护、开发、利用、修复的总体安排和政策总纲,是编制省级相关专项规划、市县级国土空间总体规划的总依据。省级国土空间总体规划由省人民政府组织编制,经省人大常委会审议后报国务院审批。 + +市县级国土空间总体规划是对市县域的空间发展蓝图和战略部署,是落实新发展理念,实施高效能空间治理、促进高质量发展和高品质生活的空间政策,是市县域国土空间保护、开发、利用、修复和指导各类建设的全面安排、综合部署和行动纲领。市县级国土空间总体规划要体现综合性、战略性、协调性、基础性和约束性,落实和深化上位规划要求,为编制下位国土空间总体规划、详细规划、相关专项规划和开展各类开发保护建设活动、实施国土空间用途管制提供基本依据。市县级国土空间总体规划一般包括市县域和中心城区两个层次:市县域要统筹全域全要素规划管理,侧重国土空间开发保护的战略部署和总体格局;中心城区要细化土地使用和空间布局,侧重功能完善和结构优化。市县域与中心城区都要落实重要管控要素的系统传导要求,并做好上下衔接。市县级国土空间总体规划由市、县(市)人民政府组织编制,除需报国务院审批的城市国土空间总体规划外,其他市县级国土空间总体规划经同级人大常委会审议后,逐级上报省人民政府审批。 + +乡镇级国土空间总体规划是对上级国土空间总体规划以及相关专项规划的细化落实,允许乡镇级国土空间总体规划与市县级国土空间总体规划同步编制。各地可因地制宜地将几个乡(镇、街道)作为一个规划片区,由其共同的上一级人民政府组织编制片区(乡镇级)国土空间总体规划。中心城区范围内的乡镇级国土空间总体规划经同级人大常委会审议后,逐级上报省人民政府审批,其他乡镇级国土空间总体规划由省人民政府授权设区市人民政府审批。 + +\subsubsection{2.详细规划} +详细规划强调实施性,一般是在市县以下组织编制,以总体规划为依据,是对具体地块用途、开发强度、管控要求等做出的实施性安排。详细规划是实施国土空间用途管制、核发城乡建设项目规划许可、进行各项建设的法定依据。 + +各地应当根据国土空间开发保护利用活动实际,合理确定详细规划编制单元和时序,按需编制。根据生态、农业、城镇空间的不同特征,依总体规划确定的规划单元分类编制详细规划。在城镇开发边界内的详细规划(主要是控制性详细规划),由市、县(市)自然资源主管部门组织编制,报同级人民政府审批;在城镇开发边界外的乡村地区,以一个或几个行政村为单元,由乡镇人民政府组织编制“多规合一”的村庄规划(详细规划),报上一级人民政府审批。根据实际需要,还可以编制郊野单元、生态单元、特定功能单元等其他类型的详细规划,由市、县(市)自然资源主管部门或由市、县(市)自然资源主管部门会同属地乡镇人民政府、管委会组织编制,报同级人民政府审批。 + +详细规划是对具体地块用途和开发建设强度等作出的实施性安排,是开展国土空间开发保护活动、实施国土空间用途管制、核发城乡建设项目规划许可、进行各项建设等的法定依据。在城镇开发边界内的详细规划,由市县自然资源主管部门组织编制,报同级政府审批;在城镇开发边界外的乡村地区,以一个或几个行政村为单元,由乡镇政府组织编制“多规合一”的实用性村庄规划,作为详细规划,报上一级政府审批。 + +\subsubsection{3.专项规划} +国土空间专项规划是在总体规划的指导约束下,针对特定区域(流域)或特定领域,在国土空间开发保护利用上做出的专门安排。一般包括自然保护地、湾区、海岸带、都市圈(区)等区域(流域)的空间规划,以及交通、水利、能源、公共服务设施、军事设施、生态修复、环境保护、文物保护、林地湿地等领域的专项规划。除法律法规已经明确编制审批要求的专项规划外,其他专项规划一般由所在区域自然资源主管部门或相关行业主管部门牵头组织编制,经国土空间规划“一张图”审查核对后报本级人民政府审批,批复后统一纳入国土空间规划“一张图”及其信息系统。 + +\subsection{国土空间规划体系的“四体系”} +“四体系”是指国土空间规划的编制审批体系、实施监督体系、法规政策体系和技术标准体系。 + +\subsubsection{1.编制审批体系} +规划编制审批体系强调不同层级、类别规划之间的协调与配合,体现了一级政府一级事权,实现全域全要素规划管控。规划的编制审批体系涉及各级各类规划的编制主体、审批主体和重点内容。根据《关于建立国土空间规划体系并监督实施的若干意见》,全国国土空间规划由自然资源部会同相关部门组织编制,由党中央、国务院审定后印发;省级国土空间规划由省级人民政府组织编制,经同级人大常委会审议后报国务院审批;国务院审批的城市国土空间总体规划,由市人民政府组织编制,经同级人大常委会审议后,由省级人民政府报国务院审批;其他市、县及乡镇国土空间规划的审批内容和程序由省级人民政府具体规定。海岸带、自然保护地等专项规划及跨行政区域或流域的国土空间规划,由所在区域或上一级自然资源主管部门牵头组织编制,报同级人民政府审批,具体国土空间规划编制审批体系(见表4.7)。 + +表4. 7国土空间规划编制审批体系 + +\subsubsection{2.实施监督体系} +实施监督体系以国土空间规划为依据,对所有国土空间分区分类实施用途管制;按照“谁组织编制、谁负责实施”“谁组织审批、谁负责监管”的原则,建立健全国土空间规划动态监测评估预警和实施监管机制,逐层授权、层层监督;按照“以空间定计划、以存量定计划、以效率定计划、以占补定计划”的要求,加强用地、用海、用林、用矿等自然资源要素配置的区域统筹力度,完善自然资源利用年度计划管理,保障规划稳步实施;强化国土空间规划的底线约束和刚性管控,制定各类空间控制线的管控要求,并开展各类空间控制线划区定界工作。依托国土空间基础信息平台,建立健全国土空间规划动态监测评估预警和实施监管机制。 + +\subsubsection{3.法规政策体系} +完善法规政策体系,加快国土空间规划相关法律法规建设。研究制定国土空间规划及其相关立法,加快国土空间规划相关法律法规建设。梳理与国土空间规划相关的现行法律法规和部门规章,对“多规合一”改革涉及突破现行法律法规规定的内容和条款,按程序报批,取得授权后施行,并做好过渡时期的法律法规衔接。完善适应主体功能区要求的配套政策,保障国土空间规划有效实施。 + +\subsubsection{4.技术标准体系} +国土空间规划是“多规合一”的规划,需要对城乡规划、土地利用规划、主体功能区规划等原有技术标准体系进行重构,建构统一的国土空间技术标准体系,并制定各类各级国土空间规划编制技术规程。为了保障国土空间规划所要求的精准传导、有效实施、及时监控,国家建立统一底板、统一数据标准、分层分级管理的国土空间规划信息平台,在信息平台上统一进行规划编制与实施管理。由自然资源部会同相关部门负责构建统一的国土空间规划技术标准体系,修订完善国土资源现状调查和国土空间规划用地分类标准,制定各级各类国土空间规划编制办法和技术规程。 + +\section{国土空间规划编制基本方法} +\subsection{国土空间规划基本原理} +\subsubsection{1.多规合一、全域管控} +国土空间规划体系延续优化主体功能区的战略导向,土地利用规划的耕地保护和集约用地,城乡规划的综合部署和建设管理,以及规划作为维护社会公平、保障公共安全和公众利益的重要公共政策属性。国土空间规划将主体功能区规划、土地利用规划、城乡规划等空间规划融合统一,实现“多规合一”,强化国土空间规划对各专项规划的指导约束作用。 + +国土空间规划对建设用地、非建设用地、未利用地等所有国土空间进行全域管控,对“山水林田湖草沙”生命共同体进行国土资源管控,通过与内外部纵横衔接协调,跨区域合作,提升国土空间治理体系和治理能力现代化水平。 + +\subsubsection{2.承上启下、多元协同} +国土空间规划以空间治理和空间结构优化为主要内容,细化落实发展规划对国土空间开发保护的要求,是实施国土空间用途管制和生态保护修复的重要依据,对专项规划具有空间性指导和约束作用。国土空间规划向上对接发展规划,向下指导和约束专项规划,在国家规划体系中具有承上启下的重要作用。 + +国土空间规划以自然资源部门为引领,协同发改、住建、林草、农业农村、交通、环保等部门,在发展战略和目标、空间结构优化、重大生产力布局等问题上,加强部门联合攻关,推进主要规划目标、重大项目部署等方面的衔接,建立上下层级清晰、部门分工明确的国土空间规划体系。 + +\subsubsection{3.摸清家底、因地制宜} +国土空间规划在资源环境承载能力和国土空间开发适宜性评价的基础上全面摸清国土空间家底,分析区域资源禀赋与环境条件,研判国土空间开发利用问题和风险,认识区域资源环境禀赋特点,找出优势与短板,识别生态保护极重要区,明确农业生产、城镇建设的最大合理规模和适宜空间,为编制国土空间规划,优化国土空间开发保护格局,完善区域主体功能定位,做到“宜农则农,适城则城,必保则保”,科学合理划定生态保护红线,永久基本农田、城镇开发边界等三条控制线,为实施国土空间生态修复和国土综合整治重大工程提供基础性依据。 + +\subsubsection{4.底线约束、保护优先} +坚持最严格的生态环境保护制度、耕地保护制度和节约用地制度,维护国家生态安全、粮食安全等国土安全。三条控制线作为调整经济结构、规划产业发展、推进城镇化不可逾越的红线,是中华民族永续发展的基础,以底线思维为出发点,根据各类控制线的相关法律法规、政策要求,科学合理地划定永久基本农田、生态保护红线、城镇开发边界,同步划定历史文化、各类海域保护线及矿产资源等其他需要保护和控制的底线并提出相应控制要求,为可持续发展预留空间。 + +\subsubsection{5.逐级传导、分类编制} +国土空间规划分为五级三类,规划自上而下编制,规定下级规划要服从上级规划,按照“国家—省—市—县—乡”五级层层传导落实,各级总体规划在规划传导手段上,采取分区传导、指标控制、边界管控、名录管理、政策规定等。国土空间规划包含总体规划、详细规划和相关专项规划三类,总体规划是战略性总纲,相关专项规划是对特定区域或特定领域空间开发保护的安排,详细规划则做出具体细化的实施性规定,是规划许可的依据。国土空间总体规划是详细规划的依据、相关专项规划的基础;专项规划和详细规划要落实总体规划,相关专项规划要相互协同,并与详细规划做好衔接。 + +全国和省国土空间规划主要是落实国家安全战略、区域协调发展战略和主体功能区战略,明确全国和省域空间发展目标,优化城镇化格局、农业生产格局、生态保护格局,确定空间发展策略,并制定国土空间开发保护和用途管制的整体框架。市县和乡镇国土空间规划要细化落实上级国土空间规划的要求,并对本行政区域开发保护作出具体安排;市县及乡镇国土空间规划分为总体规划和详细规划,对相应的政区空间以规划功能分区和制定规划用途分类等方式来施以管控,包括依据规划施行空间用途管制和城乡建设规划许可管理。 + +\textbf{图 }\textbf{4.2}\textbf{“三区三线”划定流程图} + +\subsection{国土空间规划管控方法} +\subsubsection{1.统筹推进、用途管制} +国土空间用途管制,是以总体规划、详细规划为依据,对海陆所有国土空间的保护、开发和利用活动,按照规划确定的区域、边界、用途和使用条件等,核发行政许可、进行行政审批等。对所有国土空间分区分类实施用途管制,在城镇开发边界内的建设,实行“详细规划+规划许可”的管制方式;在城镇开发边界外的建设,按照主导用途分区,实行“详细规划+规划许可”和“约束指标+分区准入”的管制方式。对国家公园为主体的自然保护地、重要海域和海岛、重要水源地、文物等实行特殊保护制度。因地制宜制定用途管制制度,为地方管理和创新活动留有空间。 + +\subsubsection{2.四大体系、全面运行} +建立“多规合一”的国土空间规划体系是系统性、整体性、重构性的改革,是一整套运行体系制度设计。国土空间规划包含编制审批体系、实施监督体系、法规政策体系和技术标准体系四个体系。其中,规划编制审批体系和实施监督体系包括从编制、审批、实施、监测、评估、预警、考核、完善等完整闭环的规划及实施管理流程;法规政策体系和技术标准体系是两个基础支撑。 + +\subsubsection{3.一本蓝图、贯彻到底} +通过编制国土空间规划统一规划期限、基础数据、坐标系统、用地分类、目标指标和管控分区等规划基础;通过基础评价摸清国土空间的家底,进而科学划定“三区三线”,并将各类空间性规划的管控要素落到统一的一张底图上,由此实现开发保护的协调统一。规划一经批复,任何部门和个人不得随意修改,违规变更,防止出现换一届党委和政府改一次规划。坚持先规划后实施,不得违反国土空间规划进行各类开发建设活动,坚持“多规合一”,不在国土空间规划体系外另设其他空间规划,让所有的规划都能在“一张蓝图”上进行落地实施。国土空间规划是现代国家进行空间治理和提高行政效率的重要手段,国土空间规划是现代国家政府进行空间治理的核心手段,是政府调控和引导空间资源配置的基础。 + +\subsubsection{4.三大应用、高效治理} +以政策、制度、标准为基础,以安全运维为保障,在“一张网”、“一张图”、“一个平台”的基础上,构建“三大应用体系”。用好自然资源的“一张网”、“一张图”、“一个平台”(如图4.3所示)。 + +整合土地、地质、矿产、海洋、测绘地理信息多套网络等基础设施资源,构建涵盖涉密网、业务网、互联网(电子政务外网)、应急通信网的多级互联的统一自然资源“一张网”。以第三次全国国土调查成果为基础,整合叠加各级各类国土空间规划成果,形成坐标一致、边界吻合、上下贯通的一张底图,并随年度土地变更调查、补充调查等工作进行及时更新,加强面向“一张图”的规划数据库建设。实现各类空间管控要素精准落地,形成覆盖全国、动态更新、权威统一的全国国土空间规划“一张图”,为统一国土空间用途管制、强化规划实施监督提供法定依据。基于平台,同步推动省、市、县各级国土空间规划“一张图”实施监督信息系统建设,为建立健全国土空间规划动态监测评估预警和实施监管机制提供信息化支撑。为国土空间规划编制和监督实施、国土空间用途管制、国土空间开发利用监测监管、国土空间生态修复等提供数据支撑和技术保障,有效提升国土空间治理能力现代化水平。 + +\textbf{图 }\textbf{4.3}\textbf{“一张网、一张图、一个平台”示意图} + +\section{国土空间规划编制基本内容} +\subsection{省级国土空间规划编制基本内容} +省级国土空间规划是落实国家发展战略要求、对省域空间发展保护格局进行统筹部署、指导市县等下层次国土空间规划的基本依据,具有战略性、综合性和协调性。纵向上,要落实上位规划的目标和战略,明确本级规划的底线和重点,提出对下位规划的控制与引导要求;横向上,要统筹省级有关部门的各类空间性规划(专项规划),明确各部门的空间使用和管理边界。 + +省级国土空间规划的编制主体为省级人民政府,由省级自然资源主管部门会同相关部门开展具体编制工作。按照政府主导、专家领衔、部门合作、公众参与、科学决策的方式进行规划。编制主要包括准备工作、专题研究、规划编制、规划多方案论证、规划公示、成果报批、规划公告等主要程序。结合《省级国土空间规划(试行)》以及《省级国土空间规划编制技术规程(征求意见稿)》,省级国土空间规划编制包含以下基本内容。 + +\subsubsection{1.规划总则} +(1)规划定位 + +省级国土空间规划是对全国国土空间规划纲要的落实和深化,是一定时期内省域国土空间保护、开发、利用、修复的政策和总纲,是编制省级相关专项规划、市县等下位国土空间规划的基本依据,在国土空间规划体系中发挥承上启下、 统筹协调作用,具有战略性、 协调性、 综合性和约束性。 + +规划任务 + +省级国土空间规划编制的主要任务主要包含5个方面(见表4.8)。 + +表4. 8省级国土空间规划编制主要任务 + +编制原则 + +省级国土空间规划主要遵循生态优先、绿色发展;以人民为中心、 高质量发展;区域协调、融合发展;因地制宜、特色发展;数据驱动、创新发展;共建共治、 共享发展这几条重要原则(见表4.9)。 + +表4. 9省级国土空间规划编制原则 + +(4)规划范围 + +行政管辖区内的全部国土空间,包括陆地国土和海洋国土。 + +(5)规划期限 + +规划期限一般为15年,并与上级规划衔接一致。 + +(6)编制依据 + +有关自然资源利用、 保护与管理, 国土空间规划的国家、 地方法律法规, 及相关政策文件。 + +\subsubsection{2.基础资料} +规划的基础资料主要包含基础资料、数据基础、重大战略、基础图件等内容(见表4.10)。 + +表4. 10省级国土空间规划基础资料内容 + +\subsubsection{3.基础研究} +通过资源环境承载能力和国土空间开发适宜性评价,分析区域资源环境禀赋特点,识别省域重要生态系统,明确生态功能极重要和极脆弱区域,提出农业生产、 城镇发展的承载规模和适宜空间。 + +从数量、质量、布局、结构、效率等方面,评估国土空间开发保护现状问题和风险挑战。结合城镇化发展、人口分布、经济发展、科技进步、气候变化等趋势,研判国土空间开发利用需求;在生态保护、资源利用、自然灾害、国土安全等方面识别可能面临的风险,并开展情景模拟分析。 + +各地可结合实际, 开展国土空间开发保护重大问题研究,如国土空间目标战略、 城镇化趋势、开发保护格局优化、人口产业与城乡融合发展、空间利用效率和品质提升、基础设施与资源要素配置、历史文化传承和景观风貌塑造、生态保护修复和国土综合整治、规划实施机制和政策保障等。要加强水平衡研究,综合考虑水资源利用现状和需求,明确水资源开发利用上限,提出水平衡措施。量水而行,以水定城、以水定地、以水定人、以水定产,形成与水资源、水环境、水生态、水安全相匹配的国土空间布局。沿海省份应开展海洋相关专题研究。 + +\subsubsection{4.技术路线图} +\textbf{图 }\textbf{4.}\textbf{4}\textbf{省级国土空间规划编制技术路线图} + +\subsubsection{5.规划编制} +(1) 战略目标 + +明确国土空间开发保护战略 + +落实国家重大战略,按照全国国土空间规划纲要确定的国土空间开发保护总体战略,立足省域资源环境禀赋和经济社会发展阶段,针对国土空间开发保护突出问题、风险挑战、未来趋势,明确省级国土空间发展的总体定位,制定省级国土空间开发保护战略。 + +提出国土空间开发保护目标 + +围绕“两个一百年 ” 奋斗目标,按照全国国土空间规划纲要确定的主要目标、管控方向、重大任务等,结合省域实际,以国土空间开发保护战略为引领,提出省级国土空间开发保护目标。落实全国国土空间规划纲要确定的省级国土空间规划指标要求,完善规划指标体系,明确省级国土空间开发保护的量化指标。 + +(2) 总体战略格局 + +确定国土空间总体战略格局 + +按照全国国土空间规划纲要确定的国土空间保护开发总体格局,立足省域自然地理本底,统筹生态、农业、历史文化等重要保护区域和廊道,形成省域国土空间保护格局;分析人、地、产、城、交通关系,确定城镇、产业开发的轴带和重要节点, 依托基础设施支撑体系,形成省域国土空间开发格局。 + +优化主体功能区战略格局 + +落实全国国土空间规划纲要确定的国家级主体功能区。依据国土空间开发适宜性评价结果,围绕战略目标和总体战略格局,结合地域特征和经济社会发展水平等,完善和细化省级主体功能区,形成主体功能约束有效、科学适度有序的总体格局。按照陆海统筹、保护优先原则,沿海县(市、区)要统筹确定一个主体功能区。 + +按照主体功能区定位划分政策单元,从投资、财政、产业、环境、生态、人口、土地等方面有针对性地提出规划实施政策措施,促进国土空间格局优化,保障规划目标的实现。 + +(3) 区域协调联动 + +省际协调发展 + +落实国家重大战略,按照全国国土空间规划纲要确定的区域协同要求,做好与相邻省份在生态保护、环境治理、产业发展、基础设施、公共服务等方面协商对接, 确保省际之间生态格局完整、环境协同共治、产业优势互补, 基础设施互联互通,公共服务共建共享。 + +省域重点地区协调指引 + +明确省域重点区域的引导方向和协调机制, 按照内涵式、绿色化、集约型的高质量发展要求,加强存量建设用地盘活力度, 提高经济发展优势区域的经济和人口承载能力。在此基础上,建设用地资源向中心城市和重点城市倾斜,使优势地区有更大发展空间。通过优化空间布局结构,促进解决资源枯竭型城市、传统工矿城市发展活力不足的问题。 + +发挥比较优势,增强不同地区在保障生态安全、粮食安全、边疆安全、文化安全、能源资源安全等方面的功能,明确主体功能定位和管控导向,促进各类要素合理流动和高效集聚,走合理分工、优化发展的路子。 + +开发保护布局 + +开发保护布局主要包括主体功能分区、生态空间、农业空间、城镇空间、网络化空间组织并统筹三条控制线等,具体内容(见表4.11)。 + +表4. 11开发保护布局内容 + +(5)资源要素保护与利用 + +自然资源 + +按照山水林田湖草系统保护要求,统筹耕地、 森林、 草原、 湿地、 河湖、 海洋、冰川、 荒漠、 矿产等各类自然资源的保护利用,确定自然资源利用上限和环境质量安全底线,提出水、土地、能源等重要自然资源供给总量、结构以及布局调整的重点和方向。 + +严格保护耕地和永久基本农田,对水土光热条件好的优质耕地,要优先划入永久基本农田。建立永久基本农田储备区制度。各项建设要尽量不占或少占耕地,特别是永久基本农田。 + +结合自然保护地体系建设, 保护林地、 草地、 湿地、冰川等重要自然资源,落实天然林、 防护林、储备林、 基本草原保护要求。 + +在落实国家确定的战略性矿产资源勘查、开发布局安排的基础上,明确省域内大中型能源矿产、金属矿产和非金属矿产的勘查开发区域,加强与三条控制线衔接,明确禁止、限制矿产资源勘查开采的空间。 + +沿海省份要明确海洋开发保护空间,提出海域、海岛与岸线资源保护利用目标。除国家重大项目外,全面禁止新增围填海,提出存量围填海的利用方向。明确无居民海岛保护利用的底线要求,加强特殊用途海岛保护。 + +以严控增量、盘活存量、提高流量为基本导向,确定水、土、能源等资源节约集约利用的目标、指标与实施策略。明确统筹地上地下空间,以及其他对省域发展产生重要影响的资源开发利用要求,提出建设用地结构优化、 布局调整的重点和时序安排。 + +历史文化和自然景观资源 + +贯彻国家文化遗产保护战略,系统建立包括国家文化公园、世界遗产、各级文物保护单位、历史文化名城名镇名村、传统村落、历史建筑、非物质文化遗产、未核定公布为文物保护单位的不可移动文物、地下文物埋藏区、水下文物保护区等在内的历史文化保护体系,编撰名录,梳理各种涉及保护和利用的空间管控要求,统一纳入省级国土空间规划。深入发掘和整合省域历史文化和自然景观资源,构建省域人文与自然景观网络,制定历史文化和自然景观区域整体保护措施,延续历史文脉,突出地方特色,做好保护、传承、利用。 + +(6)基础支撑体系 + +基础设施 + +落实国家重大交通、能源、水利、信息通信等基础设施项目,明确空间布局和规划要求。预测新增建设用地需求,明确省级重大基础设施项目、建设时序安排,确定重点项目表。 按照区域一体化要求,构建与国土空间开发保护格局相适应的基础设施支撑体系。按照高效集约的原则,统筹各类区域基础设施布局,线性基础设施尽量并线,明确重大基础设施廊道布局要求,减少对国土空间的分割和过度占用。 + +防灾减灾 + +考虑气候变化可能造成的环境风险,如沿海地区海平面上升、风暴潮等自然灾害,山地丘陵地区崩塌、滑坡、泥石流等地质灾害,提出防洪排涝、抗震、防潮、人防、地质灾害防治等防治标准和规划要求,明确应对措施。对国土空间开发不适宜区域,根据治理需求提出应对措施。合理布局各类防灾抗灾救灾通道,明确省级综合防灾减灾重大项目布局及时序安排,并纳入重点项目表。 + +(7)区域协调与规划传导 + +省际协调 + +做好与相邻省份在生态保护、环境治理、产业发展、基础设施、公共服务等方面协商对接,确保省际之间生态格局完整、环境协同共治、产业优势互补,基础设施互联互通,公共服务共建共享。 + +省域重点地区协调 + +加强省内流域和重要生态系统统筹,协调空间矛盾冲突,明确分区发展指引和管控要求,促进整体保护和修复。生态功能强的地区要得到有效保护,创造更多优质生态产品,建立健全纵向横向结合、多元化市场化的生态保护补偿机制。 + +明确省域重点区域的引导方向和协调机制,按照内涵式、绿色化、集约型的高质量发展要求,加强存量建设用地盘活力度,提高经济发展优势区域的经济和人口承载能力。在此基础上,建设用地资源向中心城市和重点城市倾斜,使优势地区有更大发展空间。通过优化空间布局结构,促进解决资源枯竭型城市、传统工矿城市发展活力不足的问题。 + +发挥比较优势,增强不同地区在保障生态安全、粮食安全、边疆安全、文化安全、能源资源安全等方面的功能,明确主体功能定位和管控导向,促进各类要素合理流动和高效集聚,走合理分工、优化发展的路子。 + +完善全民所有自然资源资产收益管理制度,健全自然资源资产收益分配机制,作为区域协调的重要手段。 + +直辖市要提出中心城区优化功能体系和空间布局的细化安排。 + +市县规划传导 + +以省域国土空间格局为指引,统筹市县国土空间开发保护需求,实现发展的持续性和空间的合理性。省级国土空间规划通过分区传导、底线管控、控制指标、名录管理、政策要求等方式,对市县级规划编制提出指导约束要求。省级国土空间规划要将上述要求分解到下级规划,下级规划不得突破。 + +专项规划指导约束 + +省级国土空间规划要综合统筹相关专项规划的空间需求,协调各专项规划空间安排。专项规划经依法批准后纳入同级国土空间基础信息平台,叠加到国土空间规划 “一张图 ” ,实施严格管理。 + +(8)生态修复与综合整治 + +落实国家确定的生态修复和国土综合整治的重点区域、重大工程。按照自然恢复为主、人工修复为辅的原则,以国土空间开发保护格局为依据,针对省域生态功能退化、生物多样性减少、用地效率低下、国土空间品质不高等问题区域,将生态单元作为修复和整治范围,按照保障安全、突出生态功能、兼顾景观功能的优先次序,结合山水林田湖草系统修复、国土综合整治、矿山生态修复和海洋生态修复等类型, 提出修复和整治目标、 重点区域、 重大工程。 + +\subsubsection{6.指导性要求} +各地可结合省域实际,按照世界眼光、国际标准、中国特色、高点定位的要求,深化相关工作(见表4.12)。 + +表4. 12省级国土空间规划编制指导性要求 + +\subsubsection{7.规划实施保障措施} +(1)健全配套政策机制 + +建立国土空间开发保护重大问题部门协同机制。结合主体功能区定位,落实和细化主体功能区配套政策。健全自然资源调查监测、资源资产管理、自然资源有偿使用、国土空间用途管制、生态保护修复等方面的规划实施保障机制及政策措施。 + +(2)完善国土空间基础信息平台建设 + +将现状数据及规划数据纳入省级国土空间基础信息平台,汇总市县基础数据和规划数据。 + +依托国土空间基础信息平台,构建国土空间规划 “一张图 ” ,推进 “智慧国土建设” ,推动实现互联互通的数据共享。 + +(3)建立规划监测评估预警制度 + +定期开展省级国土空间规划评估,评估规划主要目标、空间布局、重大工程等执行情况,以及各市县对省级国土空间规划的落实情况,对规划实施情况开展动态监测、 评估和预警。 建立 “一年一体检、五年一评估”的国土空间规划体检评估机制,强化规划全周期管理。 + +(4)近期安排 + +衔接国民经济和社会发展五年规划,提出省级国土空间规划的分期实施安排,并对规划近期做出统筹安排,包括明确重点任务、制定行动计划、编制重大项目清单、提出资金保障方案与实施支撑政策等。 + +\subsubsection{8.规划环境影响评价} +(1) 原则与依据 + +开展规划环境影响评价,依据双评价成果,预测规划方案实施后可能产生的环境影响评价, 提出拟采取的环境保护对策和措施。规划环境影响评价结合规划编制过程进行,遵循客观公正、充分协调、 可操作性原则。 + +(2)评价步骤 + +规划影响评价主要包括现状调查、评价指标、方案比较、预防措施、环境评价等步骤(见表4.13)。 + +表4. 13省级国土空间规划环境影响评价步骤 + +评价内容主要包括: + +环境影响评价主要包含分析环境与资源现状、分析规划目标与相关环境协调性、预测和评价环境影响、提出预防或减缓措施等重点内容(见表4.14)。 + +表4. 14省级国土空间规划环境影响评价重点内容 + +(4)评价方法 + +规划环境影响评价采用定性与定量相结合的方法。 可结合实际,选用核查表法、矩阵法、 生态服务价值法、 环境敏感性评价法和空间协调度分析法等方法。 + +\subsubsection{9.成果要求} +(1) 成果构成 + +规划成果包括: 规划文本、 规划图集、 编制说明、 专题成果集、 规划数据库和其他资料。 + +规划文本 + +规划文本一般应包含研究现状、目标定位、国土保护格局与分类管控引导、国土开发格局与区域发展、国土空间支撑体系建设、重点区域及重大工程、规划实施保障措施等主要内容(见表4.15)。 + +表4. 15省级国土空间规划文本内容 + +(3)国土空间规划图集 + +国土空间规划图集应包括规划基础图和规划成果图。 + +规划基础图包括: + +区域分析图、土地利用现状图、国土利用现状图、资源环境承载力评价图(包括单因子评价和综合承载能力评价图)、国土空间用地适宜性评价图(包括单因子评价和综合用地适宜性评价图)、国土经济密度分析图、城镇体系现状图、综合交通现状图、生态体系现状图等。 + +规划成果图包括: + +表达省域国土空间开发、保护的总体格局,包括国土空间总体格局图或国土空间开发格局图和国土空间保护格局图。图面要素应包括:城镇建设开发轴带与方向、城镇体系规模等级与职能定位、生态保护屏障和轴带、重要生态功能区布局、优质耕地和永久基本农田保护的基本格局等。 + +国土空间分区规划图。表达省域分级分类的生态空间、农业空间和城镇空间分布和配置。图面要素应包括:分级分类的生态空间分布情况,农业空间中优质耕地和粮食生产主要功能区以及其他一般农业地区分布情况,城镇空间集聚区域和分布格局,铁路、公路、河流等空间廊道分布情况等。 + +基础支撑体系规划图。表达支撑国土空间格局架构的铁路、公路等主要线性基础设施,交通枢纽、港口码头、机场等主要点状基础设施等。图面要素包括:规划和现状的铁路、高速公路、客货运铁路和轨道交通路线及站场、机场、港口、综合交通枢纽等基础设施空间位置。 + +国土综合整治布局图。表达各类型整治的重点区域和重点工程,包括国土综合整治布局图或生态环境整治重点区域和重大工程布局图、城乡建设用地整治重点区域和重大工程布局图、 高标准农田建设等土地整治重点区域和重大工程布局图。图面要素应包括:生态空间、农业空间、城镇空间分布,生态功能区治理、水土流失治理、土地退化、矿山环境治理、海岸带治理等以生态修复为主的整治空间布局,城镇闲置和低效建设用地开发、村庄建设用地整治、工矿废弃地复垦等以提高建设用地利用效率为主的整治空间布局,高标准农田建设等以促进农业生产为主的整治空间布局,以及其他需要标注的空间要素。 + +其他相关图件。 + +(4)国土空间规划说明 + +规划说明主要包含规划编制基础、规划协调衔接、规划目标定位、规划空间格局、国土空间划分、支撑体系、国土综合整治、规划方案论证及其他等内容(见表4.16)。 + +表4. 16省级国土空间规划说明主要内容 + +(5) 国土空间规划专题研究成果 + +根据规划主要内容要求,结合区域国土空间开发利用存在的问题和区域特点,开展国土空间规划专题研究形成的成果集。 + +(6)规划数据库 + +规划数据库是规划成果数据的电子形式,包括符合省(区、市)级国土空间总体规划数据库标准的规划图件的栅格数据和矢量数据、规划文档、规划表格、元数据等。规划数据库内容应与纸质的规划成果内容一致。 + +(7)其他资料 + +包括规划编制过程中形成的专题研究报告、工作报告、规划大纲、基础资料、会议纪要、部门意见、专家论证意见、 公众参与记录等。 + +\subsubsection{10.审查要求} +省级国土空间规划主要审查目标定位、主体功能区和重要边界、空间格局、重要设施布局、自然保护地与历史文化保护体系、乡村空间布局、保障措施和对下级规划、相关规划的指导约束要求等内容(见表4.17)。 + +表4. 17省级国土空间规划审查要求 + +\subsubsection{11.成果应用} +(1)国土空间规划经批准后, 对社会进行公告。 + +(2)对市县执行落实情况进行动态评估、 监测和预警。 + +(3)规划经批准后不得随意调整, 确需调整的,需遵照有关规定进行。 + +\subsubsection{12.省级国土空间规划案例} +以北方省份《XX省国土空间总体规划(2021—2035年)》(征求意见稿)作为省级国土空间总体规划的案例,XX省国土空间总体规划(2021—2035年)提纲(见表4.18)。 + +表4. 18《XX省国土空间总体规划(2021—2035年)》提纲 + +\subsection{市级国土空间规划编制基本内容} +市级国土空间总体规划,坚持以人民为中心、坚持底线思维、坚持一切从实际出发,做好陆海统筹、区域协同、城乡融合,发挥空间引导功能和承上启下的控制作用,注重保护和发展的底线划定及公共资源的配置安排,重点突出市域中心城市的空间规划,合理确定中心城市的规模、范围和结构。国土空间规划提出对下位规划和专项规划的指引;衔接国民经济和社会发展五年规划,制定近期行动计划;提出规划实施保障措施和机制,以“一张图”为支撑完善规划全生命周期管理。参考《市级国土空间总体规划编制指南(试行)》以及《市级国土空间总体规划数据库规范(试行)》、《市级国土空间总体规划制图规范(试行)》、《市级国土空间总体规划制图规范(试行)参考样图集》的主要内容,市级国土空间规划的重点内容主要包括以下方面: + +\subsubsection{1.规划总则} +(1)规划定位 + +市级总规是城市为实现“两个一百年”奋斗目标制定的空间发展蓝图和战略部署,是城市落实新发展理念,实施高效能空间治理,促进高质量发展和高品质生活的空间政策,是市域国土空间保护、开发、利用、修复和指导各类建设的行动纲领。市级总规要体现综合性、战略性、协调性、基础性和约束性,落实和深化上位规划要求,为编制下位国土空间总体规划、详细规划、相关专项规划和开展各类开发保护建设活动、实施国土空间用途管制提供基本依据。 + +(2)编制原则 + +贯彻新时代新要求 + +坚持以人民为中心的发展思想,从社会全面进步和人的全面发展出发,塑造高品质城乡人居环境,不断增强人民群众的获得感、幸福感、安全感;坚持底线思维,在生态文明思想和总体国家安全观指导下编制规划,将城市作为有机生命体,探索内涵式、集约型、绿色化的高质量发展新路子,推动形成绿色发展方式和生活方式,增强城市韧性和可持续发展的竞争力;坚持陆海统筹、区域协同、城乡融合,落实区域协调发展、新型城镇化、乡村振兴、可持续发展和主体功能区等国家战略;坚持一切从实际出发,立足本地自然和人文禀赋以及发展特征,发挥比较优势,因地制宜开展规划编制工作,突出地域特点、文化特色、时代特征。 + +突出公共政策属性 + +坚持体现市级总规的公共政策属性,坚持问题导向、目标导向、结果导向相结合,坚持以战略为引领,按照“问题—目标—战略—布局—机制”的逻辑,针对性地制定规划方案和实施政策措施,确保规划能用、管用、好用,更好发挥规划在空间治理能力现代化中的作用。 + +创新规划工作方法 + +坚持开门编规划,践行群众路线,将共谋、共建、共享、共治贯穿规划工作全过程,广泛凝聚社会智慧;强化城市设计、大数据、人工智能等技术手段对规划方案的辅助支撑作用,提升规划编制和管理水平。 + +(3)规划范围 + +规划范围包括市级行政辖区内全部陆域和管辖海域国土空间。 + +(4)规划期限 + +本轮规划目标年为2035年,近期至2025年,远景展望至2050年。 + +(5)规划层次 + +市级总规一般包括市域和中心城区两个层次。市域要统筹全域全要素规划管理,侧重国土空间开发保护的战略部署和总体格局;中心城区要细化土地使用和空间布局,侧重功能完善和结构优化;市域与中心城区要落实重要管控要素的系统传导和衔接。 + +\subsubsection{2.基础调研与研究} +(1)统一底图底数 + +各地应在第三次国土调查(以下简称“三调”)的基础上,按照国土空间用地用海分类、城区范围确定等有关标准规范,形成符合规定的国土空间利用现状和工作底数。统一采用2000国家大地坐标系和1985国家高程基准作为空间定位基础,形成坐标一致、边界吻合、上下贯通的工作底图。沿海地区要增加所辖海域海岛底图底数。 + +各地应根据需要开展补充调查,并充分应用基础测绘和地理国情监测成果,收集自然资源、生态环境、经济产业、人口社会、历史文化、基础设施、城乡发展、区域协调、灾害风险、水土污染、海洋空间保护和利用等相关资料,以及相关规划成果、土地利用审批、永久基本农田等数据,加强基础数据分析。 + +(2)分析自然地理格局 + +研究当地气候和地形地貌条件、水土等自然资源禀赋、生态环境容量等空间本底特征,分析自然地理格局、人口分布与区域经济布局的空间匹配关系,开展资源环境承载能力和国土空间开发适宜性评价(以下简称“双评价”),明确农业生产、城镇建设的最大合理规模和适宜空间,提出国土空间优化导向。 + +(3)重视规划实施和灾害风险评估 + +开展现行城市总体规划、土地利用总体规划、市级海洋功能区划等空间类规划及相关政策实施的评估,评估自然生态和历史文化保护、基础设施和公共服务设施、节约集约用地等规划实施情况;结合自然地理本底特征和“双评价”结果,针对不确定性和不稳定性,分析区域发展和城镇化趋势、人口与社会需求变化、科技进步和产业发展、气候变化等因素,系统梳理国土空间开发保护中存在的问题,开展灾害和风险评估。 + +(4)加强重大专题研究 + +重大专题主要包含人口专题、气候专题、区域专题、通信专题、公共服务专题、生态专题、历史文化专题、城市专题、政策专题等(见表4.19)。 + +表4. 19市级国土空间总体规划重大专题内容 + +(5)开展总体城市设计研究 + +将城市设计贯穿规划全过程。基于人与自然和谐共生的原则,研究市域生产、生活、生态的总体功能关系,优化开发保护的约束性条件和管控边界,协调城镇乡村与山水林田湖草海等自然环境的布局关系,塑造具有特色和比较优势的市域国土空间总体格局和空间形态。基于本地自然和人文禀赋,加强自然与历史文化遗产保护,研究城市开敞空间系统、重要廊道和节点、天际轮廓线等空间秩序控制引导方案,提高国土空间的舒适性、艺术性,提升国土空间品质和价值。 + +\subsubsection{3.规划编制} +(1)落实主体功能定位,明确空间发展目标战略 + +强化总体规划的战略引领和底线管控作用,促进国土空间发展更加绿色安全、健康宜居、开放协调、富有活力并各具特色。 + +围绕“两个一百年”奋斗目标和上位规划部署,结合本地发展阶段和特点,并针对存在问题、风险挑战和未来趋势,确定城市性质和国土空间发展目标,提出国土空间开发保护战略。 + +落实上位规划的约束性指标要求,结合经济社会发展要求,确定国土空间开发保护的量化指标。规划指标体系(见表4.20)。 + +表4. 20市级国土空间总体规划指标体系 + +(2)优化空间总体格局,促进区域协调、城乡融合发展 + +落实国家和省的区域发展战略、主体功能区战略,以自然地理格局为基础,形成开放式、网络化、集约型、生态化的国土空间总体格局(见表4.21)。 + +表4. 21市级国土空间总体规划优化空间内容 + +(3)强化资源环境底线约束,推进生态优先、绿色发展 + +基于资源环境承载能力和国土安全要求,明确重要资源利用上限,划定各类控制线,作为开发建设不可逾越的红线。 + +落实上位国土空间规划确定的生态保护红线、永久基本农田、城镇开发边界(以下简称“三条控制线”)等划定要求,统筹划定“三条控制线”。各地可结合地方实际,提出历史文化、矿产资源等其他需要保护和控制的底线要求。 + +制定水资源供需平衡方案,明确水资源利用上限。按照以水定城、以水定地、以水定人、以水定产原则,优化生产、生活、生态用水结构和空间布局,重视雨水和再生水等资源利用,建设节水型城市。 + +制定能源供需平衡方案,落实碳排放减量任务,控制能源消耗总量。优化能源结构,推动风、光、水、地热等本地清洁能源利用,提高可再生能源比例,鼓励分布式、网络化能源布局,建设低碳城市。 + +基于地域自然环境条件,严格保护低洼地等调蓄空间,明确海洋、河湖水系、湿地、蓄滞洪区和水源涵养地的保护范围,确定海岸线、河湖自然岸线的保护措施。明确天然林、生态公益林、基本草原等为主体的林地、草地保护区域。 + +(4)优化空间结构,提升连通性,促进节约集约、高质量发展 + +依据国土空间开发保护总体格局,注重城乡融合、产城融合,优化城市功能布局和空间结构,改善空间连通性和可达性,促进形成高质量发展的新增长点。 + +按照主体功能定位和空间治理要求,优化城市功能布局和空间结构,划分规划分区(见表4.22)。其中,中心城区和沿海城市的海洋发展区应细化至二级规划分区。 + +表4. 22规划分区 + +落实上位规划指标,以盘活存量为重点明确用途结构优化方向,确定全域主要用地用海的规模和比例。提出城乡建设用地集约利用的目标和措施。优先保障住房和各类重要公共服务设施用地,以及涉及军事、外事、殡葬等特殊用地。 + +确定中心城区各类建设用地总量和结构。提出不同规划分区的用地结构优化导向,鼓励土地混合使用。 + +优化建设用地结构和布局,推动人、城、产、交通一体化发展,促进产业园区与城市服务功能的融合,保障发展实体经济的产业空间,在确保环境安全的基础上引导发展功能复合的产业社区,促进产城融合、职住平衡。 + +提高空间连通性和交通可达性,明确综合交通系统发展目标,促进城市高效、安全、低能耗运行,优化综合交通网络,完善物流运输系统布局,促进新业态发展,增强区域、市域、城乡之间的交通服务能力。 + +坚持公交引导城市发展,提出与城市功能布局相融合的公共交通体系与设施布局。优化公交枢纽和场站(含轨道交通)布局与集约用地要求,提高站点覆盖率,鼓励站点周边地区土地混合使用,引导形成综合服务节点,服务于人的需求。 + +(5)完善公共空间和公共服务功能,营造健康、舒适、便利的人居环境 + +结合不同尺度的城乡生活圈,优化居住和公共服务设施用地布局,完善开敞空间和慢行网络,提高人居环境品质。 + +基于常住人口的总量和结构,提出分区分级公共服务中心体系布局和标准,针对实际服务管理人口特征和需求,完善服务功能,改善服务的便利性。确定中心城区公共服务设施用地总量和结构比例。 + +优化居住用地结构和布局,改善职住关系,引导政策性住房优先布局在交通和就业便利地区,避免形成单一功能的大型居住区。确定中心城区人均居住用地面积。严控高层高密度住宅。 + +完善社区生活圈,针对人口老龄化、少子化趋势和社区功能复合化需求,重点提出医疗、康养、教育、文体、社区商业等服务设施和公共开敞空间的配置标准和布局要求,建设全年龄友好健康城市,以社区生活圈为单元补齐公共服务短板。 + +按照“小街区、密路网”的理念,优化中心城区城市道路网结构和布局,提高中心城区道路网密度。 + +构建系统安全的慢行系统,结合街道和蓝绿网络,构建连通城市和城郊的绿道系统,提出城市中心城区覆盖地上地下、室内户外的慢行系统规划要求,建设步行友好城市。 + +结合市域生态网络,完善蓝绿开敞空间系统,为市民创造更多接触大自然的机会。确定结构性绿地、城乡绿道、市级公园等重要绿地以及重要水体的控制范围,划定中心城区的绿线、蓝线,并提出控制要求。 + +在中心城区提出通风廊道、隔离绿地和绿道系统等布局和控制要求。确定中心城区绿地与开敞空间的总量、人均用地面积和覆盖率指标,并着重提出包括社区公园、口袋公园在内的各类绿地均衡布局的规划要求。 + +(6)保护自然与历史文化,塑造具有地域特色的城乡风貌 + +加强自然和历史文化资源的保护,运用城市设计方法,优化空间形态,凸显本地特色优势。 + +挖掘本地历史文化资源,梳理市域历史文化遗产保护名录,明确和整合各级文物保护单位、历史文化名城名镇名村、历史城区、历史文化街区、传统村落、历史建筑等历史文化遗存的保护范围,统筹划定包括城市紫线在内的各类历史文化保护线。保护历史性城市景观和文化景观,针对历史文化和自然景观资源富集、空间分布集中的地域和廊道,明确整体保护和促进活化利用的空间要求。 + +提出全域山水人文格局的空间形态引导和管控原则,对滨水地区(河口、海岸)、山麓地区等城市特色景观地区提出有针对性的管控要求。 + +明确空间形态重点管控地区,提出开发强度分区和容积率、密度等控制指标,以及高度、风貌、天际线等空间形态控制要求。明确有景观价值的制高点、山水轴线、视线通廊等,严格控制新建超高层建筑。 + +对乡村地区分类分区提出特色保护、风貌塑造和高度控制等空间形态管控要求,发挥田野的生态、景观和空间间隔作用,营造体现地域特色的田园风光。 + +(7)完善基础设施体系,增强城市安全韧性 + +统筹存量和增量、地上和地下、传统和新型基础设施系统布局,构建集约高效、智能绿色、安全可靠的现代化基础设施体系,提高城市综合承载能力,建设韧性城市。 + +以协同融合、安全韧性为导向,结合空间格局优化和智慧城市建设,优化形成各类基础设施一体化、网络化、复合化、绿色化、智能化布局。提出市域重要交通廊道和高压输电干线、天然气高压干线等能源通道空间布局,以及市域重大水利工程布局安排。提出中心城区交通、能源、水系统、信息、物流、固体废弃物处理等基础设施的规模和网络化布局要求,明确廊道控制要求,鼓励新建城区提出综合管廊布局方案。 + +基于灾害风险评估,确定主要灾害类型的防灾减灾目标和设防标准,划示灾害风险区。明确防洪(潮)、抗震、消防、人防、防疫等各类重大防灾设施标准、布局要求与防灾减灾措施,适度提高生命线工程的冗余度。针对气候变化影响,结合城市自然地理特征,优化防洪排涝通道和蓄滞洪区,划定洪涝风险控制线,修复自然生态系统,因地制宜推进海绵城市建设,增加城镇建设用地中的渗透性表面。沿海城市应强化因气候变化造成海平面上升的灾害应对措施。 + +以社区生活圈为基础构建城市健康安全单元,完善应急空间网络。结合公园、绿地、广场等开敞空间和体育场馆等公共设施,提出网络化、分布式的应急避难场所、疏散通道的布局要求。 + +预留一定应急用地和大型危险品存储用地,科学划定安全防护和缓冲空间。 + +确定重要交通、能源、市政、防灾等基础设施用地控制范围,划定中心城区重要基础设施的黄线,与生态保护红线、永久基本农田等控制线相协调。在提出控制要求的同时保留一定弹性,为新型基础设施建设预留发展空间。 + +(8)推进国土整治修复与城市更新,提升空间综合价值 + +针对空间治理问题,分类开展整治、修复与更新,有序盘活存量,提高国土空间的品质和价值。 + +生态修复应坚持山水林田湖草生命共同体的理念,按照陆海统筹的原则,针对生态功能退化、生物多样性减少、水土污染、洪涝灾害、地质灾害等问题区域,明确生态系统修复的目标、重点区域和重大工程,维护生态系统,改善生态功能。 + +土地整治应以乡村振兴为目标,结合村庄布局优化要求,推进乡村地区田水路林村全要素综合整治,针对土壤退化等问题,提出农用地综合整治、低效建设用地整治等综合整治目标、重点区域和重大工程,建设美丽乡村。 + +城市更新应根据城市发展阶段与目标、用地潜力和空间布局特点,明确实施城市有机更新的重点区域,根据需要确定城市更新空间单元,结合城乡生活圈构建,注重补短板、强弱项,优化功能布局和开发强度,传承历史文化,提升城市品质和活力,避免大拆大建,保障公共利益。 + +(9)建立规划实施保障机制,确保一张蓝图干到底 + +保障规划有效实施,提出对下位规划和专项规划的指引;衔接国民经济和社会发展五年规划,制定近期行动计划;提出规划实施保障措施和机制,以“一张图”为支撑完善规划全生命周期管理(见表4.23)。 + +表4. 23市级国土空间规划一张图建设重点内容 + +\subsubsection{4.规划强制性内容} +市级总规中涉及的安全底线、空间结构等方面内容,应作为规划强制性内容,并在图纸上有准确标明或在文本上有明确、规范地表述,同时提出相应的管理措施。 + +市级总规中强制性内容应包括: + +(1)约束性指标落实及分解情况,如生态保护红线面积、用水总量、永久基本农田保护面积等; + +(2)生态屏障、生态廊道和生态系统保护格局,自然保护地体系; + +(3)生态保护红线、永久基本农田和城镇开发边界三条控制线; + +(4)涵盖各类历史文化遗存的历史文化保护体系,历史文化保护线及空间管控要求; + +(5)中心城区范围内结构性绿地、水体等开敞空间的控制范围和均衡分布要求; + +(6)城乡公共服务设施配置标准,城镇政策性住房和教育、卫生、养老、文化体育等城乡公共服务设施布局原则和标准; + +(7)重大交通枢纽、重要线性工程网络、城市安全与综合防灾体系、地下空间、邻避设施等设施布局。 + +\subsubsection{5.公众参与和多方协同} +贯彻落实“人民城市人民建,人民城市为人民”理念,坚持开门编规划,建立全流程、多渠道的公众参与和社会协同机制。在规划编制阶段,广泛调研社会各界意见和需求,深入了解人民群众所需所急所盼;充分调动和整合各方力量,鼓励各类相关机构参与规划编制;健全专家咨询机制,组建包括各相关领域专家的综合性咨询团队;完善部门协作机制,共同推进规划编制工作。在方案论证阶段,要形成通俗易懂可视化的中间成果,充分征求有关部门、社会各界意见。规划获批后,应在符合国家保密管理和地图管理等有关规定的基础上及时公开,并接受社会公众监督。 + +\subsubsection{6.成果要求} +规划成果包括规划文本、附表、图件、说明、专题研究报告、国土空间规划“一张图”相关成果等。 + +(1)规划文本 + +规划文本是具有法律效力的规划文件,由内容清晰、简洁明了的控制性条文所构成,全面反映了国土空间规划的编制内容。市级国土空间规划文本的内容可以包括:国土空间现状分析、规划总则、国土空间发展战略、国土空间管控体系、规划实施措施、附表等基本内容(见表4.24)。 + +表4. 24市级国土空间规划规划文本重点内容 + +(2)图件 + +国土空间规划图集主要包括现状图集和规划图集。现状图集主要包括区位关系图、土地用途现状图、生态资源现状分布图、综合交通体系现状图、国土空间开发适宜性评价图、公共设施分布现状图等:规划图集主要包括国土空间结构规划图、国土空间分区规划图、国土空间控制线规划图、土地用途规划图、国土整治与生态保护修复布局规划图、城镇体系(镇村体系)规划图、综合交通体系规划图、重大设施布局规划图、综合防灾体系规划图、近期重大项目布局规划图等。根据各个规划地区的具体情况,还可以增加相应图纸,以便能更清晰完整地表达规划编制成果(见表4.25)。 + +表4. 25市级国土空间总体规划图件目录 + +注:根据需要,可将若干张图件合并表达,也可以分为多张图件表达。 + +(3)其他规划成果 + +同其他规划的说明一样,国土空间规划的说明也是对规划成果的具体阐释和分析,主要阐述规划决策的编制基础、技术分析和编制内容,是规划实施中配合规划文本和规划图集使用的重要参考。 + +基础研究报告主要包括现行规划实施评估、资源环境承载力评价、国土空间开发适宜性评价、国土空间风险评估等内容。根据规划需要和规划区的特殊情况,也可以开展针对相关重大问题的研究,如国土空间发展战略研究、产业布局研究、土地资源保护利用研究、水资源开发与配置研究、生态保护修复研究、区域协调发展研究、乡村振兴研究、城乡一体化研究等。 + +规划数据库是国土空间规划成果数据的集成。其是国土空间信息平台的支撑内容,也是连接空间规划成果与信息平台的纽带。规划数据库的格式一般应为标准的矢量数据格式,坐标应采用2000国家大地坐标系。 + +其他材料主要包括规划编制过程中产生的一些相关材料,主要包括各个部门对规划的意见、有关规划编制的会议纪要、规划论证评审意见、公众参与记录和相关建议、政府审查审批文件等。 + +上述规划文本、图集、说明、基础研究报告和规划数据库应是国土空间规划编制成果的基本构成。但由于规划地区的特殊性,在具体实践中,将会增加相应的编制成果,由此更清晰完整地表达规划编制内容。同时应指出的是,国家统一的国土空间规划编制内容和成果要求标准尚未出台,本节构建的编制成果内容可供相关部门和读者参考。 + +\subsubsection{7.审查要求} +在方案论证阶段和成果报批之前,审查机关应组织专家参与论证和进行审查。审查要件包括市级总规相关成果。报国务院审批城市的审查要点依据《自然资源部关于全面开展国土空间规划工作的通知》(自然资发〔2019〕87号),其他城市的审查要点各省(区)可结合实际参照执行(见表4.26)。 + +表4. 26市级国土空间规划审查要求 + +\subsubsection{8.市级国土空间规划案例} +以典型的北方城市《XX市国土空间总体规划(2021—2035年)》作为市级国土空间总体规划的案例。XX市国土空间总体规划(2021—2035年)提纲(见表4.27)。 + +表4. 27《XX市国土空间总体规划(2021—2035年)》提纲 + +\subsection{县级国土空间规划编制基本内容} +县级国土空间总体规划是在县(市、区)行政辖区范围内对国土空间保护、开发、利用、修复的总体安排和综合部署,是对省级、市级国土空间总体规划和相关专项规划的细化落实,侧重实施性和操作性,是编制乡镇(片区)国土空间总体规划、相关专项规划、详细规划以及实施国土空间规划用途分区管制的重要依据。县级国土空间规划除了落实上位规划的战略要求和约束性指标以外,要重点突出空间结构布局,突出生态空间修复和全域整治,突出乡村发展和活力激发,突出产业对接和联动开发。参照《黑龙江省县级国土空间总体规划编制指南(试行)》县级国土空间规划的重点内容主要包括以下方面: + +\subsubsection{1.规划总则} +(1)编制原则 + +生态优先,推动绿色发展 + +坚持底线思维,在生态文明思想和总体国家安全观指导下编制规划,将县域作为有机生命体,探索内涵式、集约型、绿色化的高质量发展新路子,推动形成绿色发展方式和生活方式,增强城市韧性和可持续发展的竞争力。 + +问题导向,破解发展难题 + +以资源环境承载能力和国土空间开发适宜性评价(以下简称“双评价”)、空间类规划评估和灾害风险评估(以下简称“双评估”)为基础,着力解决国土空间开发利用保护修复中存在的核心问题,因地制宜制定规划方案和实施措施,充分发挥县级总规在空间治理中的基础性公共政策作用,确保规划能用、管用、好用。 + +目标导向,确保规划落实 + +尊重区域发展规律,把握区域发展特征和自然生态本底条件,合理确定规划目标,明确约束性指标和刚性管控要求,提出分级分类的用途管制措施,将上位规划、专项规划的约束性指标和控制要求落实到国土空间总体规划“一张图”,确保国土空间总体规划科学性、协调性,具有可操作性。 + +三线管控,严守安全底线 + +落实“三条控制线”管理要求,按照生态功能划定生态保护红线,按照保质保量要求划定永久基本农田,按照集约适度、绿色发展要求划定城镇开发边界,真正让“三条控制线”成为不可逾越的红线,严守生态安全、粮食安全、国土安全底线。 + +上下联动,强化公众参与 + +坚持开门编规划。按照党委领导、政府组织、部门协同、公众参与的工作组织方式,发挥国土空间规划委员会(以下简称为“规委会”)的作用,健全专家咨询与公众参与等机制,加强规划上下联动、部门协同,采用多种方式和手段,广纳民意、广集民智、广聚共识,将规划编制过程转变为全社会参与共建共治共享的过程。 + +(2)规划范围 + +规划范围包括县级行政辖区内全部国土空间。 + +(3)规划期限 + +规划期限为2021年至2035年,基期年为2020年,规划目标年为2035年,近期至2025年,远景展望至2050年。 + +(4)规划层次 + +县级总规包括县域和中心城镇两个规划层次。 + +县域应突出全域统筹,整体谋划县域国土空间格局优化方向,统筹划定生态保护红线、永久基本农田和城镇开发边界等控制线,促进资源保护利用与生态修复,合理配置县域空间要素,明确城镇体系布局,引导乡村建设与发展,提出对乡镇规划的控制要求。县域应达到二级规划分区深度。 + +中心城镇应突出对城镇空间重点内容的细化安排,侧重底线管控和功能布局细化,合理确定功能结构、用地布局、重大基础设施布局、明确城镇开发强度分区和强度指引,对空间形态提出管控要求。中心城镇应达到《国土空间调查、规划、用途管制用地用海分类指南》(试行)的用地二级类深度,部分可细分至三级类。 + +(5)编制主体 + +县级人民政府负责本级国土空间总体规划编制工作,县级自然资源主管部门会同有关部门承担具体编制工作。市辖区需单独编制区级国土空间总体规划的,编制主体由市级人民政府确定,同级自然资源主管部门承担具体编制工作。 + +(6)编制程序 + +主要包括准备工作、基础调研、规划编制、咨询论证、审查审议、规划公告七个阶段,社会参与贯穿规划编制的全过程。 + +\subsubsection{2.基础调研与研究} +(1)基础调研 + +县级自然资源主管部门统筹组织,规划编制技术单位全程参与,分类分组开展基础调研工作。以座谈走访或问卷调研为主要方式,对各县级部门、乡镇政府、相关专家学者及社会公众等开展调研,深入了解当地发展实际与发展诉求;针对重点研究区域,进行现场实地踏勘。 + +(2)底数底图 + +以第三次全国国土调查成果为基础,综合考虑规划基期用地实际和国土空间规划管理需要,形成基期现状用地底数、底图,也可结合实际,对城镇开发边界内用地进行细化调查。统一采用2000国家大地坐标系和1985国家高程基准作为空间定位基础,形成坐标一致、边界吻合、上下贯通的工作底图。 + +(3)基础分析 + +县级总规可直接使用市级“双评价”结果,山地、丘陵等地形地貌复杂的县(市)或其他有必要深化研究的县(市),可在市级评价基础上进一步细分评价单元、提高评价精度,因地制宜选择评价指标,有重点地深化、明确评价结论,为制定国土空间开发保护战略和规划方案提供技术支撑。 + +开展现行城市总体规划、土地利用总体规划等空间类规划及相关政策实施的评估,评估自然生态和历史文化保护、基础设施和公共服务设施、节约集约用地等规划的实施情况;结合自然地理本底特征和“双评价”结果,针对不确定性和不稳定性,分析区域发展和城镇化趋势、人口与社会需求变化、科技进步和产业发展、气候变化等因素,系统梳理国土空间开发保护中存在的问题,开展灾害和风险评估。 + +(4)专题研究 + +结合地方特点和规划编制需求,在“双评价”、“双评估”的基础上对国土空间开发保护战略、耕地保护、城市支撑保障体系与安全韧性、历史文化保护与传承、建设用地节约集约利用和生态修复的空间策略等方向重大问题开展专题研究,为规划编制提供方向性、基础性支撑。 + +\subsubsection{3.规划编制} +一是结合主体功能区定位和规划编制需求,着重开展相应的专题研究工作。二是以专题研究结论为基础,整理基础数据和资料,分析自然地理特征,梳理县域空间保护开发利用现状、发展需求、规划设想等情况,明晰上位规划约束指标和控制性要求,科学确定区域发展战略和定位;划定落实“三条控制线”、进行规划分区管控;对全域资源保护、开发、利用、整治、修复提出规划方案,对交通、公共设施、基础设施、历史文化保护与城乡风貌塑造等方面提出规划设想;划定中心城镇规划范围,谋划中心城镇空间布局;拟定规划期间实施的重大建设与治理工程,提出规划实施保障措施。 + +(1)发展定位 + +落实国家、省、市重大战略部署,以上位国土空间规划为指导,结合本地自然资源禀赋和经济社会发展阶段,综合考虑主体功能定位,确定总体发展定位和城市性质,突出城市特色,并提出国土空间开发保护战略。 + +(2)发展目标 + +围绕“两个一百年”奋斗目标,落实上位国土空间规划的约束性指标要求,提出2025年、2035年国土空间开发保护目标,建立可考核的目标指标体系(见表4.28),明确指标属性。 + +表4. 28县级国土空间总体规划指标体系表 + +注:各地可结合本地实际,确定具体指标,湿地面积、自然和文化遗产等视地方实际安排,也可在上述指标基础上,安排本地特色指标。 + +(3)空间格局优化 + +落实国家、省、市的区域发展战略、主体功能区战略,以自然地理格局为基础,形成开放式、网络化、集约型、生态化的国土空间总体格局(见表4.29)。 + +表4. 29县级国土空间总体规划空间格局优化内容 + +(4)功能结构优化 + +落实市级总规控制指标,建立指标体系,明确主要约束性和预期性指标。依次考虑满足生态保护、农业保障及其他土地需求,严格控制各类建设占用生态用地和长期稳定利用耕地,提出县域范围内国土空间结构调整优化的重点、方向和时序安排,编制功能结构调整表。 + +(5)规划分区 + +以国土空间保护开发总体格局为基础,结合地域特征和经济社会发展水平,按照全域全覆盖、不交叉、不重叠的原则,在市域国土空间总体规划基本分区的基础上,将县域划分为生态保护区、生态控制区、农田保护区、城镇发展区、乡村发展区、矿产能源发展区等6类规划一级分区。在城镇发展区、乡村发展区分别细分为14类规划二级分区。如县域内存在未列出的特殊政策管制要求,可在规划分区基础上,依据国家相关法律法规及特色产业、特殊用途、历史文化保护等特别需要,划定编制详细规划的特殊单元和边界。 + +按照划定的规划分区,确定各规划分区国土空间功能导向和主要用途方向,制定用途准入原则和管控要求。 + +资源保护利用 + +资源保护利用主要保护耕地资源、自然保护地、水资源、湿地生态系统、森林资源、草地资源、矿产资源、风景名胜区、建设用地等方面(见表4.30)。 + +表4. 30县级国土空间总体规划资源保护与利用内容 + +(7)城乡融合发展 + +城镇体系规划 + +围绕新型城镇化、乡村振兴、产城融合,综合考虑经济社会、产业发展、人口分布等因素,依据上位规划明确的建设用地规模,确定城镇体系结构、城镇职能结构和规模等级。 + +村庄分类与布局优化 + +根据村庄的发展现状、区位条件、资源禀赋等,按照集聚提升、城郊融合、特色保护、搬迁撤并及边境巩固等类型,统筹确定村庄分类和布局。 + +产业布局及园区规划 + +围绕区域产业发展导向和全省产业布局,对接国民经济五年发展规划,基于现状产业基础与发展条件,确定主导产业发展方向,合理布局产业空间,提出产业用地规模控制目标,明确产业园区相关管控要求。 + +乡村振兴 + +引导乡村二三产业向城镇及产业园区适度集聚,以特色村镇为载体,根据资源禀赋,充分发挥比较优势,突出特色。以自然环境秀丽为特色的村镇,应充分利用山水风光,保持原真性、生态性,发展旅游、运动、康养等产业;以丰富历史文化为特色的村镇,应延续历史文脉、挖掘内涵,做强文化旅游、民族民俗体验、创意策划等产业;以主导产业为特色的村镇,充分发挥主导产业特色,做强、做大主导产业,延长产业链,形成产业集群。 + +全域旅游发展 + +深入挖掘县域历史文化、地域特色文化、民族民俗文化等,规划旅游发展的主题与主线,策划文化旅游产品,大力推进“旅游+”,促进产业融合、产城融合、文旅融合。依托风景名胜区、历史文化名城名镇名村、特色小镇、传统村落,探索名胜名城名镇名村“四名一体”全域旅游发展模式,优先发展冰雪旅游、生态旅游、康养旅游等旅游产品。优化提升乡村旅游、文化遗产旅游、边境旅游。在空间设计上,将旅游开发与城市公共空间优化相结合,保障重点区域的旅游设施支撑。 + +(8)完善支撑保障体系 + +突出全域支撑要素智能化、网络化、现代化,加快补齐短板,为县域发展提供强力支撑。 + +县域综合交通规划 + +落实上位规划及相关专项规划交通网络布局,根据全域多元交通需求,以提升区域衔接与城乡可达性为目的,因地制宜制定综合交通体系发展目标与策略。落实确定公路、铁路、航运、轨道交通等重要交通走廊和重要交通枢纽设施的布局和控制要求,预控县级以上交通枢纽和交通廊道的线型走向以及大型交通、物流设施用地,并积极对接县域国省道、高速等对外交通,科学布局综合交通网络,提升县域交通连通性与可达性。坚持公共交通引导城乡交通网络建设,优化公交枢纽和站点布局,提高站点覆盖率,构建智慧交通。 + +公共服务设施提升 + +基于常住人口的总量和结构,考虑实际服务管理人口规模和特征,明确“中心城镇-重点镇-一般镇”分级公共服务中心体系,提出不同空间层级教育设施(含学前教育、义务教育、特殊教育)、行政管理与服务设施、公共文化设施、体育设施、医疗卫生设施、养老设施、社会福利设施等公共服务设施的差异化配置要求,实现城乡公共服务设施均等化配置。 + +市政基础设施完善 + +确定各类市政基础设施的建设目标,在落实上位规划及相关专项规划要求基础上,统筹规划城乡全域的供水、供电、冷链物流、信息基础设施、广播电视、垃圾污水等基础设施的建设,确定各类设施建设标准、规模和重大设施布局,科学谋划5G基站、智能交通基础设施、智慧能源基础设施等新型基础设施布局与空间预留。预控县级以上水利、能源等区域性市政基础设施廊道,推进基础设施向农村延伸,协调安排县级垃圾焚烧厂、墓地等邻避设施布局,鼓励重大区域基础设施共建共享。 + +安全韧性与综合防灾 + +针对县域主要灾害风险类型及存在的主要安全防灾问题,做好综合灾害风险评估。明确综合防灾减灾目标、设防标准和防灾分区,提出主要防灾基础设施和应急避难场所布局的原则和要求,制定防洪排涝、消防、人防、抗震、地质灾害防治等规划措施,明确危险品存储设施用地布局方案及安全管控要求,提高城市安全保障水平和韧性应急能力。 + +(9)历史文化保护与利用 + +梳理县域内历史文化名城、名镇、名村、传统村落、历史文化街区、历史建筑、文物保护单位和非物质文化遗产,提出历史文化保护体系和保护格局,确定保护名录。明确各类、各级历史文化遗产的保护范围和要求,提出整体保护各类遗产及其依存的历史环境和人文环境的要求和措施,提出历史文化资源活化利用的目标要求和策略。 + +依托历史文化名城名镇名村、特色景观旅游名镇、传统村落,深入挖掘历史文化、地域特色文化、民族民俗文化、传统农耕文化等,建设旅游综合体、风情小镇、旅游小镇、休闲康养小镇及美丽宜居村庄等。 + +(10)城乡风貌引导 + +全域风貌管控 + +在县域层面运用城市设计方法,强化生态、农业和城镇空间的全域全要素整体统筹,优化县域的整体空间秩序(见表4.31)。 + +表4. 31县级国土空间总体规划全域风貌管控内容 + +乡村风貌塑造 + +在乡村层面应体现尊重自然、传承文化、以人为本的理念,保护乡村自然本底,营造富有地域特色的“田水路林村”景观格局,传承空间基因,延续当地空间特色,运用本土化材料,展现独特的村庄建设风貌,忌简单套用城市空间的设计手法。 + +(11)规划约束传导 + +对乡镇规划的传导指引 + +分别明确全域范围内单独编制或合并编制国土空间总体规划的乡镇。 + +引导乡镇规划落实县级总规确定的规划目标、规划分区、重要控制线、城镇发展定位、要素配置等规划内容,制定乡镇主要约束性指标。各地可结合本地特点和地方实际,在必选指标的基础上补充其他预期性规划指标。 + +明确强制性要求:包括县域国土空间总体规划分区和用途管制规则、三条控制线、县级以上重大交通及公共服务设施、历史文化保护范围与控制要求。制定引导性内容:包含乡镇定位目标、乡镇空间优化、品质提升要求,以及一般公共服务设施和基础设施布局等内容。 + +对相关专项规划的指导约束 + +相关专项规划应在同级国土空间总体规划的指导约束下编制,落实相关约束性指标,不得违背县级总规的强制性内容,并与国土空间总体规划“一张图”核对。经依法批准后纳入县级国土空间基础信息平台,叠加到国土空间总体规划“一张图”。 + +对详细规划的传导约束 + +城镇开发边界内:对不同详细规划编制单元主导功能提出差异化引导要求,明确需要向各编制单元传导的功能定位、核心指标、管控边界和要求。其中建设用地规模、开发强度、道路网密度等应作为约束性指标向下传递,城市黄线、蓝线、绿线、紫线以及城市快速路和主次干路的走向、红线宽度应作为刚性要素层层落实。产业园区按照规划范围划定详细规划编制单元。在城镇开发边界内的建设,实行“详细规划+规划许可”的管制方式。 + +城镇开发边界外:在城镇开发边界外的建设,按照主导用途分区,实行“详细规划+规划许可”和“约束指标+分区准入”的管制方式。明确重要控制指标、要素配置等约束准入条件。 + +(12)中心城镇规划 + +范围划定 + +综合考虑地形地貌、自然生态、灾害风险、区域协同、重大设施廊道控制、行政区划调整、空间布局演进特征等因素,划定中心城镇范围。 + +中心城镇范围划定过程中,应考虑划定区域的后续管理;研究县级关注的城市边界和形态,防止贴边等无序蔓延;应考虑县级总规对该部分内容的承接和其他规划区域的深度不同。 + +结合实际,可以有多种划定情况,如城关镇全域划定、拓展开发边界涉及的镇村单元边界、按集中城镇开发边界划定等方式划定中心城镇控制范围。 + +中心城镇未完全覆盖的镇(街道办事处)均应按照全域范围编制乡(镇)级国土空间总体规划。 + +功能结构与用地布局 + +遵循生态优先的理念,结合中心城镇地形地貌、自然环境和用地条件,合理规划城镇主要功能,妥善处理新区开发与旧区、生活区与生产区、建设空间与生态空间关系。确定中心城镇发展中心,功能组团与主要发展轴线。 + +明确中心城镇各类建设用地结构,统筹生活居住、产业发展、道路交通、基础设施与公共服务设施、历史文化资源、防灾减灾等用地功能,合理组织各类用地布局,充分运用指标预留、空间预留、功能预留等多种手段,为不可预见的重大项目用地需求作出战略预留。 + +规划分区 + +在县域国土空间总体规划基本分区的基础上,进一步细化国土空间总体规划分区至二级,确定国土空间功能导向和主要用途方向,制定用途准入原则和管控要求。 + +居住与住房保障 + +协调重要产业园区与中心城镇的关系,鼓励产城融合,避免形成单一功能的大型居住区。根据人口规模和住房需求,科学确定住宅用地占比。构建多主体供给、多渠道保障、租购并举的住房供应和保障体系,提出保障性住房配置标准。合理安排城镇居住用地供应时序,明确城镇新建住房、城镇居住用地供应量等,优化居住用地布局。 + +综合交通组织 + +按照“小街区、密路网”的理念,优化中心城镇道路网结构和布局,确定主要道路交通设施,提出交通发展策略。统筹对外交通、轨道交通、公共交通、客运枢纽、货运枢纽、物流系统等重大交通设施布局,确定主干路系统,合理确定中心城镇道路网密度和人均道路用地面积,提出慢行交通、静态交通的规划原则和指引。 + +公共服务设施与社区生活圈 + +针对人口老龄化、少子化趋势,补齐公共服务设施短板,按照《社区生活圈规划技术指南》(TD/T 1062-2021)的相关要求,明确配置内容和标准,确定教育、文化、体育、医疗卫生、社会服务等重要公共服务设施用地布局与规模,划定社区生活圈,推动社区基本公共服务设施均等化、服务范围全覆盖。 + +市政基础设施布局 + +按照提高城镇韧性和可持续发展能力的原则,统筹布局各类市政基础设施。确定各类市政基础设施的建设目标,科学预测城乡供水、排水、供电、燃气、供热、垃圾处理、通信需求总量,确定各类设施建设标准、规模和重大设施布局。基于水资源承载能力,控制用水规模,优化用水结构,制定节水措施。根据实际,提出城镇综合管廊、碳中和的布局要求。确定中心城镇智慧城市建设目标,对新型基础设施适度超前布局,以信息网络为基础,明确5G、新能源汽车充电桩等新型基础设施空间布局。 + +公共绿地与开敞空间 + +确定中心城镇绿地与广场用地的总量、人均面积和覆盖率指标,提出社区公园与开敞空间的网络化布局要求,划定结构性绿地及重要水体的控制范围与控制要求,明确各级绿地的服务半径。 + +历史文化资源保护与利用 + +明确中心城镇范围内历史文化街区、历史建筑、各级文物保护单位的保护范围,制定保护各类遗产及其依存的历史环境和人文景观的要求和措施,提出历史文化资源保护利用的目标要求和策略。 + +地下空间开发与利用 + +按照安全、高效、适度的原则,统筹地上地下空间利用,提出中心城镇地下空间利用的原则和目标,划定中心城镇地下空间开发重点区域,明确地下空间总体规模和主导功能,兼顾公共交通、市政设施与人防等用途,因地制宜划定地下空间管控范围。 + +公共安全与综合防灾 + +按照提升城镇安全和韧性的理念,确定设防标准,明确防灾设施用地布局和防灾减灾具体措施,划定涉及综合安全的重要设施范围、通道以及危险品生产和仓储用地的防护范围。结合绿地和开敞空间,布局网络化、分布式的应急设施和应急避难场所。 + +“五线”管控 + +划定黄、蓝、绿、紫、红“五条控制线”,明确各控制线管控要求。黄线指对城镇发展全局有影响的、规划中确定的、必须控制的城镇基础设施用地的控制界线。蓝线指规划确定的江、河、湖、库、渠和湿地等地表水体保护和控制的地域界线。绿线指城镇各类绿地范围的控制线。紫线指国家历史文化名城内的历史文化街区和省、自治区、直辖市人民政府公布的历史文化街区的保护范围界线,以及历史文化街区外经县级以上人民政府公布保护的历史建筑的保护范围界线。红线即城市道路控制线,是指依法规划建设的城市道路两侧边界控制线,包括规划和已建成的城镇主、次干道、消防疏散通道等内容。 + +对不能进行空间落位的“城市五线”,应因地制宜地提出定性、定量等方面的管控要求,在文本和图纸中进行标示。 + +城市更新 + +突出完善功能、提升品质和保护环境,优化中心城镇功能,划定规划期末城市更新区块,明确整治型、调整型和重构型等城市更新类型,提出与县级实际相符的城市更新原则、实施路径和相关机制,盘活存量低效用地,加快老工业区搬迁改造,稳步实施中心城镇老旧小区、危旧住房改造,有序实施城市修补和有机更新。 + +城市设计 + +在中心城镇层面运用城市设计方法,整体统筹、协调各类空间资源的布局与利用,合理组织开放空间体系与特色景观风貌系统,提升城镇空间品质与活力,分区分级提出城镇形态导控要求(见表4.32)。 + +表4. 32城市设计专题内容 + +划分详细规划单元 + +详规编制单元划分依据空间结构、规划分区、城市骨架路网、铁路及河流岸线等自然界线,结合规划用地布局和原控规单元划分,考虑功能完整性、边界稳定性和规模适宜度,合理划定中心城镇详细规划编制单元。划分编制单元应覆盖中心城镇全部地域范围,相邻编制单元之间范围不得重叠和留有空隙(见表4.33)。 + +表4. 33编制单元规模 + +(13)生态修复与综合整治 + +落实上位规划,按照自然恢复为主、人工修复为辅的原则,将生态单元作为修复和整治范围,按照保障安全、突出生态功能、兼顾景观功能的优先次序,统筹确定生态修复和国土综合整治的目标、任务、重点区域、重大工程。 + +全域国土综合整治(见表4.34) + +表4. 34国土综合整治内容 + +生态修复 + +以各类自然保护地、重要生态功能区、生态敏感区、生态脆弱区等为目标单元,对破碎化严重、功能退化的生态系统进行修复和综合整治,并提出重点工程和措施。 + +矿山生态修复 + +划分矿山生态环境保护与修复治理分区,实现成区连片治理,将主要交通干线两侧和景区周边可视范围内的矿山作为修复重点,提出生态环境保护与修复治理的主要措施,加大对植物破坏严重、岩坑裸露矿山的修复力度。 + +\subsubsection{4.规划强制性内容} +县级总体规划中涉及的安全底线、空间结构等方面内容,应作为规划强制性内容,并在图纸上有准确标明或在文本上有明确、规范地表述,同时提出相应的管控措施。强制性内容包括: + +(1)约束性指标落实及分解情况,如生态保护红线面积、用水总量、永久基本农田保护面积等; + +(2)生态屏障、生态廊道和生态系统保护格局,自然保护地体系; + +(3)生态保护红线,永久基本农田,城镇开发边界控制线范围、规模; + +(4)重大交通枢纽、重要线性工程网络、城市安全与综合防灾体系、地下空间、邻避设施等设施布局; + +(5)城乡公共服务设施配置标准,城镇政策性住房和教育、卫生、养老、文化体育等城乡公共服务设施布局原则和标准; + +(6)历史文化保护体系,各类历史文化遗产的保护范围和要求; + +(7)中心城镇“五线”(绿线、蓝线、紫线、黄线、红线)的控制范围和布局要求。 + +\subsubsection{5.近期重点建设项目} +根据国土空间规划分期实施要求,结合国民经济社会发展规划,提出分期实施目标和重点任务,明确约束性指标、管控边界和管控要求。 + +对近期规划做出统筹安排,明确近期内实施规划的重点和发展时序,确定城市近期发展方向、规模、空间布局,对重要基础设施和公共服务设施做出选址安排,提出自然和文化遗产保护、生态修复和国土综合整治措施。对国土保护、开发、整治项目及用地安排制定近期规划,优先安排生态、农业和重要民生项目。 + +\subsubsection{6.规划实施保障措施} +(1)强化组织领导 + +在县级党委和政府领导下,各有关部门要依法实施规划。党委、政府履行国土空间总体规划实施主体责任,县级自然资源部门负责规划的具体实施。建立健全国土空间规划委员会制度,发挥规委会组织协调和咨询审查作用,完善规划实施统筹决策机制。 + +(2)完善配套政策 + +县级政府牵头制定相关激励、资金筹措、帮扶政策,保障民生工程及重点项目推进。对所有国土空间分区分类实施用途管制,因地制宜明确分区准入、用途转换等管制规则。严格耕地、自然保护地、生态保护红线等特殊区域的用途管制。县级自然资源主管部门应制定预留机动指标制度、建设用地交易制度、高质量发展奖励制度、责任规划师制度和规划编制单位终身负责制等相关制度。 + +(3)提升规划信息化水平 + +以第三次全国国土调查成果为基础,按现状地类基数转换规则,根据实际进行地类细分,形成一张底图,并以此为基础,建设县级总规数据库;不断完善国土空间基础信息平台,实现全县各部门共享共用,同步建设县级国土空间总体规划“一张图”实施监督信息系统,作为县级总规的成果组成部分同步上报。 + +总规数据库建设 + +按照统一标准和要求,开展县级国土空间总体规划数据库建设,并及时逐级向上级自然资源主管部门汇交和更新,形成可层层叠加打开的、动态更新、权威统一的全县域国土空间总体规划“一张图”,为统一国土空间用途管制、实施建设项目规划许可、强化规划实施监督提供依据和支撑。 + +规划“一张图”实施监督信息系统建设 + +依托国土空间基础信息平台,以国土空间总体规划“一张图”数据为基础,结合实际管理需求,整合本级“多规合一”协同审批平台已有功能,建设国土空间总体规划“一张图”实施监督信息系统,主要功能模块包括数据应用、国土空间总体规划分析评价、国土空间总体规划成果审查与管理、资源环境承载能力监测预警、国土空间总体规划指标模型管理、国土空间总体规划大数据分析等。为建立健全国土空间总体规划动态监测评估预警和实施监管机制提供信息化支撑,为城市体检评估和规划全生命周期管理奠定基础。 + +(4)宣传与社会监督 + +开展规划进社区等宣传活动,提高全社会规划的意识。完善公众参与规划实施的社会监督机制。利用国土空间总体规划“一张图”实施监督系统,实现对县级总规的实时监测、及时预警、定期评估。 + +(5)建设专业人才队伍 + +加强专业融合创新,加快大数据、5G等新技术的研发应用,补齐短板,培养知识结构丰富、能力复合的国土空间总体规划人才。加强培训学习,积极组织地方规划人员参加省内外国土空间总体规划学习研讨和相关理论知识、政策文件学习。 + +\subsubsection{7.成果要求} +(1)成果形式 + +规划成果分为技术成果和报批成果,报批成果为在技术成果基础上,按“明晰事权、权责对等”原则进行梳理、提炼,形成报批成果。鼓励形成图文并茂、通俗易懂的公众读本。规划成果应以纸质文档和电子文件两种形式提交。电子文件采用通用的文件存储格式,文字报告成果统一采用*.docx格式,图片成果采用*.jpg格式,矢量数据采用*.gdb格式。 + +(2)成果构成 + +技术成果和报批成果均由规划文本(含附表)、图件、说明、国土空间总体规划“一张图”数据库和附件构成,规划成果的表达应当清晰、规范。 + +规划文本 + +规划文本应表述准确规范,简明扼要。文本内容应涵盖本技术要点所涵盖的规划要求,并明确表述规划的强制性内容。 + +规划图件 + +县级总体规划图件包括规划成果图和基础分析图,图件内容应包括但不限于所列图件。制图方式参照《市级国土空间总体规划制图规范》(试行)执行。图件均采用北方定向,县(市)中心城镇范围的图件比例尺原则上为 1:1万—1:5 万,与中心城镇规划合并编制的乡镇图件比例尺原则上为 1:1 万—1:5 万,县(市)域范围的图件比例尺原则上为 1:5 万—1:10 万,可根据行政辖区面积的实际情况,适当调整图件比例尺,确保制图区域内容全部表达在图幅内(见表4.35)。 + +表4. 35县级国土空间总体规划图件 + +规划说明 + +规划说明是对规划文本的说明,包括规划背景与基础、规划编制主要过程、规划主要内容、重大规划问题处理、规划成果构成。 + +规划数据库 + +数据库成果参照《黑龙江省县级国土空间总体规划数据库规范》(试行)执行,与规划编制工作同步建设、同步报批,并逐级报省自然资源厅备案,形成国土空间总体规划“一张图”。 + +专题研究报告 + +依据需要设置的重大专题,形成相应专题研究报告集。 + +附件材料 + +主要包括规划编制过程中搜集整合的现状资料和成果咨询审查形成的人大常委会审议意见、部门意见、专家论证意见、规划公示、公众参与记录及采纳情况等。 + +\subsubsection{8.成果审查} +(1)成果审查内容(见表4.36) + +表4. 36县级国土空间总体规划成果审查内容 + +(2)咨询论证 + +分类型、分层次召开公众代表规划咨询会议。鼓励采用电视、报纸、宣传栏、网站、公众号等征求意见方式,广泛收集和听取社会各方意见建议,提高规划的科学性,进一步论证完善规划编制方案。 + +(3)审查审议 + +县级自然资源主管部门将修改完善后的规划方案(含图件),以会议或文函形式,征求同级发改、教育、工信、民政、商务、生态环境、农业农村、住建、交通、水利、文旅、林草、应急管理等相关部门的意见,充分对接各部门、各行业的政策要求和发展规划,衔接发展空间和用地需求,切实增强规划的协同性和可操作性。 + +(4)规划公示 + +规划成果由编制主体组织规划公示,可通过报刊、电视、网络等各种媒体公示规划成果,规划公示时间不少于30天。公示规划图件应清晰、直观表达规划内容。 + +(5)成果审批 + +规划成果应由县级政府报同级人大常委会审议通过后,报市级人民政府初审,市级人民政府初审包括程序性审查和技术性审查,其中程序性审查由自然资源主管部门审查,技术性审查可由自然资源主管部门委托第三方进行,审查通过后报省自然资源主管部门审查;通过审查后,由市(地)人民政府将规划成果正式上报省人民政府审批。 + +(6)规划公告 + +县级总规经省人民政府批准后,县级人民政府应当在行政辖区内以适当形式向社会公告,具体包括规划目标、规划期限、规划范围、规划图件、规划批准机关和批准时间、违反规划的法律责任等内容。 + +\subsubsection{9.县级国土空间规划案例} +以典型的北方大农业地区县城《XX县国土空间总体规划(2021—2035年)》作为县级国土空间总体规划的案例,XX县国土空间总体规划(2021—2035年)提纲(见表4.37)。 + +表4. 37《XX县国土空间总体规划(2021—2035年)》提纲 + +\subsection{乡镇级国土空间规划编制基本内容} +乡镇级国土空间总体规划是对市(县)级国土空间总体规划要求的细化落实,是对乡镇域国土空间保护开发作出的具体安排,是乡镇进行空间治理的工具,是编制专项规划、详细规划以及实施国土空间用途管制的基本依据。乡镇总规在县(区)级人民政府统一领导下,由乡镇人民政府组织编制。街道办事处以县(区)政府为编制主体,几个乡镇合并编制的以县(区)政府或主导乡镇为编制主体。县(区)级自然资源主管部门指导乡镇政府开展规划编制工作。乡镇总规编制经费应纳入县(区)财政预算。承担乡镇总规编制的设计单位应当符合国家有关国土空间规划编制机构资质认证的规定。参照《黑龙江省乡镇级国土空间总体规划编制指南(试行)》乡镇级国土空间规划的重点内容主要包括以下方面: + +\subsubsection{1.规划总则} +(1)编制原则 + +坚持生态优先,绿色发展。落实上位规划划定的“三条控制线”,严守生态环境底线,优化人居环境。 + +坚持以人为本,品质提升。以人民为中心,处理好人与自然的和谐关系,实现城乡高质量发展、高品质生活。 + +坚持全域管控,适度集约。强化自然资源统筹利用和用途管控,探索控制城乡建设用地增量,盘活存量的内涵式发展路径,提高土地利用效率。 + +坚持承上启下,体现特色。严格落实市县规划下达的传导内容,并将本级约束性、预期性指标分解至村庄,因地制宜体现黑土地保护、能源安全、矿业经济、守边固边等特色。 + +坚持侧重实施,突出近期。侧重对本行政区域开发保护作出具体安排,突出与国民经济和社会发展规划的衔接,保障近期项目实施。 + +坚持公众参与,开放共享。广泛征求公众意见,开门编规划,保障公众的知情权、参与权和监督权。 + +(2) 规划范围 + +规划范围为乡镇级行政辖区内全部国土空间,也可根据实际需要由几个乡镇合并编制规划。 + +(3) 规划期限 + +本轮规划目标年为2035年,近期至2025年,远景展望至2050年。 + +(4) 规划层次 + +乡镇总规一般包括乡镇级行政辖区和乡镇政府驻地两个层次。乡镇域要统筹全域全要素规划管理,乡镇政府驻地要细化土地使用和空间布局。 + +\subsubsection{2.基础调研与研究} +(1)资料收集 + +收集涉及自然资源、生态环境、经济产业、人口社会、历史文化、基础设施、城乡发展、灾害风险等方面资料,以及相关规划成果、审批数据。 + +(2)基数和底图 + +以第三次国土调查成果为基础,结合市县总规的现状基数和底图,充分考虑规划基期用地实际和空间规划管理需要,对用地进行细化调查,按照国家相关规定进行规划现状基数分类转换,形成基期现状用地的基数和底图。 + +(3)基础分析 + +以全域全要素为基础,结合市(县)级“双评价”运算结果,明确评价结论,深化、细化乡镇的人口、经济、各类自然资源、地理要素、城乡空间、基础设施等现状特征。 + +分析乡镇国土空间资源开发保护的现状情况、变化趋势、结构布局、空间绩效,总结特点和问题,对现行乡镇总体规划和土地利用总体规划实施评估,开展灾害和风险评估。明确市县总规对乡镇总规的编制要求,提出规划编制的重点内容。 + +\subsubsection{3.规划编制} +(1) 目标与战略 + +发展目标 + +立足于地区整体发展情况,落实市县总规对乡镇的总体定位要求、职能分工和管控要求,结合乡镇自身特色与发展条件,明确乡镇功能定位、发展目标和产业导向。 + +发展战略 + +根据乡镇定位与发展目标,结合本地自然资源禀赋和经济社会发展阶段,从国土空间资源保护、开发利用、城乡品质、整治修复等方面提出国土空间开发保护的战略。 + +(2)规划指标 + +落位市县总规对乡镇的规划指标传导要求,明确生态保护红线面积、耕地保有量、永久基本农田保护面积、城乡建设用地面积等约束性指标的分解落实情况,并向村庄传导。非约束性指标可根据乡镇实际情况缩减或补充。 + +(3)国土空间格局 + +总体空间格局 + +依据市县总规,以自然地理格局为基础,统筹协调生态、农业、城乡空间,因地制宜形成乡镇开放式、网络化、集约型、生态化的国土空间保护与开发利用总体格局,彰显地方特色。 + +产业发展空间格局 + +提出乡镇产业培育的目标、方向、类型和重点,科学实践“两山”转化,提出优质生态产品和生态资源的供给与转化方向。合理提出果蔬生产区、畜牧区、养殖区等特色农产品区的空间指引。明确工业主导发展方向,统筹工业用地功能分区与布局,推动产业园区集聚化发展,落实县级相关部门制定的产业发展正负面清单。旅游资源丰富的乡镇可因地制宜提出旅游产品与旅游线路规划等内容。 + +居民点体系 + +依据市县总规,采取多手段分析乡镇人口的流动、结构、分布变化,合理预测乡镇域、乡镇政府驻地和各村庄常住人口规模。 + +可按照乡镇政府驻地、中心村、基层村三个等级,合理确定居民点体系等级结构与职能结构;结合人口变化与灾害分析等因素,按照集聚提升、搬迁撤并等五个类别,明确各村庄分类。 + +(4)规划分区与控制线落实 + +总体要求 + +在市县总规确定的空间格局、规划分区和调控目标基础上,结合本地实际与各行业主管部门具体要求细化至二级分区,明确各规划分区的范围边界和面积,落实三条控制线的划定范围,落实生态、农业、历史文化等重要保护区域和廊道,安排重大交通基础设施网络,明确各级、各类分区与控制线的管制要求。 + +生态保护空间(见表4.38) + +表4. 38乡镇级国土空间总体规划生态保护空间内容 + +农业发展空间(见表4.39) + +表4. 39乡镇级国土空间总体规划农业发展空间内容 + +城乡发展空间(见表4.40) + +表4. 40乡镇级国土空间总体规划城乡发展空间内容 + +地上地下空间(见表4.41) + +表4. 41乡镇级国土空间总体规划地上地下空间内容 + +(5) 国土空间用地结构与布局优化 + +国土空间用地功能结构调整 + +围绕规划管控目标、方向及上位规划下达的指标,优化用地布局,提出国土空间结构调整优化的重点、方向及时序安排,优化乡镇域国土资源配置。明确到规划目标年,乡镇域范围内耕地、林地、建设用地等各类用地的规模和比例,制定国土空间功能结构调整表。 + +内涵集约发展路径 + +以盘活存量、集约绿色发展为基本导向,提升用地保障能力,提高资源配置效率,明确城乡建设用地利用目标和措施,优先保障基础设施、公益性设施等民生项目用地指标。落实城乡建设用地增减挂钩机制,提出盘活存量建设用地与建设用地增减挂钩的利用措施。 + +用地布局优化(见表4.42) + +表4. 42乡镇级国土空间总体规划用地布局优化内容 + +(6) 乡镇政府驻地用地布局 + +用地结构和布局 + +根据各乡镇经济社会发展需求和自身资源禀赋,结合规划二级分区,确定乡镇政府驻地用地结构与布局。重点明确集中建设区内居住用地、公共管理与公共服务用地等各类用地规模和布局。乡镇总规如在乡镇政府驻地外规划乡镇集中建设区,应在规划中做具体说明,并统筹规划布局。 + +乡镇总规的范围如涉及市县总规中心城镇,应落实市县总规对中心城镇的国土空间安排。 + +住房建设和人居环境保障(见表4.43) + +表4. 43住房建设和人居环境保障内容 + +绿地与开敞空间用地布局 + +明确公园绿地、广场用地、城镇内河水系等开敞空间的控制范围和管控要求,确定公园绿地与广场用地的总量、人均面积和覆盖率指标。网络化布局社区公园等开敞空间,构建尺度宜人、富有活力的公共空间体系。鼓励各类公共空间与公共设施、基础设施的共用共享,提高公共空间利用效率。 + +“五线”管控与战略留白 + +划定红线、黄线、绿线、蓝线、紫线等控制线,明确管控范围和要求。对不能进行空间落位的“五线”,应因地制宜地提出定性、定量等方面的管控要求,在文本和图纸中进行标示。 + +乡镇可根据市县总规要求落实战略留白用地。战略留白用地应在集中建设区内划定,计入城乡建设用地指标。乡镇集中建设区内现状低效利用待转型、待腾退区域及尚未明确建设意向的空间可进行留白,作为功能优化和承接市县功能的疏解空间。 + +(7) 基础保障体系 + +总体要求 + +严格按照国家标准,落实上位规划,加强公共服务设施、交通设施、公共安全设施、市政基础设施等四大类设施的规划建设,在乡镇总规中明确各项设施的规划布局、规模及建设要求。 + +公共服务设施 + +对接落实市县总规确定的公共服务设施配套指标以及城乡基本公共服务均等化构建要求。明确规划公共服务设施总体布局和规模要求,建立城乡生活圈,明确各级公共服务设施配置标准,统筹乡村公共服务设施资源配置,构建公共服务设施体系。 + +交通设施 + +明确交通系统的发展方向与规划目标,提出交通设施规划实施策略。落实市县总规确定的公路、铁路、机场、水运等重要交通设施。加强乡镇域道路系统的衔接协调,配置相应的公交站场(点)等交通设施。 + +集中建设区内应明确道路交通网结构和密度,划分道路等级,明确主次干路走向,确定红线宽度,合理布局公交站场(点)、客运站、停车场等交通设施。 + +基础设施 + +协调并深化落实市县总规、专项规划中重要设施的建设目标、用地需求和空间布局。提出邻避设施控制要求,对重要的市政生命线廊道进行预留和管控。统筹安排供水、排水、供电、通信、供热、供燃气、环卫等设施,提出建设标准、规模和规划要求(见表4.44)。 集中建设区内应结合市县总规的相关建设要求,确定各类基础设施建设规模和布局。 + +表4. 44乡镇级国土空间总体规划基础设施建设内容 + +安全防灾设施 + +依据市县总规及相关法律、法规、规范要求,结合现状实际确定防灾减灾目标及防洪(潮)排涝、消防、人防、抗震、森林防火等主要灾害设防标准。落实各项安全设施用地,提出相应的安全防护要求。 + +乡镇集中建设区内应确定防洪堤、避难场所、应急指挥、消防站、救灾物资储备等设施布局,明确疫情防控、道路交通、消防通道、消防供水等基础设施防灾和应急防灾要求,对重大危险源防治、改造、搬迁提出管控要求。 + +(8)历史文化与地方特色风貌 + +历史文化保护 + +依据市县总规明确保护与传承的重点地区,严格落实各级文物保护单位、历史文化名城名镇名村、传统村落、历史建筑等历史文化遗存的保护范围,明确保护利用措施。 + +地方特色风貌 + +细化落实市县总规提出的城乡总体风貌指引和管控要求,基于自然地理格局,构筑全域景观体系。结合乡镇民族特色、边境特色、寒地特色等划定重点管控区域与节点,提出具体的风貌控制安排,对村庄的整体风貌和建筑布局提出设计引导。对集中建设区内的公共空间、重要景观节点等标志性地段提出风貌指引,划定开发强度分区和高度分区,按照分区或用地类型提出管控要求。 + +(9)生态修复与国土综合整治 + +总体要求 + +落实市县总规关于生态保护修复和国土综合整治的管控要求以及准入、退出和转换规则。确定生态修复与国土整治的类型、规模和范围,统筹相关行业部门,安排整治、修复项目。 + +生态修复 + +落实市县总规确定的生态修复和国土综合整治目标任务、主要内容、重点区域及整治对策和措施,并进行空间落位。提出乡镇生态空间整治与修复项目,明确各类生态修复工程的规模、布局、时序、建设内容(见表4.45)。 + +表4. 45乡镇级国土空间总体规划生态修复内容 + +农用地综合整治 (见表4.46) + +表4. 46乡镇级国土空间总体规划农用地综合整治 + +建设用地综合整治(见表4.47) + +表4. 47乡镇级国土空间总体规划建设用地综合整治 + +\subsubsection{4.规划强制性内容} +(1)落实分解建设用地总规模、城乡建设用地规模、生态保护红线控制面积、耕地保有量及永久基本农田面积等规划指标体系中的约束性指标。 + +(2)生态屏障、生态廊道和生态系统保护格局,自然保护地体系的保护控制要求。 + +(3)生态保护红线、永久基本农田、城镇开发边界三条控制线。 + +(4)各类历史文化遗存的保护范围和控制要求。 + +(5)乡镇集中建设区范围内结构性绿地、水体等开敞空间的控制范围和均衡分布要求。 + +(6)城镇政策性住房和城乡文化、教育、养老、体育、卫生、社会福利等主要公共服务设施和殡葬等特殊用地的布局和建设标准。 + +(7)重大交通枢纽、重要线性工程网络、重要市政基础设施、地下空间、邻避设施等设施布局。 + +(8)防洪堤走向、城镇抗震与消防疏散通道、城镇人防设施等安全与综合防灾设施布局。 + +(9)红线、绿线、蓝线、紫线、黄线等五条控制线的界线及管控要求。 + +\subsubsection{5.规划传导与管控} +应明确规划编制传导与管控体系,划分详细规划编制单元,明确向下位规划的传导内容。确保详细规划与乡镇总规有效衔接。 + +(1)划分详细规划编制单元 + +划分详细规划编制单元,包括城镇单元和村庄单元。城镇单元应编制控制性详细规划,村庄单元应编制村庄规划。 + +乡镇集中建设区内为城镇单元,单元划分应以功能为导向,根据社区生活圈、公共服务半径以及干道、河流等自然地理界线,结合社区管理边界及近远期开发时序,研究单元划分的合理性并进行适当调整。 + +乡镇集中建设区外为村庄单元,以一个或若干个行政村为单位划分单元。 + +(2)城镇单元的传导与管控 + +明确乡镇集中建设区详细规划编制单元的边界、面积、功能定位、建设用地规模,以及单元内涉及的重要公共服务设施、市政基础设施、公园绿地面积、防灾避难场所等配建标准或空间布局要求;落实“五线”等强制性内容。 + +(3)村庄单元的传导与管控 + +乡镇总规中应根据村庄等级、规模、功能等明确村庄规划编制数量和名单。村庄规划应做到应编尽编,暂时没有条件编制规划的村庄需在乡镇总规中确定。按照是否单独编制村庄规划明确不同的规划管控指引要求。 + +可编制村庄规划的,在乡镇总规中应明确村庄规划边界、面积、功能定位、村庄人口、建设用地规模及重要设施配建标准或空间布局要求;落实生态保护红线和永久基本农田等强制性内容,划定村庄建设用地边界;梳理村庄开发建设的正负面清单,引导不同类型的村庄开发建设。 + +暂时没有条件编制村庄规划的,在乡镇总规的指导下,需明确村庄建设用地二级分区,明确各规划分区的范围边界与面积,提出规划分区的用途管制规则和建设管控要求,用于审批核发乡村建设规划许可。 + +村民生活区管控要求:明确村民建设住宅的建筑层数、建筑高度、建筑密度、建筑退让等控制要求,对建筑风格、色彩、朝向、选材等提出建设指引要求。对既有农房建设提出危房改造措施和改(扩)建农房的体量与风貌控制要求。 + +生产发展区管控要求:明确生产建设用地的容积率、建筑密度、建筑高度、绿地率、建筑退让等控制要求,对建筑风格、色彩、选材等提出建设指引,鼓励产业空间复合高效利用。 + +生活服务区管控要求:明确生活服务设施用地的建筑层数、建筑高度、建筑密度、建筑退让等控制要求,对建筑风格、色彩、朝向、选材等提出建设指引要求。 + +\subsubsection{6.规划实施} +(1)分期建设 + +衔接国民经济与社会发展五年规划,制定近期行动计划。同时根据不同发展时期,提出分期实施目标、重点任务和发展时序,编制重大项目清单。 + +需进行统筹安排的重大工程和项目,包括但不限于:水污染防治和水生态修复、重点流域水土流失治理、生物多样性保护、矿山生态修复、森林质量改善、土壤污染修复、自然保护地生态修复、地质灾害隐患点修复等生态修复重大工程;高标准农田建设工程、耕地垦造工程、建设用地复垦工程、耕地质量提升工程等农用地整治工程;城镇闲置浪费用地、老旧小区、旧工业区、城中村及城边村等低效利用空间有机更新重大工程;涉及基础设施、公共服务设施的工程和项目。 + +(2)实施保障 + +为保障乡镇总规有序实施,应明确实施的组织要求,强化政策保障,健全监督问责等配套机制,加强对规划实施的督导和考核。 + +\subsubsection{7.成果要求} +(1)成果构成 + +成果由法定文件和技术文件构成。 + +(2)法定文件 + +法定文件包括规划文本、附表、图件、附件,一经审批则具有法定效力,是需要严格执行的公共政策(见表4.48)。 + +表4. 48乡镇级国土空间总体规划成果内容 + +(3)技术文件 + +技术文件包括规划说明、图件、数据库,有需要的乡镇还可以针对重点问题编制专题研究报告。技术文件是法定文件的基础性文件,是规划管理部门执行规划的参考文件,包括技术性内容和分析过程等(见表4.49)。 + +表4. 49乡镇级国土空间总体规划技术文件内容 + +(4) 图表目录 + +附表 + +指标内容与《市级国土空间总体规划编制指南》(试行)衔接一致,为保障规划指标传导,指标体系应与自然资源部颁布的正式指南为准。各乡镇可因地制宜增加相应指标。按指标确定方式分为传导指标、审核指标。传导指标由上层规划确定,在乡镇总规中严格落实;审核指标由乡镇总规根据上层规划及规范要求结合乡镇实际合理提出,由审批部门审核确定(见表4.50)。 + +表4. 50乡镇级国土空间总体规划指标体系表 + +图件 + +编制乡镇总规必选图件10张。各乡镇可根据实际需要和规划特色合并或取舍相关图纸,也可增设其他附图或将相关内容拆分表达。规划图件主要分为管控型图件、调查型图件、示意型图件(见表4.51)。 + +表4. 51乡镇级国土空间总体规划图纸说明 + +\subsubsection{8.成果审批} +(1)审查、审议 + +规划成果应先由组织编制机关采取论证会、听证会或者其他方式征求专家和公众的意见,并由县(区)人民政府组织初审,通过审查论证的规划成果由组织编制机关予以公示,公示的时间不得少于三十个自然日。规划成果公示后由乡镇人民代表大会审议通过,无本级人民代表大会及区人大街道工作委员会的街道可由上级人民代表大会常务委员会审议或由街道办事处召集本街道人大代表审议。 + +(2)规划报批 + +规划成果由县(区)人民政府上报市人民政府批准。 + +(3)成果公告、备案 + +规划自批准之日起三十个自然日内,在符合国家保密管理和地图管理等有关规定的基础上,由组织编制主体在乡镇进行公布,相应县(区)人民政府以网络媒体等方式向社会公告。同时,由组织编制主体将规划成果逐级报送至省自然资源厅备案。 + +(4)公众参与 + +乡镇总规编制应全程公众参与。基础分析阶段,应广泛听取公众意见;规划编制阶段,应及时征求公众意见;规划获批后,应及时公布并接受社会监督。 + +\subsubsection{乡镇级国土空间规划案例目录} +以典型的北方城镇《XX镇国土空间总体规划(2021—2035年)》作为乡镇级国土空间总体规划的案例,XX镇国土空间总体规划(2021—2035年)提纲(见表4.52)。 + +表4. 52《XX镇国土空间总体规划(2021—2035年)》提纲 + +第4章 国土空间规划基本原理与体系构成 71 + +4.1国土空间规划编制总则与基本术语 71 + +4.1.1国土空间规划编制总则 71 + +4.1.2国土空间规划基本术语 72 + +4.1.3国土空间用地分类 74 + +4.2国土空间规划体系 76 + +4.2.1国土空间规划体系的“五级” 77 + +4.2.2国土空间规划体系的“三类” 79 + +4.2.3国土空间规划体系的“四体系” 81 + +4.3国土空间规划编制基本方法 82 + +4.3.1国土空间规划基本原理 82 + +4.3.2国土空间规划管控方法 84 + +4.4国土空间规划编制基本内容 86 + +4.4.1省级国土空间规划编制基本内容 86 + +4.4.2市级国土空间规划编制基本内容 98 + +4.4.3县级国土空间规划编制基本内容 114 + +4.4.4乡镇级国土空间规划编制基本内容 132 + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 分类原则 & 具体内容 \\ +\hline +1 & 主干分类 & 用地用海二级类为国土调查、国土空间规划的主干分类 \\ +2 & 基础分类 & 国家国土调查以一级类和二级类为基础分类,三级类为专项调查和补充调查的分类 \\ +3 & 规划分类 & 国土空间总体规划原则上以一级类为主,可细分至二级类;国土空间详细规划和市县层级涉及空间利用的相关专项规划,原则上使用二级类和三级类。具体实用按照相关国土空间规划编制要求执行 \\ +4 & 综合利用 & 在保障安全、避免功能冲突的前提下,鼓励节约集约利用国土空间资源,国土空间详细规划可在用地用海分类基础上确定用地用海的混合利用以及地上、地下空间的复合利用 \\ +5 & 调查用途 & 为满足调查工作中年度考核管理的需要,用途改变过程中,未达到新用途验收或变更标准的,按原用途确认 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +序号 & 重点内容 \\ +\hline +1 & 体现国家意志导向,维护国家安全和国家主权,谋划顶层设计和总体部署,明确国土空间开发保护的战略选择和目标任务 \\ +2 & 明确国土空间规划管控的底数、底盘、底线和约束性指标 \\ +3 & 协调区域发展、海陆统筹和城乡统筹,优化部署重大资源、能源、交通、水利等关键性空间要素 \\ +4 & 进行地域分区,统筹全国生产力组织和经济布局,调整和优化产业空间布局结构 \\ +5 & 合理规划城镇体系,合理布局中心城市、城市群或城市圈 \\ +6 & 统筹推进大江大河流域治理,跨省区的国土空间综合整治和生态保护修复,建立以国家公园为主体的自然保护地体系 \\ +7 & 提出国土空间开发保护的政策宣言和差别化空间治理的总体原则 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +序号 & 重点内容 \\ +\hline +1 & 落实国家规划的重大战略、目标任务和约束性指标 \\ +2 & 综合考虑区域发展战略、空间结构优化、空间发展与保护、空间统筹与管制、城镇体系组织、乡村振兴等“一揽子”要求,提出省域国土空间组织的总体方案 \\ +3 & 合理配置国土空间要素,在省域内因地制宜地划定地域分区,突出永久基本农田集中保护区、生态保育区、旅游休闲区、农业复合区等功能区,明确相应的用途管制要求。明确国土空间整治修复的空间区域与总体要求 \\ +4 & 提出省域内重大资源、能源、交通、水利等关键性空间要素的布局方案,突出对历史文化、风貌特色保护与塑造等方面的要求 \\ +5 & 强化国土空间区际协调,对跨省区边界区域、跨市县行政区区域的重大空间要素配置、自然资源保护与利用、基础设施协调建设等,提出相应的建议或要求 \\ +6 & 制定保证省级国土空间规划实施的保障政策 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +序号 & 重点内容 \\ +\hline +1 & 落实国家级和省级规划的重大战略、目标任务和约束性指标,提出提升城市能级和核心竞争力、实现高质量发展、创造高品质生活的战略指引 \\ +2 & 确定市域国土空间保护、开发、利用、修复、治理的总体格局,构建与市域自然环境、发展实际相契合的可持续的城乡国土空间总体格局 \\ +3 & 确定市域总体空间结构、城镇体系结构,明确中心城市性质、职能与规模,落实生态保护红线,划定市级城镇开发边界、城市周边基本农田保护区等有关强制性区界 \\ +4 & 落实省级国土空间规划所提出的山水林田湖草等各类自然资源保护、修复的规模和要求,明确约束性指标,并对下位规划提出传导要求 \\ +5 & 统筹安排市域交通、水利、电力等基础设施布局和廊道控制要求,明确重要交通枢纽地区选址和轨道交通走向;提出公共服务设施建设标准和布局要求;统筹安排重大资源、能源、水利、交通等关键性空间要素 \\ +6 & 对城乡风貌特色、历史文脉传承、城市更新、社区生活圈建设等提出原则要求,塑造以人为本的宜居城乡环境,满足人民群众对美好生活向往的需求 \\ +7 & 建立健全从全域到功能区、社区、地块,从总体规划到专项规划、详细规划,从地级市、县(县级市、区)到乡(镇)的规划传导机制,明确下位规划需要落实的约束性指标、管控边界、管控要求等 \\ +8 & 在规划期内提出分阶段规划实施目标和重点任务,明确保障支撑国土空间规划实施的有关政策机制 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +序号 & 重点内容 \\ +\hline +1 & 落实国家和省域重大战略决策部署,落实区域发展战略、乡村振兴战略、主体功能区战略和制度,落实省级和市级规划的目标任务和约束性指标 \\ +2 & 划分国土空间用途分区,确定开发边界内集中建设地区的功能布局,明确城市主要发展方向、空间形态和用地结构 \\ +3 & 以县域内的城镇开发边界为限,划定县域“集中建设区”与“非集中建设区”,分别构建“指标+控制线+分区”的管控体系,集中建设区重点突出土地开发模式引导 \\ +4 & 确定县域镇村体系、村庄类型和村庄布点原则,明确县域镇村体系组织方案,统筹布局综合交通、基础设施、公共服务设施、综合防灾体系等 \\ +5 & 划定乡村发展和振兴的重点区域,提出优化乡村居民点空间布局的方案,提出激活乡村发展活力、推进乡村振兴的路径策略 \\ +6 & 明确国土空间生态修复目标、任务和重点区域,安排国土综合整治和生态保护修复重点工程的规模、布局和时序 \\ +7 & 根据县情实际、发展需要和可能,在县域内因地制宜地划定国土空间规划单元,明确单元规划编制指引。明确国土空间用途管制、转换和准入规则 \\ +8 & 健全规划实施动态监测、评估、预警和考核机制,提出保障规划落地实施的政策措施 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +序号 & 重点内容 \\ +\hline +1 & 落实县级规划的战略、目标任务和约束性指标 \\ +2 & 统筹生态保护修复,统筹耕地和永久基本农田保护,统筹乡村住房布局,统筹自然历史文化传承与保护,统筹产业发展空间,统筹基础设施和基本公共服务设施布局,制定乡村综合防灾减灾规划 \\ +3 & 根据需要因地制宜地进行国土空间用途编定,制定详细的用途管制规则,全面落实国土空间用途管制制度 \\ +4 & 根据需要并结合实际,在乡(镇)域范围内以一个村或几个行政村为单元编制“多规合一”的实用性村庄规划 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|} +\hline +“三类”规划 & “五级”规划 & “五级”规划 & 编制部门 & 审批部门 \\ +\hline +总体规划 & 全国国土空间规划 & 全国国土空间规划 & 自然资源部会同相关部门 & 党中央、国务院 \\ +总体规划 & 省级国土空间规划 & 省级国土空间规划 & 省级人民政府 & 同级人大常委会审议后报国务院 \\ +总体规划 & 市县乡镇 & 国务院审批的城市国土空间总体规划 & 城市人民政府 & 同级人大常委会审议后,由省级人民政府报国务院 \\ +总体规划 & 市县乡镇 & 其他市县和乡镇国土空间规划 & 市级人民政府 & 省级人民政府明确编制审批内容和程序要求 \\ +专项规划 & 海岸带、自然保护地等专项规划及跨行政区域或流域的国土空间规划 & 海岸带、自然保护地等专项规划及跨行政区域或流域的国土空间规划 & 所在区域或上一级自然资源主管部门 & 同级政府 \\ +专项规划 & 以空间利用为主的某一领域专项规划 & 以空间利用为主的某一领域专项规划 & 相关主管部门 & 国土空间规划“一张图”核对 \\ +详细规划 & 城镇开发边界内 & 城镇开发边界内 & 市县国土空间规划主管部门 & 市县人民政府 \\ +详细规划 & 城镇开发边界外的乡村地区:村庄规划 & 城镇开发边界外的乡村地区:村庄规划 & 乡镇人民政府 & 市县人民政府 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +序号 & 重点任务 \\ +\hline +1 & 全面摸清省域国土空间本底条件,开展资源环境承载力和国土空间开发适宜性评价 \\ +2 & 明确省域国土空间开发、 保护和整治的战略目标和总体布局, 落实《纲要》目标任务 \\ +3 & 确定生态空间、 农业空间和城镇空间,促进国土空间集聚开发、 分类保护和综合整治 \\ +4 & 强化支撑体系建设,促进区域联动发展 \\ +5 & 完善配套政策,建设信息平台 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 编制原则 & 详细内容 \\ +\hline +1 & 生态优先、绿色发展 & 践行绿水青山就是金山银山的理念,坚持节约资源和保护环境的基本国策,落实最严格的生态环境保护制度、耕地保护制度和节约用地制度,严守生态、粮食、能源资源等安全底线。 坚持人与自然和谐共生,积极协调人、地、产、城、乡关系,通过优化国土空间开发保护格局促进加快形成绿色发展方式和生活方式 \\ +2 & 以人民为中心、 高质量发展 & 以人民对美好生活的向往为目标,坚持增进人民福扯,改善人居环境,提升国土空间品质。建设美丽国土,促进形成生产、 生活、 生态相协调的空间格局,实现高质量发展,满足高品质生活 \\ +3 & 区域协调、融合发展 & 落实主体功能区等国家重大战略,推动国家区域协调发展战略在省域协同实施。完善统筹协调机制,协调解决国土空间矛盾冲突。加强陆海统筹,促进城乡融合。形成主体功能约束有效、国土开发有序的空间发展格局 \\ +4 & 因地制宜、特色发展 & 立足省域资源禀赋、发展阶段、重点问题和治理需求,尊重客观规律,体现地方特色,发挥比较优势,确定规划目标、策略、任务和行动,走合理分工、 优化发展的路子 \\ +5 & 数据驱动、创新发展 & 收集整合覆盖陆海全域、涵盖各类空间资源的基础数据,充分利用大数据等技术手段分析研判,夯实规划基础。 打造国土空间基础信息平台,实现互联互通, 为国土空间规划 “一张图 ” 提供支撑 \\ +6 & 共建共治、 共享发展 & 加强社会协同和公众参与,充分听取公众意见,发挥专家作用,实现共商共治,让规划编制成为凝聚社会共识的平台。发挥市场配置和政府引导作用,推进空间治理体系和治理能力现代化,实现经济效益、 社会效益、环境效益相统一,使发展成果更多更公平惠及全体人民 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 类别 & 具体内容 \\ +\hline +1 & 基础资料 & 国土空间现状数据以规划基期年法定土地利用变更调查成果为基础,充分结合地理国情普查数据、遥感影像、地形图及其他空间数据。社会经济发展数据以人口普查、社会经济统计年鉴和其他专业统计年鉴为基础 \\ +2 & 数据基础 & 以第三次国土调查成果数据为基础,形成统一的工作底数。结合基础测绘和地理国情监测成果,收集整理自然地理、自然资源、生态环境、人口、经济、社会、文化、基础设施、城乡建设、灾害风险等方面的基础数据和资料, 以及相关规划成果、 审批数据。 利用大数据等手段, 加强基础数据分析 \\ +3 & 重大战略 & 按照主体功能区战略、 区域协调发展战略、 乡村振兴战略、可持续发展战略等国家战略部署, 以及省级党委政府有关发展要求, 梳理相关重大战略对省域国土空间的具体要求, 作为编制省级国土空间规划的重要依据 \\ +4 & 基础图件 & 在规划基数确定的基础上,以土地利用现状图、行政区划图等为规划编制底图,按照制图规范要求编制相关图件 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 开发保护布局 & 具体内容 \\ +\hline +1 & 主体功能分区 & 落实全国国土空间规划纲要确定的国家级主体功能区。各地可结合实际,完善和细化省级主体功能区,按照主体功能定位划分政策单元,确定协调引导要求,明确管控导向。按照陆海统筹、保护优先原则,沿海县(区)要统筹确定一个主体功能定位 \\ +2 & 生态空间 & 依据重要生态系统识别结果,维持自然地貌特征,改善陆海生态系统、流域水系网络的系统性、整体性和连通性,明确生态屏障、生态廊道和生态系统保护格局;确定生态保护与修复重点区域;构建生物多样性保护网络,为珍稀动植物保留栖息地和迁徙廊道;合理预留基础设施廊道。优先保护以自然保护地体系为主的生态空间,明确省域国家公园、自然保护区、自然公园等各类自然保护地布局、规模和名录 \\ +3 & 农业空间 & 将全国国土空间规划纲要确定的耕地和永久基本农田保护任务严格落实,确保数量不减少、质量不降低、生态有改善、布局有优化。以水平衡为前提,优先保护平原地区水土光热条件好 、质量等级高、集中连片的优质耕地,实施 “小块并大块” ,推进现代农业规模化发展;在山地丘陵区因地制宜发展特色农业。综合考虑不同种植结构水资源需求和现代农业发展方向,明确种植业、畜牧业、养殖业等农产品主产区, 优化农业生产结构和空间布局。按照乡村振兴战略和城乡融合要求,提出优化乡村居民点布局的总体要求,实施差别化国土空间利用政策;可对村庄建设用地总量作出指标控制要求 \\ +4 & 城镇空间 & 依据全国国土空间规划纲要确定的建设用地规模,结合主体功能定位,综合考虑经济社会、产业发展、人口分布等因素,确定城镇体系的等级和规模结构、职能分工,提出城市群、都市圈、城镇圈等区域协调重点地区多中心、网络化、集约型、开放式的空间格局,引导大中小城市和小城镇协调发展。按照城镇人口规模300万以下、300—500万、500—1000万、1000—2000万、2000万以上等层级,分别确定城镇空间发展策略,促进集中集约集聚发展。将建设用地规模分解至各市(地、州、盟)。针对不同规模等级城镇提出基本公共服务配置要求,优化教育、医疗、养老等民生领域重要设施的空间布局。加强产城融合,完善产业集群布局,为战略性新兴产业预留发展空间 \\ +5 & 网络化空间组织 & 以重要自然资源、历史文化资源等要素为基础、以区域综合交通和基础设施网络为骨架、以重点城镇和综合交通枢纽为节点,加强生态空间、农业空间和城镇空间的有机互动,实现人口、资源、经济等要素优化配置,促进形成省域国土空间网络化 \\ +6 & 统筹三条控制线 & 将生态保护红线、永久基本农田、城镇开发边界等三条控制线(以下简称三条控制线)作为调整经济结构、规划产业发展、推进城镇化不可逾越的红线。结合生态保护红线和自然保护地评估调整、永久基本农田核实整改等工作,陆海统筹,确定省域三条控制线的总体格局和重点区域,明确市县划定任务,提出管控要求,将三条控制线的成果在县乡级国土空间规划中落地。实事求是解决历史遗留问题,协调解决划定矛盾,做到边界不交叉、空间不重叠、功能不冲突。各类线性基础设施应尽量并线、预留廊道,做好与三条控制线的协调衔接 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 要求 & 具体内容 \\ +\hline +1 & 提升国土空间韧性 & 主动应对全球气候变化带来的风险挑战,采取绿色低碳安全的发展举措,优化国土空间供给,改善生物多样性,提升国土空间韧性 \\ +2 & 促进高质量发展 & 深度融入经济全球化,结合“一带一路”优化生产力、城镇和基础设施布局,强化公共服务供给能力,促进高质量发展和高品质生活,提升区域竞争力 \\ +3 & 塑造美丽国土空间 & 运用国土空间地理设计方法,结合全域旅游,加强区域自然和人文景观的整体保护和塑造,充分供给多样化、高品质的魅力国土空间 \\ +4 & 提升资源资产价值 & 探索“绿水青山就是金山银山”的实现路径,完善生态产品价值实现机制,提升自然资源的经济、社会和生态价值 \\ +5 & 加强智慧规划建设 & 在规划编制实施中充分运用大数据、云计算、区块链、人工智能等新技术,探索可感知、能学习、善治理、自适应的智慧规划 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 步骤 & 内容 \\ +\hline +1 & 现状调查 & 开展省域生态环境现状调查 \\ +2 & 评价指标 & 确定规划环境影响评价的环境目标与评价指标 \\ +3 & 方案比较 & 对规划编制过程中形成方案的主要环境影响进行评价与比较 \\ +4 & 预防措施 & 针对规划推荐方案提出预防和减轻不良环境影响的措施 \\ +5 & 环境评价 & 编写规划环境影响评价篇章或说明 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 评价重点 & 重点内容 \\ +\hline +1 & 分析环境与资源现状 & 识别环境和资源特征,分析资源和环境面临的压力和问题,确定规划环境影响评价的环境目标 \\ +2 & 分析规划目标与相关环境协调性 & 分析规划目标与相关环境保护和生态建设规划环境目标的协调性 \\ +3 & 预测和评价环境影响 & 针对土地利用结构调整、 土地利用布局调整和土地利用重大工程规划方案,预测和评价可能引致的环境影响 \\ +4 & 提出预防或减缓措施 & 针对规划推荐方案实施后可能产生的不良环境影响,提出切实可行的预防或减缓措施 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 名称 & 重点内容 \\ +\hline +1 & 研究现状 & 国土空间现状和面临形势。阐述省域国土空间开发保护现状、资源环境承载现状以及存在问题,国土空间开发保护面临的形势 \\ +2 & 目标定位 & 明确省域国土空间发展定位、发展战略和主要目标 \\ +3 & 国土保护格局与分类管控引导 & 明确国土保护总体格局,提出生态保护空间分级分类保护要求,农业生产空间产业发展与耕地和永久基本农田保护要求 \\ +4 & 国土开发格局与区域发展 & 明确省域国土开发总体格局,城镇体系及基础设施网络架构,城镇和产业发展与空间布局优化措施;从广域合作、区域协同、城乡统筹、陆海联动等方面推动区域可持续发展 \\ +5 & 国土空间支撑体系建设 & 明确支撑资源环境与经济社会协调可持续发展的资源保障、能源保障、基础设施支撑体系和防灾减灾体系建设方案 \\ +6 & 重点区域及重大工程 & 国土综合整治重点区域及重大工程部署。明确城镇空间、生态空间、农业空间等国土综合整治的主要模式、重点区域和重大工程 \\ +7 & 规划实施保障措施 & \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 说明 & 具体内容 \\ +\hline +1 & 规划编制基础 & 编制背景、依据,数据采用 \\ +2 & 规划协调衔接 & 现有规划目标、空间的衔接情况,规划方案中有关规划区发展定位、规划目标、 空间格局和规划红线的衔接情况等 \\ +3 & 规划目标定位 & 规划定位和发展战略的确定依据,规划目标确定和规划指标体系构建依据,规划指标测算的依据 \\ +4 & 规划空间格局 & 国土空间格局的确定依据 \\ +5 & 国土空间划分 & 生态空间、农业空间、 城镇空间划分的依据和分级分类管控的思路 \\ +6 & 支撑体系 & 资源、 能源、基础设施、 防灾减灾等支撑体系确定的思路 \\ +7 & 国土综合整治 & 生态、环境、土地、矿产、海洋等综合整治修复区域和重点项目制定的依据 \\ +8 & 规划方案论证 & 对规划方案进行组织、技术、经济可行性论证的结论,以及规划方案实施后可能产生的社会经济、生态环境影响评价 \\ +9 & 其他 & 规划需要具体说明的其他重要问题 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 主要内容 & 具体要求 \\ +\hline +1 & 目标定位 & 国土空间开发保护目标 \\ +2 & 重要指标 & 国土空间开发强度、建设用地规模,生态保护红线控制面积、自然岸线保有率,耕地保有量及永久基本农田保护面积,用水总量和强度控制等指标的分解下达 \\ +3 & 主体功能区和重要边界 & 主体功能区划分,城镇开发边界、生态保护红线、永久基本农田的协调落实情况 \\ +4 & 空间格局 & 城镇体系布局,城市群、都市圈等区域协调重点地区的空间结构,生态屏障、生态廊道和生态系统保护格局 \\ +5 & 重要设施布局 & 重大基础设施网络布局,城乡公共服务设施配置要求 \\ +6 & 自然保护地与历史文化保护体系 & 体现地方特色的自然保护地体系,历史文化保护体系 \\ +7 & 乡村空间布局 & 促进乡村振兴的原则和要求 \\ +8 & 保障措施和对下级规划、相关规划的指导约束要求 & 保障规划实施的政策措施,对市县规划的指导和约束要求等 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +文本 & 文本 & 图纸 & 专题研究 \\ +\hline +1.基础与形势 & 1.1区域概况 & 基础分析图:区位图、地形地貌图、行政区划图、土地利用现状图、矿产资源分布图、自然保护地现状图、城镇体系现状图、综合交通现状图等 & 资源专题、气候专题 \\ +1.基础与形势 & 1.2基础优势 & 基础分析图:区位图、地形地貌图、行政区划图、土地利用现状图、矿产资源分布图、自然保护地现状图、城镇体系现状图、综合交通现状图等 & \\ +1.基础与形势 & 1.3发展机遇 & 基础分析图:区位图、地形地貌图、行政区划图、土地利用现状图、矿产资源分布图、自然保护地现状图、城镇体系现状图、综合交通现状图等 & \\ +1.基础与形势 & 1.4面临挑战 & 基础分析图:区位图、地形地貌图、行政区划图、土地利用现状图、矿产资源分布图、自然保护地现状图、城镇体系现状图、综合交通现状图等 & \\ +2.目标与战略 & 2.1指导思想 & & \\ +2.目标与战略 & 2.2基本原则 & & \\ +2.目标与战略 & 2.3目标定位 & & \\ +2.目标与战略 & 2.4空间战略 & & \\ +3.优化国土空间开发保护格局 & 3.1构建国土空间开发保护总体格局 & 国土空间总体规划图 & \\ +3.优化国土空间开发保护格局 & 3.2细化落实主体功能区战略 & 主体功能分区图 & \\ +3.优化国土空间开发保护格局 & 3.3实施“三区三线”分类管控 & & \\ +4.建设绿色安全的生态空间 & 4.1构建生态空间保护格局 & 生态保护重要性等级评价图、生态空间布局规划图 & \\ +4.建设绿色安全的生态空间 & 4.2分级划定各类生态空间 & 生态保护重要性等级评价图、生态空间布局规划图 & \\ +4.建设绿色安全的生态空间 & 4.3强化生物多样性保护 & 生态保护重要性等级评价图、生态空间布局规划图 & \\ +5.塑造美丽富饶的农业空间 & 5.1构建农业空间发展格局 & 农业生产适宜性等级评价图、农业空间布局规划图 & \\ +5.塑造美丽富饶的农业空间 & 5.2科学划定农业空间 & 农业生产适宜性等级评价图、农业空间布局规划图 & \\ +5.塑造美丽富饶的农业空间 & 5.3合理配置农业空间 & 农业生产适宜性等级评价图、农业空间布局规划图 & \\ +5.塑造美丽富饶的农业空间 & 5.4统筹推进耕地保护 & 农业生产适宜性等级评价图、农业空间布局规划图 & \\ +5.塑造美丽富饶的农业空间 & 5.5全面助推乡村振兴 & 农业生产适宜性等级评价图、农业空间布局规划图 & \\ +6.构建高效活力的城镇空间 & 6.1构建城镇空间开发格局 & 城镇建设适宜性等级评价图、城镇空间布局规划图 & \\ +6.构建高效活力的城镇空间 & 6.2优化城镇体系结构 & 城镇体系规划图 & \\ +6.构建高效活力的城镇空间 & 6.3严控城镇开发边界 & & \\ +6.构建高效活力的城镇空间 & 6.4优化产业空间布局 & 重要产业集群布局规划图 & \\ +6.构建高效活力的城镇空间 & 6.5完善公共服务设施 & 重要公共设施布局规划图 & \\ +6.构建高效活力的城镇空间 & 6.6推进城镇空间品质提升 & & \\ +7.统筹自然资源保护与利用 & 7.1优化自然资源结构与布局 & 自然保护地体系规划图 & 自然资源专题 \\ +7.统筹自然资源保护与利用 & 7.2强化水资源节约保护利用 & 自然保护地体系规划图 & 水资源专题 \\ +7.统筹自然资源保护与利用 & 7.3加强黑土耕地资源保护利用 & 自然保护地体系规划图 & 黑土耕地资源专题 \\ +7.统筹自然资源保护与利用 & 7.4生态资源保护利用 & 自然保护地体系规划图 & 生态资源专题 \\ +7.统筹自然资源保护与利用 & 7.5统筹矿产资源勘察开发和利用 & 自然保护地体系规划图 & 矿产资源专题 \\ +7.统筹自然资源保护与利用 & 7.6提高建设用地节约集约利用水平 & 自然保护地体系规划图 & \\ +8.打造彰显特色风貌的魅力龙江 & 8.1构建特色景观风貌格局 & 景观风貌保护规划图 & 景观风貌专题 \\ +8.打造彰显特色风貌的魅力龙江 & 8.2系统保护自然遗产和历史文化遗产 & 历史文化保护规划图 & 历史文化专题 \\ +8.打造彰显特色风貌的魅力龙江 & 8.3活化利用自然遗产与历史文化遗产 & 历史文化保护规划图 & \\ +8.打造彰显特色风貌的魅力龙江 & 8.4提升城乡特色风貌 & & \\ +9.构建支撑保障体系 & 9.1全面提升基础设施建设空间支撑水平 & 重点基础设施规划图 & 基础设施专题 \\ +9.构建支撑保障体系 & 9.2统筹交通设施建设空间配置 & 重点基础设施规划图 & 基础设施专题 \\ +9.构建支撑保障体系 & 9.3保障水利基础设施网络建设空间 & 重点基础设施规划图 & 基础设施专题 \\ +9.构建支撑保障体系 & 9.4预留能源信息环保设施建设空间 & 重点基础设施规划图 & 基础设施专题 \\ +9.构建支撑保障体系 & 9.5加强综合防灾设施建设保障 & 重点基础设施规划图 & 基础设施专题 \\ +10.稳步推进生态修复与国土综合整治 & 10.1实施山水林田湖草沙系统修复 & 生态修复和国土综合整治规划图 & 生态修复与国土综合整治专题 \\ +10.稳步推进生态修复与国土综合整治 & 10.2推进全域土地综合整治 & 生态修复和国土综合整治规划图 & 生态修复与国土综合整治专题 \\ +10.稳步推进生态修复与国土综合整治 & 10.3推进矿山生态修复 & 生态修复和国土综合整治规划图 & 生态修复与国土综合整治专题 \\ +10.稳步推进生态修复与国土综合整治 & 10.4重大工程安排 & 重点区域规划图 & 生态修复与国土综合整治专题 \\ +11.推动区域协调与联动发展 & 11.1构建高水平对外开放新格局 & & 区域战略专题 \\ +11.推动区域协调与联动发展 & 11.2加强省际区域协调联动发展 & & 区域战略专题 \\ +11.推动区域协调与联动发展 & 11.3推进省域重点地区协调发展 & & 区域战略专题 \\ +12.加强规划实施全生命周期管理 & 12.1强化规划传导与指引 & & 规划管控专题 \\ +12.加强规划实施全生命周期管理 & 12.2完善规划实施的制度保障 & & 规划管控专题 \\ +12.加强规划实施全生命周期管理 & 12.3建设国土空间规划“一张图” & & 规划管控专题 \\ +12.加强规划实施全生命周期管理 & 12.4建立监测评估预警和考核监管制度 & & 规划管控专题 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +序号 & 专题内容 \\ +\hline +1 & 研究人口规模、结构、分布以及人口流动等对空间供需的影响和对策 \\ +2 & 研究气候变化及水土资源、洪涝等自然灾害因素对空间开发保护的影响和对策 \\ +3 & 研究重大区域战略、新型城镇化、乡村振兴、科技进步、产业发展等对区域空间发展的影响和对策 \\ +4 & 研究交通运输体系和信息技术对区域空间发展的影响和对策 \\ +5 & 研究公共服务、基础设施、公共安全、风险防控等支撑保障系统的问题和对策 \\ +6 & 研究建设用地节约集约利用和城市更新、土地整治、生态修复的空间策略 \\ +7 & 研究自然山水和人工环境的空间特色、历史文化保护传承等空间形态和品质改善的空间对策 \\ +8 & 研究资源枯竭、人口收缩城市振兴发展的空间策略 \\ +9 & 综合研究规划实施保障机制和相关政策措施 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +编号 & 指标项 & 指标属性 & 指标层级 \\ +\hline +一、空间底线 & 一、空间底线 & 一、空间底线 & 一、空间底线 \\ +1 & 生态保护红线面积(平方公里) & 约束性 & 市域 \\ +2 & 用水总量(亿立方米) & 约束性 & 市域 \\ +3 & 永久基本农田保护面积(平方公里) & 约束性 & 市域 \\ +4 & 耕地保有量(平方公里) & 约束性 & 市域 \\ +5 & 建设用地总面积(平方公里) & 约束性 & 市域 \\ +6 & 城乡建设用地面积(平方公里) & 约束性 & 市域 \\ +7 & 林地保有量(平方公里) & 约束性 & 市域 \\ +8 & 基本草原面积(平方公里) & 约束性 & 市域 \\ +9 & 湿地面积(平方公里) & 约束性 & 市域 \\ +10 & 大陆自然海岸线保有率(\%) & 约束性 & 市域 \\ +11 & 自然和文化遗产(处) & 预期性 & 市域 \\ +12 & 地下水水位(米) & 建议性 & 市域 \\ +13 & 新能源和可再生能源比例(\%) & 建议性 & 市域 \\ +14 & 本地指示性物种种类 & 建议性 & 市域 \\ +二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 \\ +15 & 常住人口规模(万人) & 预期性 & 市域、中心城区 \\ +16 & 常住人口城镇化率(\%) & 预期性 & 市域 \\ +17 & 人均城镇建设用地面积(平方米) & 约束性 & 市域、中心城区 \\ +18 & 人均应急避难场所面积(平方米) & 预期性 & 中心城区 \\ +19 & 道路网密度(千米/平方公里) & 约束性 & 中心城区 \\ +20 & 轨道交通站点800米半径服务覆盖率(\%) & 建议性 & 中心城区 \\ +21 & 都市圈1小时人口覆盖率(\%) & 建议性 & 市域 \\ +22 & 每万元GDP水耗(立方米) & 预期性 & 市域 \\ +23 & 每万元GDP地耗(平方米) & 预期性 & 市域 \\ +三、空间品质 & 三、空间品质 & 三、空间品质 & 三、空间品质 \\ +24 & 公园绿地、广场步行5分钟覆盖率(\%) & 约束性 & 中心城区 \\ +25 & 卫生、养老、教育、文化、体育等社区公共服务设施步行15分钟覆盖率(\%) & 预期性 & 中心城区 \\ +26 & 城镇人均住房面积(平方米) & 预期性 & 市域 \\ +27 & 每千名老年人养老床位数(张) & 预期性 & 市域 \\ +28 & 每千人口医疗卫生机构床位数(张) & 预期性 & 市域 \\ +29 & 人均体育用地面积(平方米) & 预期性 & 中心城区 \\ +30 & 人均公园绿地面积(平方米) & 预期性 & 中心城区 \\ +31 & 绿色交通出行比例(\%) & 预期性 & 中心城区 \\ +32 & 工作日平均通勤时间(分钟) & 建议性 & 中心城区 \\ +33 & 降雨就地消纳率(\%) & 预期性 & 中心城区 \\ +34 & 城镇生活垃圾回收利用率(\%) & 预期性 & 中心城区 \\ +35 & 农村生活垃圾处理率(\%) & 预期性 & 市域 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 优化空间 & 内容 \\ +\hline +1 & 完善区域协调格局 & 注重推动城市群、都市圈交通一体化,发挥综合交通对区域网络化布局的引领和支撑作用,重点解决资源和能源、生态环境、公共服务设施和基础设施、产业空间和邻避设施布局等区域协同问题。城镇密集地区的城市要提出跨行政区域的都市圈、城镇圈协调发展的规划内容,促进多中心、多层次、多节点、组团式、网络化发展,防止城市无序蔓延。其他地区在培育区域中心城市的同时,要注重发挥县城、重点特色镇等节点城镇作用,形成多节点、网络化的协同发展格局 \\ +2 & 优先确定生态保护空间 & 优先确定生态保护空间:明确自然保护地等生态重要和生态敏感地区,构建重要生态屏障、廊道和网络,形成连续、完整、系统的生态保护格局和开敞空间网络体系,维护生态安全和生物多样性 \\ +3 & 保障农业发展空间 & 保障农业发展空间:优化农业(畜牧业)生产空间布局,引导布局都市农业,提高就近粮食保障能力和蔬菜自给率,重点保护集中连片的优质耕地、草地,明确具备整治潜力的区域,以及生态退耕、耕地补充的区域。沿海城市要合理安排集约化海水养殖和现代化海洋牧场空间布局 \\ +4 & 融合城乡发展空间 & 围绕新型城镇化、乡村振兴、产城融合,明确城镇体系的规模等级和空间结构,提出村庄布局优化的原则和要求。完善城乡基础设施和公共服务设施网络体系,改善可达性,构建不同层次和类型、功能复合、安全韧性的城乡生活圈 \\ +5 & 彰显地方特色空间 & 发掘本地自然和人文资源,系统保护自然景观资源和历史文化遗存,划定自然和人文资源的整体保护区域 \\ +6 & 协同地上地下空间 & 提出地下空间和重要矿产资源保护开发的重点区域,处理好地上与地下、矿产资源勘查开采与生态保护红线及永久基本农田等控制线的关系。提出城市地下空间的开发目标、规模、重点区域、分层分区和协调连通的管控要求 \\ +7 & 统筹陆海空间 & 沿海城市应按照陆海统筹原则确定生态保护红线,并提出海岸带两侧陆海功能衔接要求,制定陆域和海域功能相互协调的规划对策 \\ +8 & 预留空间 & 明确战略性的预留空间,应对未来发展的不确定性 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +一级规划分区 & 二级规划分区 & 二级规划分区 & 含义 \\ +\hline +生态保护区 & & & 具有特殊重要生态功能或生态敏感脆弱、必须强制性严格保护的陆地和海洋自然区域,包括陆域生态保护红线、海洋生态保护红线集中划定的区域 \\ +生态控制区 & & & 生态保护红线外,需要予以保留原貌、强化生态保育和生态建设、限制开发建设的陆地和海洋自然区域 \\ +农田保护区 & & & 永久基本农田相对集中需严格保护的区域 \\ +城镇发展区 & & & 城镇开发边界围合的范围,是城镇集中开发建设并可满足城镇生产、生活需要的区域 \\ +城镇发展区 & 城镇集中建设区 & 居住生活区 & 以住宅建筑和居住配套设施为主要功能导向的区域 \\ +城镇发展区 & 城镇集中建设区 & 综合服务区 & 以提供行政办公、文化、教育、医疗以及综合商业等服务为主要功能导向的区域 \\ +城镇发展区 & 城镇集中建设区 & 商业商务区 & 以提供商业、商务办公等就业岗位为主要功能导向的区域 \\ +城镇发展区 & 城镇集中建设区 & 工业发展区 & 以工业及其配套产业为主要功能导向的区域 \\ +城镇发展区 & 城镇集中建设区 & 物流仓储区 & 以物流仓储及其配套产业为主要功能导向的区域 \\ +城镇发展区 & 城镇集中建设区 & 绿地休闲区 & 以公园绿地、广场用地、滨水开敞空间、防护绿地等为主要功能导向的区域 \\ +城镇发展区 & 城镇集中建设区 & 交通枢纽区 & 以机场、港口、铁路客货运站等大型交通设施为主要功能导向的区域 \\ +城镇发展区 & 城镇集中建设区 & 战略预留区 & 在城镇集中建设区中,为城镇重大战略性功能控制的留白区域 \\ +城镇发展区 & 城镇弹性发展区 & 城镇弹性发展区 & 为应对城镇发展的不确定性,在满足特定条件下方可进行城镇开发和集中建设的区域 \\ +城镇发展区 & 特别用途区 & 特别用途区 & 为完善城镇功能,提升人居环境品质,保持城镇开发边界的完整性,根据规划管理需划入开发边界内的重点地区,主要包括与城镇关联密切的生态涵养、休闲游憩、防护隔离、自然和历史文化保护等区域 \\ +乡村发展区 & & & 农田保护区外,为满足农林牧渔等农业发展以及农民集中生活和生产配套为主的区域 \\ +乡村发展区 & 村庄建设区 & 村庄建设区 & 城镇开发边界外,规划重点发展的村庄用地区域 \\ +乡村发展区 & 一般农业区 & 一般农业区 & 以农业生产发展为主要利用功能导向划定的区域 \\ +乡村发展区 & 林业发展区 & 林业发展区 & 以规模化林业生产为主要利用功能导向划定的区域 \\ +乡村发展区 & 牧业发展区 & 牧业发展区 & 以草原畜牧业发展为主要利用功能导向划定的区域 \\ +海洋发展区 & & & 允许集中开展开发利用活动的海域,以及允许适度开展开发利用活动的无居民海岛 \\ +海洋发展区 & 渔业用海区 & 渔业用海区 & 以渔业基础设施建设、养殖和捕捞生产等渔业利用为主要功能导向的海域和无居民海岛 \\ +海洋发展区 & 交通运输用海区 & 交通运输用海区 & 以港口建设、路桥建设、航运等为主要功能导向的海域和无居民海岛 \\ +海洋发展区 & 工矿通信用海区 & 工矿通信用海区 & 以临海工业利用、矿产能源开发和海底工程建设为主要功能导向的海域和无居民海岛 \\ +海洋发展区 & 游憩用海区 & 游憩用海区 & 以开发利用旅游资源为主要功能导向的海域和无居民海岛 \\ +海洋发展区 & 特殊用海区 & 特殊用海区 & 以污水达标排放、倾倒、军事等特殊利用为主要功能导向的海域和无居民海岛 \\ +海洋发展区 & 海洋预留区 & 海洋预留区 & 规划期内为重大项目用海用岛预留的控制性后备发展区域 \\ +矿产能源发展区 & & & 为适应国家能源安全与矿业发展的重要陆域采矿区、战略性矿产储量区等区域。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 类别 & 建设内容 \\ +\hline +1 & 区县指引 & 对市辖县(区、市)提出规划指引,按照主体功能区定位,落实市级总规确定的规划目标、规划分区、重要控制线、城镇定位、要素配置等规划内容。制定市辖县(区、市)的约束性指标分解方案,下达调控指标,确保约束性指标的落实。各地可根据实际情况,在市级总规基础上,大城市可以行政区域规划片区为单元编制分区规划(相当于县级总规),中小城市可直接划分详规单元,加强对详细规划的指引和传导。涉及中心城区范围的县(区、市)的国土空间总体规划,应落实市级总规对中心城区的国土空间安排 \\ +2 & 专项指引 & 明确专项规划编制清单。相关专项规划应在国土空间总体规划的指导约束下编制,落实相关约束性指标,不得违背市级总规的强制性内容。经依法批准后纳入市级国土空间基础信息平台,叠加到国土空间规划“一张图”上 \\ +3 & 近期行动计划 & 衔接国民经济和社会发展五年规划,结合城市体检评估,对规划近期做出统筹安排,制定行动计划。编制城市更新、土地整治、生态修复、基础设施、公共服务设施和防洪排涝工程等重大项目清单,提出实施支撑政策 \\ +4 & 政策机制 & 落实和细化主体功能区等政策,提出有针对性、可操作的财政、投资、产业、环境、生态、人口、土地等规划实施政策措施,保障规划目标的实现,促进国土空间的优化和空间资源的资产价值实现。鼓励探索主体功能区制度在基层落实的途径,各地可依法制定相应配套措施 \\ +5 & 国土空间规划“一张图”建设 & 形成市级总规数据库,作为市级总规的成果组成部分同步上报。建立各部门共建共享共用、全市统一、市县(区)联动的国土空间基础信息平台,并做好与国家级平台对接,积极推进与其他信息平台的横向联通和数据共享。基于国土空间基础信息平台同步建设国土空间规划“一张图”实施监督信息系统,为城市体检评估和规划全生命周期管理奠定基础。基于国土空间基础信息平台,探索建立城市信息模型(CIM)和城市时空感知系统,促进智慧规划和智慧城市建设,提高国土空间精治、共治、法治水平 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 类别 & 内容 \\ +\hline +1 & 国土空间现状分析 & 重点归纳总结规划地区的国土空间开发保护现状以及存在的主要问题,分析国土空间规划面临的形势 \\ +2 & 规划总则 & 规划目的、规划依据、规划期限、规划范围、规划地位和作用等内容 \\ +3 & 国土空间发展战略 & 国土空间发展定位、国土空间开发保护目标以及国土空间开发保护战略、发展指标、空间结构等内容。其中,发展定位要科学合理地确定国土空间保护与发展的总体定位;国土空间开发保护目标要从经济社会发展、资源环境约束、国土空间保护、空间利用效率、生态修复等方面提出规划目标,同时,规划目标要包括近期目标、远期目标和远景目标,由此构建系统的规划目标体系;国土空间开发保护战略要从保护和开发协调进行的角度出发,提出国土空间开发保护的总体战略,为进一步的规划布局和开发保护提供总体框架和行动方向;发展指标是规划管控要求的具体化,既要能落实上级规划的管控要求和指标,又可将主要要求和指标分解到下级规划;空间结构应包括空间发展战略格局和城乡居民点体系等主要内容 \\ +4 & 国土空间管控体系 & 国土空间管控体系主要包括四个层面:首先是城镇、农业、生态三类空间划定及其国土开发强度控制指标制定,提出差异化的空间管控措施;其次是生态保护红线、永久基本农田和城镇开发边界三大控制线划定,结合规划地区的特点可以划定其他空间控制线如产业区块控制线、历史文化遗产保护控制线等,要明确各类控制线的边界、规模及其管控措施;第三是土地用途规划管控,在市县国土空间规划里,要做到全域、全要素、全地类的规划管控;最后是要素设施配置,主要包括产业布局、综合交通以及资源能源、基础设施、公共服务和防灾减灾等重大设施布局 \\ +5 & 规划实施措施 & 编制重大项目库、制定规划实施措施等内容 \\ +6 & 附表 & 规划指标一览表、国土空间管控一览表、重大项目库一览表等 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +现状图 & 市域国土空间用地用海现状图 \\ +\hline +现状图 & 市域自然保护地分布图 \\ +现状图 & 市域历史文化遗存分布图 \\ +现状图 & 市域自然灾害风险分布图 \\ +现状图 & 中心城区用地用海现状图 \\ +现状图 & 其他现状图件:反映自然地理、生态环境、能源矿产、区域发展、经济产业、人口社会、城镇化、乡村发展、灾害风险等方面现状与分析评价的必要图件。 \\ +规划图 & 市域主体功能分区图 \\ +规划图 & 市域国土空间总体格局规划图 \\ +规划图 & 市域国土空间控制线规划图 \\ +规划图 & 市域生态系统保护规划图 \\ +规划图 & 市域城镇体系规划图 \\ +规划图 & 市域农业空间规划图 \\ +规划图 & 市域历史文化保护规划图 \\ +规划图 & 市域城乡生活圈和公共服务设施规划图 \\ +规划图 & 市域综合交通规划图 \\ +规划图 & 市域基础设施规划图 \\ +规划图 & 市域国土空间规划分区图 \\ +规划图 & 市域生态修复和综合整治规划图 \\ +规划图 & 市域矿产资源规划图 \\ +规划图 & 中心城区土地使用规划图 \\ +规划图 & 中心城区国土空间规划分区图 \\ +规划图 & 中心城区开发强度分区规划图 \\ +规划图 & 中心城区控制线规划图(绿线、蓝线、紫线、黄线) \\ +规划图 & 中心城区历史文化保护和城市更新规划图 \\ +规划图 & 中心城区绿地系统和开敞空间规划图 \\ +规划图 & 中心城区公共服务设施体系、道路交通、市政基础设施、综合防灾减灾、地下空间规划图 \\ +规划图 & 其他规划图件:包括住房保障、社区生活圈、慢行系统、城乡绿道、通风廊道、景观风貌、详规单元等内容的规划图件。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 主要内容 & 具体要求 \\ +\hline +1 & 目标定位 & 国土空间开发保护目标,城市定位 \\ +2 & 重要指标 & 省级国土空间保护开发治理修复等有关量化指标的落实分解和城市发展指标体系 \\ +3 & 空间格局 & 城镇开发边界、生态保护红线、永久基本农田(海洋保护利用控制线) \\ +4 & 城镇开发边界内 & 市域国土空间规划分区和用途管制规则;生态屏障、生态廊道和生态系统保护格局,自然保护地范围和保护要求;城乡公共服务设施配置标准和布局要求;历史文化保护体系和保护框架 \\ +5 & 重要设施布局 & 重大交通枢纽、重要线性工程网络、重大基础设施网络;城市安全与综合防灾体系、地下空间、邻避设施等设施布局;城镇政策性住房布局要求,教育、卫生、养老、文化、体育等城乡公共服务布局原则和标准 \\ +6 & 乡村振兴战略有关要求 & 县域镇村体系 \\ +7 & 保障措施和对下级规划、相关规划指导约束要求 & 对县级(乡镇级)规划的指导和约束要求,对相关专项规划的指导和约束要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|} +\hline +文本 & 文本 & 文本 & 图纸 & 专题研究 \\ +\hline +1.总则 & 1.1规划目的 & & & \\ +1.总则 & 1.2规划定位 & & & \\ +1.总则 & 1.3规划依据 & & & \\ +1.总则 & 1.4指导思想 & & & \\ +1.总则 & 1.5规划原则 & & & \\ +1.总则 & 1.6规划范围、层次和期限 & & & \\ +2.现状分析与评价 & 2.1规划实施评估和灾害风险评估 & 2.1.1国土空间利用现状 & 市域国土空间用地用海现状图、市域自然保护地分布图、市域历史文化遗存分布图、市域自然灾害风险分布图、中心城区用地用海现状图、其他现状图件等 & 气候专题 \\ +2.现状分析与评价 & 2.1规划实施评估和灾害风险评估 & 2.1.2规划实施评估 & & \\ +2.现状分析与评价 & 2.1规划实施评估和灾害风险评估 & 2.1.3风险评估 & & \\ +2.现状分析与评价 & 2.2资源环境承载力与国土空间开发适宜性评价 & 2.2.1自然地理格局 & & \\ +2.现状分析与评价 & 2.2资源环境承载力与国土空间开发适宜性评价 & 2.2.2生态保护重要性评价 & 生态保护重要性等级评价图 & “双评价”专题 \\ +2.现状分析与评价 & 2.2资源环境承载力与国土空间开发适宜性评价 & 2.2.3农业生产适应性评价 & 农业生产适宜性等级评价图 & “双评价”专题 \\ +2.现状分析与评价 & 2.2资源环境承载力与国土空间开发适宜性评价 & 2.2.4城镇建设适宜性评价 & 城镇建设适宜性等级评价图 & “双评价”专题 \\ +2.现状分析与评价 & 2.2资源环境承载力与国土空间开发适宜性评价 & 2.2.5承载规模评价 & & “双评价”专题 \\ +3.目标定位与发展规模 & 3.1发展目标与空间策略 & 3.1.1目标愿景 & & \\ +3.目标定位与发展规模 & 3.1发展目标与空间策略 & 3.1.2发展目标 & & \\ +3.目标定位与发展规模 & 3.1发展目标与空间策略 & 3.1.3发展定位 & & \\ +3.目标定位与发展规模 & 3.1发展目标与空间策略 & 3.1.4指标体系 & & \\ +3.目标定位与发展规模 & 3.1发展目标与空间策略 & 3.1.5国土空间开发保护战略 & & \\ +3.目标定位与发展规模 & 3.2发展规模 & 3.2.1人口规模和城镇化水平 & & 人口专题 \\ +3.目标定位与发展规模 & 3.2发展规模 & 3.2.2建设用地规模 & & \\ +4.国土空间格局 & 4.1区域协同发展 & 4.1.1东北亚区域合作 & & 区域战略专题 \\ +4.国土空间格局 & 4.1区域协同发展 & 4.1.2国内合作 & & 区域战略专题 \\ +4.国土空间格局 & 4.1区域协同发展 & 4.1.3省际协同 & & 区域战略专题 \\ +4.国土空间格局 & 4.1区域协同发展 & 4.1.4省内协调 & & 区域战略专题 \\ +4.国土空间格局 & 4.2xx都市圈 & 4.2.1都市圈空间结构 & & 都市圈专题 \\ +4.国土空间格局 & 4.2xx都市圈 & 4.2.2都市圈协作平台 & & 都市圈专题 \\ +4.国土空间格局 & 4.2xx都市圈 & 4.2.3都市圈交通 & & 都市圈专题 \\ +4.国土空间格局 & 4.3国土空间总体格局 & & 市域国土空间总体格局规划图 & \\ +4.国土空间格局 & 4.4重要控制线 & 4.4.1生态保护红线 & 市域国土空间控制线规划图 & \\ +4.国土空间格局 & 4.4重要控制线 & 4.4.2永久基本农田 & 市域国土空间控制线规划图 & \\ +4.国土空间格局 & 4.4重要控制线 & 4.4.3城镇开发边界 & 市域国土空间控制线规划图 & \\ +4.国土空间格局 & 4.5国土空间用途管制 & 4.5.1规划分区 & 市域国土空间规划分区图 & \\ +4.国土空间格局 & 4.5国土空间用途管制 & 4.5.2空间政策 & 市域国土空间规划分区图 & \\ +4.国土空间格局 & 4.5国土空间用途管制 & 4.5.3用途结构优化 & 市域国土空间规划分区图 & \\ +5.生态空间保护 & 5.1生态空间格局 & & 市域生态系统保护规划图 & \\ +5.生态空间保护 & 5.2生态系统保护 & 5.2.1重要生态区 & 市域生态系统保护规划图 & \\ +5.生态空间保护 & 5.2生态系统保护 & 5.2.2重要生态廊道 & 市域生态系统保护规划图 & \\ +5.生态空间保护 & 5.2生态系统保护 & 5.2.3自然保护地体系 & 市域生态系统保护规划图 & \\ +5.生态空间保护 & 5.3空间特色塑造 & 5.3.1特色风貌定位 & & \\ +5.生态空间保护 & 5.3空间特色塑造 & 5.3.2风貌分区 & & \\ +6.农业空间保障 & 6.1农业空间布局 & 6.1.1农业总体布局 & 市域农业空间规划图 & \\ +6.农业空间保障 & 6.1农业空间布局 & 6.1.2养殖业空间 & 市域农业空间规划图 & \\ +6.农业空间保障 & 6.1农业空间布局 & 6.1.3高品质农产品生产基地布局 & 市域农业空间规划图 & \\ +6.农业空间保障 & 6.2乡村振兴 & 6.2.1乡村振兴目标 & 市域乡村分类建设引导规划图 & 乡村振兴专题 \\ +6.农业空间保障 & 6.2乡村振兴 & 6.2.2村庄分类 & 市域乡村分类建设引导规划图 & 乡村振兴专题 \\ +6.农业空间保障 & 6.2乡村振兴 & 6.2.3乡村建设引导 & 市域乡村分类建设引导规划图 & 乡村振兴专题 \\ +6.农业空间保障 & 6.3耕地保护 & 6.3.1耕地保护任务 & 黑土地保护规划图 & 黑土地保护专题 \\ +6.农业空间保障 & 6.3耕地保护 & 6.3.2提高耕地质量 & 黑土地保护规划图 & 黑土地保护专题 \\ +6.农业空间保障 & 6.3耕地保护 & 6.3.3黑土地保护 & 黑土地保护规划图 & 黑土地保护专题 \\ +7.城镇空间布局 & 7.1城镇空间格局 & & 市域城镇体系规划图 & 新型城镇化专题 \\ +7.城镇空间布局 & 7.2城镇体系 & 7.2.1城镇等级规模结构 & 市域城镇体系规划图 & 新型城镇化专题 \\ +7.城镇空间布局 & 7.2城镇体系 & 7.2.2城镇职能结构 & 市域城镇体系规划图 & 新型城镇化专题 \\ +7.城镇空间布局 & 7.2城镇体系 & 7.2.3城镇定位 & 市域城镇体系规划图 & 新型城镇化专题 \\ +7.城镇空间布局 & 7.3产业布局 & 7.3.1产业定位 & 市域产业空间布局规划图 & 产业发展专题 \\ +7.城镇空间布局 & 7.3产业布局 & 7.3.2产业空间布局 & 市域产业空间布局规划图 & 产业发展专题 \\ +7.城镇空间布局 & 7.4公共服务设施 & 7.4.1公共服务及配套体系 & 市域城乡生活圈和公共服务设施规划图 & 公共服务设施专题 \\ +7.城镇空间布局 & 7.4公共服务设施 & 7.4.2市级、区县级配置标准 & 市域城乡生活圈和公共服务设施规划图 & 公共服务设施专题 \\ +7.城镇空间布局 & 7.4公共服务设施 & 7.4.3城镇社区生活圈 & 市域城乡生活圈和公共服务设施规划图 & 公共服务设施专题 \\ +7.城镇空间布局 & 7.4公共服务设施 & 7.4.4乡村社区生活圈 & 市域城乡生活圈和公共服务设施规划图 & 公共服务设施专题 \\ +8.历史文化空间保护 & 8.1保护目标 & & 市域历史文化保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.2市域历史文化保护 & 8.2.1名城名镇名村保护 & 市域历史文化保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.2市域历史文化保护 & 8.2.2文物保护单位 & 市域历史文化保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.2市域历史文化保护 & 8.2.3历史建筑保护 & 市域历史文化保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.2市域历史文化保护 & 8.2.4工业遗产保护 & 市域历史文化保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.2市域历史文化保护 & 8.2.5古树名木保护 & 市域历史文化保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.2市域历史文化保护 & 8.2.6非物质文化遗产的保护 & 市域历史文化保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.3XX历史文化名城保护 & 8.3.1历史城区整体格局保护 & XX历史文化名城保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.3XX历史文化名城保护 & 8.3.2历史文化街区保护 & XX历史文化名城保护规划图 & 历史文化保护传承专题 \\ +8.历史文化空间保护 & 8.3XX历史文化名城保护 & 8.3.3历史文化风貌区保护 & XX历史文化名城保护规划图 & 历史文化保护传承专题 \\ +9.中心城区布局 & 9.1空间结构与布局 & 9.1.1空间发展目标 & 中心城区国土空间规划分区图、中心城区开发强度分区规划图、中心城区控制线规划图 & \\ +9.中心城区布局 & 9.1空间结构与布局 & 9.1.2空间结构 & 中心城区国土空间规划分区图、中心城区开发强度分区规划图、中心城区控制线规划图 & \\ +9.中心城区布局 & 9.2居住与住房保障 & 9.2.1居住用地布局引导 & 中心城区居住与住房保障规划图 & \\ +9.中心城区布局 & 9.2居住与住房保障 & 9.2.2住房供应结构 & 中心城区居住与住房保障规划图 & \\ +9.中心城区布局 & 9.2居住与住房保障 & 9.2.3住房建设引导 & 中心城区居住与住房保障规划图 & \\ +9.中心城区布局 & 9.3绿地与开敞空间 & 9.3.1总体目标 & 中心城区绿地系统和开敞空间规划图 & \\ +9.中心城区布局 & 9.3绿地与开敞空间 & 9.3.2蓝绿空间结构 & 中心城区绿地系统和开敞空间规划图 & \\ +9.中心城区布局 & 9.3绿地与开敞空间 & 9.3.3公园绿地 & 中心城区绿地系统和开敞空间规划图 & \\ +9.中心城区布局 & 9.3绿地与开敞空间 & 9.3.4防护绿地 & 中心城区绿地系统和开敞空间规划图 & \\ +9.中心城区布局 & 9.3绿地与开敞空间 & 9.3.5通风廊道 & 中心城区绿地系统和开敞空间规划图 & \\ +9.中心城区布局 & 9.3绿地与开敞空间 & 9.3.6城市绿道和城市暖廊 & 中心城区绿地系统和开敞空间规划图 & \\ +9.中心城区布局 & 9.4产业与创新空间 & 9.4.1产业布局 & 中心城区产业布局规划图 & \\ +9.中心城区布局 & 9.4产业与创新空间 & 9.4.2工业保障线 & 中心城区产业布局规划图 & \\ +9.中心城区布局 & 9.4产业与创新空间 & 9.4.3创新空间 & 中心城区产业布局规划图 & \\ +9.中心城区布局 & 9.5公共服务设施 & 9.5.1公共服务设施体系 & 中心城区公共服务设施体系规划图 & \\ +9.中心城区布局 & 9.5公共服务设施 & 9.5.2文化用地 & 中心城区公共服务设施体系规划图 & \\ +9.中心城区布局 & 9.5公共服务设施 & 9.5.3教育用地 & 中心城区公共服务设施体系规划图 & \\ +9.中心城区布局 & 9.5公共服务设施 & 9.5.4体育用地 & 中心城区公共服务设施体系规划图 & \\ +9.中心城区布局 & 9.5公共服务设施 & 9.5.5医疗卫生用地 & 中心城区公共服务设施体系规划图 & \\ +9.中心城区布局 & 9.5公共服务设施 & 9.5.6社会福利用地 & 中心城区公共服务设施体系规划图 & \\ +9.中心城区布局 & 9.5公共服务设施 & 9.5.7社区生活圈 & 中心城区公共服务设施体系规划图 & \\ +9.中心城区布局 & 9.6城市景观风貌 & 9.6.1景观风貌定位 & 中心城区城市景观风貌规划图 & \\ +9.中心城区布局 & 9.6城市景观风貌 & 9.6.2空间景观格局 & 中心城区城市景观风貌规划图 & \\ +9.中心城区布局 & 9.6城市景观风貌 & 9.6.3滨江景观塑造 & 中心城区城市景观风貌规划图 & \\ +9.中心城区布局 & 9.6城市景观风貌 & 9.6.4重点景观节点控制 & 中心城区城市景观风貌规划图 & \\ +9.中心城区布局 & 9.6城市景观风貌 & 9.6.5重点景观风貌控制区 & 中心城区城市景观风貌规划图 & \\ +9.中心城区布局 & 9.6城市景观风貌 & 9.6.6开发强度分区 & 中心城区城市景观风貌规划图 & \\ +9.中心城区布局 & 9.6城市景观风貌 & 9.6.7整体高度控制 & 中心城区城市景观风貌规划图 & \\ +9.中心城区布局 & 9.7城市更新 & 9.7.1分类盘活低效用地 & 中心城区历史文化保护和城市更新规划图 & \\ +9.中心城区布局 & 9.7城市更新 & 9.7.2有序推进城市更新与品质提升 & 中心城区历史文化保护和城市更新规划图 & \\ +9.中心城区布局 & 9.8地下空间开发利用 & 9.8.1地下空间开发目标 & 中心城区地下空间规划图 & 城市地下空间开发利用专题 \\ +9.中心城区布局 & 9.8地下空间开发利用 & 9.8.2立体分层利用地下空间 & 中心城区地下空间规划图 & 城市地下空间开发利用专题 \\ +9.中心城区布局 & 9.8地下空间开发利用 & 9.8.3地下公共设施与重点区域 & 中心城区地下空间规划图 & 城市地下空间开发利用专题 \\ +10.资源要素保护与利用 & 10.1自然资源保护与利用 & 10.1.1自然资源整体保护与利用 & 市域自然资源整体保护与利用规划图 & 自然山水和人工环境专题 \\ +10.资源要素保护与利用 & 10.1自然资源保护与利用 & 10.1.2水资源 & 市域自然资源整体保护与利用规划图 & 自然山水和人工环境专题 \\ +10.资源要素保护与利用 & 10.1自然资源保护与利用 & 10.1.3湖泊湿地资源 & 市域自然资源整体保护与利用规划图 & 自然山水和人工环境专题 \\ +10.资源要素保护与利用 & 10.1自然资源保护与利用 & 10.1.4森林资源 & 市域自然资源整体保护与利用规划图 & 自然山水和人工环境专题 \\ +10.资源要素保护与利用 & 10.1自然资源保护与利用 & 10.1.5松花江岸线资源 & 市域自然资源整体保护与利用规划图 & 自然山水和人工环境专题 \\ +10.资源要素保护与利用 & 10.2矿产资源 & 10.2.1矿产资源开发与保护 & 市域矿产资源规划图 & 资源开发保护利用专题 \\ +10.资源要素保护与利用 & 10.2矿产资源 & 10.2.2矿产资源开采规划分区管控 & 市域矿产资源规划图 & 资源开发保护利用专题 \\ +10.资源要素保护与利用 & 10.2矿产资源 & 10.2.3绿色矿山建设 & 市域矿产资源规划图 & 资源开发保护利用专题 \\ +11.综合交通 & 11.1综合交通发展战略 & 11.1.1发展目标 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.1综合交通发展战略 & 11.1.2指标体系 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.1综合交通发展战略 & 11.1.3发展策略 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.2市域综合交通系统布局 & 11.2.1公路交通 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.2市域综合交通系统布局 & 11.2.2轨道交通 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.2市域综合交通系统布局 & 11.2.3航空系统 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.2市域综合交通系统布局 & 11.2.4港口水运 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.2市域综合交通系统布局 & 11.2.5客运枢纽 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.2市域综合交通系统布局 & 11.2.6货运枢纽 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.2市域综合交通系统布局 & 11.2.7旅游交通 & 市域综合交通规划图 & 交通运输体系专题 \\ +11.综合交通 & 11.3中心城区综合交通系统布局 & 11.3.1道路网系统 & 中心城区道路交通规划图 & \\ +11.综合交通 & 11.3中心城区综合交通系统布局 & 11.3.2城市轨道 & 中心城区道路交通规划图 & \\ +11.综合交通 & 11.3中心城区综合交通系统布局 & 11.3.3公共交通 & 中心城区道路交通规划图 & \\ +11.综合交通 & 11.3中心城区综合交通系统布局 & 11.3.4慢行系统 & 中心城区道路交通规划图 & \\ +11.综合交通 & 11.3中心城区综合交通系统布局 & 11.3.5停车设施 & 中心城区道路交通规划图 & \\ +12.市政公用设施 & 12.1供水工程 & 12.1.1市域供水工程 & 市域供水规划图 & 基础设施专题 \\ +12.市政公用设施 & & 12.1.2中心城区供水 & 中心城区供水规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.2排水工程 & 12.2.1市域排水工程 & 市域排水规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.2排水工程 & 12.2.2中心城区排水工程 & 中心城区排水规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.3供电工程 & 12.3.1市域供电工程 & 市域供电规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.3供电工程 & 12.3.2中心城区供电工程 & 中心城区供电规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.4通信工程 & 12.4.1市域通信工程 & 市域通信规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.4通信工程 & 12.4.2中心城区通信工程 & 中心城区通信规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.5燃气工程 & 12.5.1市域燃气体系规划及利用 & 市域燃气规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.5燃气工程 & 12.5.2中心城区燃气设施 & 中心城区燃气规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.6供热工程 & 12.6.1市域供热体系 & 市域供热规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.6供热工程 & 12.6.2中心城区供热设施 & 中心城区供热规划图 & 基础设施专题 \\ +12.市政公用设施 & 12.7环卫工程 & 12.7.1市域环卫工程 & 市域环卫规划图 & 基础设施专题 \\ +12.市政公用设施 & & 12.7.2中心城区环卫设施 & 中心城区环卫规划图 & 基础设施专题 \\ +13.城乡安全设施 & 13.1综合防灾 & 13.1.1防洪排涝体系 & 市域综合防灾减灾规划图、中心城区综合防灾减灾规划图 & 公共安全、风险防控专题 \\ +13.城乡安全设施 & 13.1综合防灾 & 13.1.2防震减灾安全体系 & 市域综合防灾减灾规划图、中心城区综合防灾减灾规划图 & 公共安全、风险防控专题 \\ +13.城乡安全设施 & 13.1综合防灾 & 13.1.3消防救援体系 & 市域综合防灾减灾规划图、中心城区综合防灾减灾规划图 & 公共安全、风险防控专题 \\ +13.城乡安全设施 & 13.1综合防灾 & 13.1.4人防保障水平 & 市域综合防灾减灾规划图、中心城区综合防灾减灾规划图 & 公共安全、风险防控专题 \\ +13.城乡安全设施 & 13.2重大基础设施廊道控制线 & 13.2.1电力廊道 & 重大基础设施廊道控制规划图 & 公共安全、风险防控专题 \\ +13.城乡安全设施 & 13.2重大基础设施廊道控制线 & 13.2.2输气管道 & 重大基础设施廊道控制规划图 & 公共安全、风险防控专题 \\ +14.生态修复和国土综合整治 & 14.1生态修复 & 14.1.1总体目标 & 市域生态修复和综合整治规划图 & 生态修复专题 \\ +14.生态修复和国土综合整治 & 14.1生态修复 & 14.1.2生态修复重要类型和重点区域 & 市域生态修复和综合整治规划图 & 生态修复专题 \\ +14.生态修复和国土综合整治 & 14.2国土综合整治 & 14.2.1总体目标 & 市域生态修复和综合整治规划图 & 土地整治专题 \\ +14.生态修复和国土综合整治 & 14.2国土综合整治 & 14.2.2国土综合整治重要类型和重点区域 & 市域生态修复和综合整治规划图 & 土地整治专题 \\ +15.规划实施 & 15.1完善规划体系 & & & 规划实施保障专题 \\ +15.规划实施 & 15.2规划传导 & 15.2.1分级规划体系 & & 规划实施保障专题 \\ +15.规划实施 & 15.2规划传导 & 15.2.2目标指标传导 & & 规划实施保障专题 \\ +15.规划实施 & 15.2规划传导 & 15.2.3结构管控传导 & & 规划实施保障专题 \\ +15.规划实施 & 15.2规划传导 & 15.2.4策略机制传导 & & 规划实施保障专题 \\ +15.规划实施 & 15.3加强规划实施 & 15.3.1“一张图”建设 & & 规划实施保障专题 \\ +15.规划实施 & 15.3加强规划实施 & 15.3.2公共参与与社会监督 & & 规划实施保障专题 \\ +15.规划实施 & 15.3加强规划实施 & 15.3.3国土空间规划决策机制 & & 规划实施保障专题 \\ +15.规划实施 & 15.3加强规划实施 & 15.3.4近期行动计划 & & 规划实施保障专题 \\ +16.附则 & & & & \\ +17.附表 & & & & \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|} +\hline +编号 & 指标项 & 指标属性 & 指标层级 & 传导层级 \\ +\hline +一、空间底线 & 一、空间底线 & 一、空间底线 & 一、空间底线 & 一、空间底线 \\ +1 & 生态保护红线面积(公顷) & 约束性 & 县域 & 乡镇 \\ +2 & 用水总量(立方米) & 约束性 & 县域 & 乡镇 \\ +3 & 永久基本农田保护面积(公顷) & 约束性 & 县域 & 乡镇 \\ +4 & 耕地保有量(公顷) & 约束性 & 县域 & 乡镇 \\ +5 & 建设用地总面积(公顷) & 约束性 & 县域 & 乡镇 \\ +6 & 城乡建设用地面积(公顷) & 约束性 & 县域 & 乡镇 \\ +7 & 林地保有量(公顷) & 约束性 & 县域 & 乡镇 \\ +8 & 基本草原面积(公顷) & 约束性 & 县域 & 乡镇 \\ +9 & 湿地面积(公顷) & 约束性 & 县域 & 乡镇 \\ +10 & 自然和文化遗产(处) & 预期性 & 县域 & 乡镇 \\ +11 & 新增国土空间生态修复面积(公顷) & 建议性 & 县域 & 县 \\ +二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 \\ +12 & 常住人口规模(人) & 预期性 & 县域、中心城镇 & 县 \\ +13 & 常住人口城镇化率(\%) & 预期性 & 县域 & 县 \\ +14 & 人均城镇建设用地面积(平方米) & 约束性 & 县域、中心城镇 & 县 \\ +15 & 人均应急避难场所面积(平方米) & 预期性 & 中心城镇 & 县 \\ +16 & 道路网密度(米/公顷) & 约束性 & 中心城镇 & 县 \\ +17 & 每万元GDP水耗(立方米) & 预期性 & 县域 & 县 \\ +18 & 每万元GDP地耗(平方米) & 预期性 & 县域 & 县 \\ +三、空间品质 & 三、空间品质 & 三、空间品质 & 三、空间品质 & 三、空间品质 \\ +19 & 公园绿地、广场步行5分钟覆盖率(\%) & 约束性 & 中心城镇 & 县 \\ +20 & 卫生、养老、教育、文化、体育等社区公共服务设施步行15分钟覆盖率(\%) & 预期性 & 中心城镇 & 县 \\ +21 & 城镇人均住房面积(平方米) & 预期性 & 县域 & 县 \\ +22 & 每千名老年人养老床位数(张) & 预期性 & 县域 & 县 \\ +23 & 每千人口医疗卫生机构床位数(张) & 预期性 & 县域 & 县 \\ +24 & 人均公园绿地面积(平方米) & 预期性 & 中心城镇 & 县 \\ +25 & 城镇生活垃圾回收利用率(\%) & 预期性 & 中心城镇 & 县 \\ +26 & 农村生活垃圾处理率(\%) & 预期性 & 县域 & 乡镇 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 优化空间格局 & 具体内容 \\ +\hline +1 & 区域协同发展 & 落实省、市级国土空间总体规划的总体布局要求,衔接“十四五”经济社会发展规划,加强与周边行政区域在自然资源保护利用、生态环境治理、产业互补协作、基础设施联通、公共服务配置、交通网络衔接、城镇协同规划建设等方面的协调,统筹协调平衡跨行政区域的空间布局安排 \\ +2 & 县域总体格局 & 以县域内地形地貌基本特征为基础,以国土空间开发保护战略与目标为导向,结合主体功能区定位,统筹山水林田湖草沙等保护要素和城乡、产业、交通等发展类要素布局,合理构建生态屏障、生态廊道、交通网络、城镇体系,优化形成区域协调、城乡融合、人与自然和谐的国土空间总体格局,为统领生态保护、农业生产、城乡发展等开发保护提供依据 \\ +3 & “三类”空间 & 优先确定生态保护空间,遵循生态保护连续性原则,注重城镇空间、农业空间中的河湖水系、绿地系统、森林、耕地等生态要素的衔接连通,构建健康、完整、连续的绿色空间网络,明确自然保护地等生态重要和生态敏感地区,构建重要生态屏障、廊道和网络,形成连续、完整、系统的生态保护格局和开敞空间网络体系,合理预留基础设施廊道,构建生态保护空间。保障农业发展空间,优化农业生产空间布局,引导布局都市农业,提高就近粮食保障能力和蔬菜自给率,重点保护集中连片的优质耕地、草地,科学划定具备整治潜力的区域,以及生态退耕、耕地补充的区域,明确粮食生产功能区和重要农产品生产保护区,布局现代农业产业园,安排养殖设施、渔业设施、休闲渔业等设施用地,布局农业生产和农业种植、养殖配备的设施农用地,结合绿色和智慧农业发展要求,引导农业发展向优势区聚集。融合城乡发展空间,立足城乡融合发展,突出以城带乡、以工促农,健全设施网络布局、城乡融合发展的空间格局。明确城镇体系的规模等级、职能和空间结构,提出村庄布局优化的原则和要求。完善城乡基础设施和公共服务设施网络体系,改善可达性、通达性和设施完备度,构建不同层次和类型、功能复合的城乡生活圈 \\ +4 & 三条控制线 & 划定生态保护红线。落实上级生态保护红线的规模、布局以及管控要求,明确生态保护红线坐标界线,制定管控原则和保护措施。划定永久基本农田。在上级下达永久基本农田保护任务的基础上,优化县域永久基本农田布局。划定永久基本农田,落实坐标界线,制定管控原则和保护措施。划定城镇开发边界。落实上级下达的城镇开发边界划定的规模与管控要求,按照集约适度、绿色发展的要求。在城镇开发边界规模确定的基础上,细化城镇开发边界。对统筹划定后的三条控制线上图入库,纳入国土空间总体规划“一张图”数据库,作为县级总规编制的刚性底图 \\ +5 & 地方特色空间 & 发掘本地自然和人文资源,系统保护自然景观资源和历史文化遗存,划定自然和人文资源的整体保护区域 \\ +6 & 地上地下空间 & 提出地下空间和重要矿产资源保护开发等重点区域,处理好地上与地下、矿产资源勘查开采与生态保护红线及永久基本农田等控制线的关系。提出地下空间的开发目标、规模、重点区域、分层分区和协调连通的管控要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 资源 & 内容 \\ +\hline +1 & 耕地资源保护与利用 & 永久基本农田保护与利用。确定永久基本农田储备区范围边界,优化空间布局。确定永久基本农田储备区。结合永久基本农田核实整改、高标准农田建设、全域土地综合整治,开展永久基本农田储备区初步成果分析论证,统筹优化永久基本农田储备区布局,分解储备区划定规模,明确储备区利用及调整指引要求。一般耕地保护与利用。落实耕地保有量保护任务要求,提出国土综合整治指引,明确耕地质量提升的主要措施。落实市级规划提出的耕地保有量目标要求,按照数量、质量、生态“三位一体”保护的要求,严格保护耕地,尤其是稳定耕地,坚决遏制耕地“非农化”、严格管控“非粮化”。黑土地涉及的县(市)应结合地区实际特点,提出针对性的保护性利用措施。在确保生态安全前提下,合理开发耕地后备资源。实施更严格的占补平衡措施,从严控制建设占用耕地,对新增建设用地占用耕地的,按照“三位一体”要求实现占补平衡,确保耕地面积不减少 \\ +2 & 自然保护地体系建设 & 明确国家公园、自然保护区、自然公园等各类自然保护地布局和名录,建立生态保护红线与自然保护地体系间的协同调整机制 \\ +3 & 水资源保护与利用 & 坚守水资源承载能力底线,确定取用水总量、水质达标率等控制目标和配置方案,统筹重点河湖岸线及周边土地保护利用,明确水源地保护要求和保护范围 \\ +4 & 湿地生态系统保护 & 严格制定湿地保护目标,划定湿地保护范围线,科学修复退化湿地,提出修复重点工程的规模、布局和时序,积极推进合理利用,全面加强能力建设,努力提升湿地保护的治理能力和水平 \\ +5 & 森林资源保护与利用 & 加强森林资源管护,明确林地保有量、森林覆盖率等指标。强化林地利用监督管理,提出严格执行森林采伐限额、有偿使用林地等措施要求。 \\ +6 & 草地资源保护与利用 & 严格划定基本草原边界,落实封禁沙化土地保护区管理要求,加强草原用途管制 \\ +7 & 矿产资源保护与利用 & 加强与三条控制线的衔接,正确处理保护与开采、地上与地下的关系,提出矿产资源开发格局、时序安排、总量调控目标。按照防治矿山地质灾害,推动清洁能源、绿色矿山建设等转型升级,提高矿产资源利用效率的要求,明确重要矿产资源保护和开发的重要区域 \\ +8 & 风景名胜区保护与利用 & 明确省级及以上风景名胜区的分布与用地范围,划定核心景区的范围,明确风景名胜区保护、利用和管理的管控规则 \\ +9 & 建设用地节约集约利用 & 以严控增量、盘活存量、扩大流量为基本导向,明确建设用地等规模控制、结构调整、节约集约利用目标,提出建设用地布局调整的重点方向和时序安排;明确县域减量优化区域、存量挖潜区域、增量控制区域、适度发展区域以及重点发展区域、特色城镇等发展引导和开发强度控制。制定低效建设用地盘活方案,明确盘活利用规模、时序和配套政策 \\ +10 & 制定能源供需平衡方案 & 落实“碳达峰”、“碳中和”战略,构建清洁低碳安全高效的能源体系,控制化石能源总量,着力提高利用效能,实施可再生能源替代行动。优化能源结构,推动风、光、水、地热等本地清洁能源利用,提高可再生能源比例,推广“零碳”建筑,建设低碳城市 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 风貌管控 & 具体内容 \\ +\hline +1 & 统筹整体空间格局 & 落实宏观规划中自然山水环境与历史文化要素方面的相关要求,协调城镇乡村与山水林田湖草沙的整体空间关系,对优化空间结构和空间形态提出框架性导控建议 \\ +2 & 提出大尺度开放空间的导控要求 & 梳理并划定全域尺度开放空间,结合形态与功能对结构性绿地、水体等提出布局建议,辅助规划形成组织有序、结构清晰、功能完善的绿色开放空间网络 \\ +3 & 明确全域全要素的空间特色 & 根据县域自然山水、历史文化、都市发展等资源禀赋,结合规划明确的县(市)性质、发展定位、功能布局、制约条件,并结合公众意愿等,总结县域整体特色风貌,提出需重点保护的特色空间、特色要素及其框架性导控要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 专项名称 & 具体内容 \\ +\hline +1 & 确立城镇空间特色 & 细化落实宏观规划中关于城镇特色的相关要求,明确自然环境、历史人文等特色内容在城市空间中的落位。对城镇中心、空间轴带和功能布局等内容分别进行梳理,确定城镇特色空间结构并提出城镇功能布局优化建议,对城镇特色空间提出结构性导控要求。 \\ +2 & 提出空间秩序的框架 & 明确重要视线廊道及其导控要求,对建筑高度、街区尺度、城市天际线、城市色彩等内容进行有序组织,并提出结构性导控要求。 \\ +3 & 明确开放空间与设施品质提升措施 & 组织多层级、多类型的开放空间体系及其联系脉络,提出拟采取的规划政策和管控措施,提升公共服务设施及市政基础设施的集约复合性与美观实用性。 \\ +4 & 划定城市设计重点控制区 & 根据城镇空间结构、特色风貌等影响因素,划定城市设计一般控制区和重点控制区。有条件的可对重点控制区进一步进行精细化设计。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 用地 & 编制单元规模 \\ +\hline +1 & 旧城区、中心区 & 控规编制单元控制在1平方公里左右,新区可适当划大 \\ +2 & 居住混合用地 & 控规编制单元规模为1-2平方公里左右 \\ +3 & 风景区、工业区 & 控规编制单元规模一般为2平方公里以上 \\ +4 & 特色风貌区、历史文化街区等特殊地区 & 应保持边界和功能完整性,结合实际确定编制单元规模,以利于保护和塑造城市特色 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序列 & 专项名称 & 具体内容 \\ +\hline +1 & 农用地整治 & 统筹规划田水路林村综合整治,明确农用地整治项目的建设规模、新增耕地、建设时序、涉及区域等内容 \\ +2 & 建设用地增减挂钩 & 有序实施农村空心房、空心村整治以及其他低效闲置建设用地整理,明确腾退建设用地的规模和位置,节余建设用地指标优先用于农村新产业新业态融合发展用地,或用作农村集体经营性建设用地安排 \\ +3 & 低效闲置建设用地使用 & 以节约集约用地为原则,实施城乡建设用地存量更新,明确重点区域、重点工程及项目,盘活城乡闲散土地、低效城镇工业用地、老旧小区和城中村等存量低效用地 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +序号 & 图件名称 & 适用范围 & 约束条件 \\ +\hline +1 & 县域国土空间用地现状图 & 县域 & 必选 \\ +2 & 县域主体功能分区图 & 县域 & 必选 \\ +3 & 县域国土空间总体格局规划图 & 县域 & 必选 \\ +4 & 县域国土空间控制线规划图 & 县域 & 必选 \\ +5 & 县域生态系统保护规划图 & 县域 & 必选 \\ +6 & 县域农(牧)业空间规划图 & 县域 & 必选 \\ +7 & 县域城镇体系规划图 & 县域 & 必选 \\ +8 & 县域历史文化保护规划图 & 县域 & 条件必选 \\ +9 & 县域城乡生活圈和公共服务设施规划图 & 县域 & 必选 \\ +10 & 县域综合交通规划图 & 县域 & 必选 \\ +11 & 县域基础设施规划图 & 县域 & 必选 \\ +12 & 县域国土空间规划分区图 & 县域 & 必选 \\ +13 & 县域生态修复和综合整治规划图 & 县域 & 必选 \\ +14 & 县域矿产资源开采限制禁止规划图 & 县域 & 必选 \\ +15 & 县域自然保护地分布图 & 县域 & 条件必选 \\ +16 & 县域历史文化遗存分布图 & 县域 & 条件必选 \\ +17 & 县域自然灾害风险分布图 & 县域 & 条件必选 \\ +18 & 生态保护重要性评价结果图 & 县域 & 必选 \\ +19 & 农业生产适宜性评价结果图 & 县域 & 必选 \\ +20 & 城镇建设适宜性评价结果图 & 县域 & 必选 \\ +21 & 生态保护极重要区内开发利用地类分布图 & 县域 & 条件必选 \\ +22 & 种植业生产不适宜区内耕地分布图 & 县域 & 条件必选 \\ +23 & 城镇建设不适宜区内城镇建设用地分布图 & 县域 & 条件必选 \\ +24 & 耕地空间潜力分析图 & 县域 & 条件必选 \\ +25 & 城镇建设空间潜力分析图 & 县域 & 条件必选 \\ +26 & 生态系统服务功能重要性分布图 & 县域 & 条件必选 \\ +27 & 生态脆弱性分布图 & 县域 & 条件必选 \\ +28 & 多年平均降水量分布图 & 县域 & 条件必选 \\ +29 & 人均可用水资源总量分布图 & 县域 & 条件必选 \\ +30 & 地质灾害危险性分区图 & 县域 & 条件必选 \\ +31 & 地下水超采与地面沉降分布图 & 县域 & 条件必选 \\ +32 & 中心城镇国土空间规划分区图 & 中心城镇 & 必选 \\ +33 & 中心城镇土地使用规划图 & 中心城镇 & 必选 \\ +34 & 中心城镇开发强度分区规划图 & 中心城镇 & 必选 \\ +35 & 中心城镇控制线规划图 & 中心城镇 & 必选 \\ +36 & 中心城镇历史文化保护规划图 & 中心城镇 & 条件必选 \\ +37 & 中心城镇城市更新规划图 & 中心城镇 & 条件必选 \\ +38 & 中心城镇绿地系统和开敞空间规划图 & 中心城镇 & 必选 \\ +39 & 中心城镇公共服务设施体系规划图 & 中心城镇 & 必选 \\ +40 & 中心城镇市政基础设施规划图 & 中心城镇 & 必选 \\ +41 & 中心城镇道路交通规划图 & 中心城镇 & 必选 \\ +42 & 中心城镇综合防灾减灾规划图 & 中心城镇 & 必选 \\ +43 & 中心城镇地下空间规划图 & 中心城镇 & 条件必选 \\ +44 & 中心城镇国土空间用地现状图 & 中心城镇 & 必选 \\ +45 & 中心城镇详细规划编制单元划分图 & 中心城镇 & 条件必选 \\ +46 & 中心城镇景观风貌规划图 & 中心城镇 & 条件必选 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 主要内容 & 具体要求 \\ +\hline +1 & 目标定位 & 国土空间开发保护目标,城市定位 \\ +2 & 重要指标 & 省级国土空间保护开发治理修复等有关量化指标的落实分解和城市发展指标体系 \\ +3 & 空间格局 & 城镇开发边界、生态保护红线、永久基本农田(海洋保护利用控制线) \\ +4 & 城镇开发边界内 & 市域国土空间规划分区和用途管制规则;生态屏障、生态廊道和生态系统保护格局,自然保护地范围和保护要求;城乡公共服务设施配置标准和布局要求;历史文化保护体系和保护框架 \\ +5 & 重要设施布局 & 重大交通枢纽、重要线性工程网络、重大基础设施网络;城市安全与综合防灾体系、地下空间、邻避设施等设施布局;城镇政策性住房布局要求,教育、卫生、养老、文化、体育等城乡公共服务布局原则和标准 \\ +6 & 乡村振兴战略有关要求 & 县域镇村体系 \\ +7 & 保障措施和对下级规划、相关规划指导约束要求 & 对县级(乡镇级)规划的指导和约束要求,对相关专项规划的指导和约束要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|} +\hline +文本 & 文本 & 文本 & 图纸 & 专题报告 \\ +\hline +1.总则 & 1.1规划期限 & & & \\ +1.总则 & 1.2规划范围与层次 & & & \\ +1.总则 & 1.3规划底数 & & & \\ +2.规划基础与现状分析 & 2.1XX县基本情况 & & & \\ +2.规划基础与现状分析 & 2.2经济社会发展现状 & & & \\ +2.规划基础与现状分析 & 2.3国土空间利用现状 & & 县域国土空间用地现状图、中心城镇国土空间用地现状图 & \\ +2.规划基础与现状分析 & 2.4现状评估、风险评估和规划实施评估 & 2.4.1现状和风险评估 & & \\ +2.规划基础与现状分析 & 2.4现状评估、风险评估和规划实施评估 & 2.4.2规划实施评估 & & \\ +2.规划基础与现状分析 & 2.5资源环境承载能力和国土空间开发适宜性评价 & & 生态保护重要性评价结果图、农业生产适宜性评价结果图、城镇建设适宜性评价结果图 & “双评价”专题 \\ +2.规划基础与现状分析 & 2.6现状问题分析 & & & \\ +3.发展定位与目标 & 3.1发展定位 & & & \\ +3.发展定位与目标 & 3.2城市性质 & & & \\ +3.发展定位与目标 & 3.3发展目标 & & & \\ +3.发展定位与目标 & 3.4指标体系 & & & \\ +3.发展定位与目标 & 3.5发展规模 & 3.5.1人口规模 & & 人口专题 \\ +3.发展定位与目标 & 3.5发展规模 & 3.5.2用地规模 & & \\ +3.发展定位与目标 & 3.6发展战略 & & & \\ +4.县域国土空间格局 & 4.1总体格局 & & 县域主体功能分区图、县域国土空间总体格局规划图 & \\ +4.县域国土空间格局 & 4.2“三线”划定 & & 县域国土空间控制线规划图 & \\ +4.县域国土空间格局 & 4.3“三类”空间划定 & 4.3.1生态空间 & 县域生态系统保护规划图 & \\ +4.县域国土空间格局 & 4.3“三类”空间划定 & 4.3.2农业空间 & 县域农(牧)业空间规划图 & \\ +4.县域国土空间格局 & 4.3“三类”空间划定 & 4.3.3城镇空间 & 县域城镇体系规划图 & \\ +4.县域国土空间格局 & 4.4彰显地方特色空间 & & & \\ +4.县域国土空间格局 & 4.5国土规划分区与管控 & & 县域国土空间规划分区图 & \\ +5.资源保护与利用 & & & 县域矿产资源开采限制禁止规划图 & \\ +6.城乡融合发展与乡村振兴 & 6.1城镇体系规划 & 6.1.1县域人口规模预测 & 县域城镇体系规划图 & 新型城镇化专题 \\ +6.城乡融合发展与乡村振兴 & 6.1城镇体系规划 & 6.1.2县域城镇空间结构 & & 新型城镇化专题 \\ +6.城乡融合发展与乡村振兴 & 6.1城镇体系规划 & 6.1.3县域城镇等级规模结构规划 & & 新型城镇化专题 \\ +6.城乡融合发展与乡村振兴 & 6.1城镇体系规划 & 6.1.4县域城镇职能结构规划 & & 新型城镇化专题 \\ +6.城乡融合发展与乡村振兴 & 6.2村庄分类与布局优化 & & & \\ +6.城乡融合发展与乡村振兴 & 6.3产业布局及园区规划 & & & 产业专题 \\ +6.城乡融合发展与乡村振兴 & 6.4乡村振兴 & & & 乡村振兴专题 \\ +6.城乡融合发展与乡村振兴 & 6.5全域旅游发展规划 & & & 全域旅游专题 \\ +7.支撑保障体系 & 7.1县域综合交通规划 & & 县域综合交通规划图 & 交通运输体系专题 \\ +7.支撑保障体系 & 7.2公共服务设施规划 & & 县域城乡生活圈和公共服务设施规划图 & 公共服务设施专题 \\ +7.支撑保障体系 & 7.3市政基础设施规划 & & 县域基础设施规划图 & 市政基础设施专题 \\ +7.支撑保障体系 & 7.4安全韧性与综合防灾规划 & & 县域自然灾害风险分布图 & 综合防灾减灾专题 \\ +8.历史文化保护与利用 & & & 县域历史文化保护规划图 & 历史文化保护专题 \\ +9.城乡风貌引导 & 9.1全域风貌管控 & & & 城乡风貌专题 \\ +9.城乡风貌引导 & 9.2乡村风貌整治 & & & 城乡风貌专题 \\ +10.规划约束与传导 & 10.1规划管控 & & & \\ +10.规划约束与传导 & 10.2规划传导 & & & \\ +11.中心城镇规划 & 11.1发展方向与范围规模 & & & \\ +11.中心城镇规划 & 11.2功能结构与用地布局 & 11.2.1空间拓展策略 & & \\ +11.中心城镇规划 & 11.2功能结构与用地布局 & 11.2.2空间结构 & & \\ +11.中心城镇规划 & 11.2功能结构与用地布局 & 11.2.3用地布局 & 中心城镇土地使用规划图 & \\ +11.中心城镇规划 & 11.3规划分区 & & 中心城镇国土空间规划分区图 & \\ +11.中心城镇规划 & 11.4居住与住房保障 & & 中心城镇开发强度分区规划图 & \\ +11.中心城镇规划 & 11.5综合交通规划 & & 中心城镇道路交通规划图 & \\ +11.中心城镇规划 & 11.6公共服务设施与生活圈规划 & & 中心城镇公共服务设施体系规划图 & \\ +11.中心城镇规划 & 11.7市政基础设施规划 & & 中心城镇市政基础设施规划图 & \\ +11.中心城镇规划 & 11.8公共绿地与开敞空间规划 & & 中心城镇绿地系统和开敞空间规划图 & 公共绿地与开敞空间专题 \\ +11.中心城镇规划 & 11.9景观风貌规划 & & 中心城镇景观风貌规划图 & \\ +11.中心城镇规划 & 11.10地下空间开发与利用 & & 中心城镇地下空间规划图 & 地下空间专题 \\ +11.中心城镇规划 & 11.11公共安全与综合防灾 & & 中心城镇综合防灾减灾规划图 & 公共安全与综合防灾专题 \\ +11.中心城镇规划 & 11.1.2“五线”管控 & & 中心城镇控制线规划图 & \\ +11.中心城镇规划 & 11.1.3城市更新 & & 中心城镇城市更新规划图 & \\ +11.中心城镇规划 & 11.14城市设计 & & & \\ +11.中心城镇规划 & 11.15详细规划单元划分 & & 中心城镇详细规划编制单元划分图 & \\ +12.生态修复与国土综合整治 & & & 县域生态修复和综合整治规划图 & 生态修复与土地整治专题 \\ +13.近期重点建设项目 & & & & \\ +14.规划实施保障措施 & & & & \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 生态保护空间 & 具体内容 \\ +\hline +1 & 生态保护红线 & 严格落实市县总规下达的生态保护红线传导指标和要求,结合三调成果和乡镇现状,将生态保护红线落实到具体地块,并分解至村庄,确保生态保护红线面积不减少、落地准确、边界清晰 \\ +2 & 其他控制线 & 落实河湖管理范围划界、饮用水水源保护区、水源涵养地、水产种质资源保护区、蓄滞洪区等水生态、水功能保护区范围。落实生态公益林、基本草原和退耕还草范围等自然资源保护范围 \\ +3 & 细化分区 & 遵从面积不减少、布局有优化的原则,落实市县总规划定的生态保护区与生态控制区,结合乡镇实际情况,可细化至二级分区 \\ +4 & 管控要求 & 根据不同分区与控制线的管制规则,明确主要规划用途、禁止准入用途等管控要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 农业发展空间 & 具体内容 \\ +\hline +1 & 落实永久基本农田 & 将永久基本农田落实到具体地块,并分解至村庄,确保布局稳定、边界清晰 \\ +2 & 落实其他控制线 & 将永久基本农田储备区范围落实到地块,明确耕地后备资源储备、分布。落实稳定耕地、粮食生产功能区、重要农产品生产保护区、水产养殖区、畜牧禁养区等农业功能区域范围。提出种植设施、畜禽养殖设施、水产养殖设施等设施农业建设用地的布局引导 \\ +3 & 细化分区 & 落实市县总规划定的农田保护区范围,应细化至二级分区。落实市县总规划定的乡村发展区中一般农业区、林业发展区、牧业发展区范围 \\ +4 & 管控要求 & 根据不同分区与控制线的管制规则,明确主要规划用途、禁止准入用途等管控要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|} +\hline +序号 & 城乡发展空间 & 内容 & 备注 \\ +\hline +1 & 落实城镇开发边界 & 落实市县总规划定的城镇集中建设区、弹性发展区和特别用途区,确保布局稳定、边界清晰 & 乡政府驻地的村庄应参照城镇开发边界划定要求,划定本村开发边界 \\ +2 & 落实其他控制线 & 按照市县总规下达的城乡建设用地规模指标,划定城镇开发边界以外的村庄集中建设区边界 & 落实市县总规中交通、水利、能源、环保等基础设施项目的选线、走向等内容 \\ +3 & 细化分区 & 城镇集中建设区需细化到对应的二级分区,明确城镇集中建设区内用地功能分区与用地布局、规模。暂无条件编制村庄规划的村庄需明确村庄建设区的功能分区 & 明确其他建设用地的分布区域。细化落实矿产能源发展区 \\ +4 & 管控要求 & 根据不同分区与控制线的管制规则,明确主要规划用途、禁止准入用途等管控要求 & \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 地上地下空间 & 具体内容 \\ +\hline +1 & 落实要求 & 明确乡镇地下空间的开发目标、规模、重点区域、分层分区和协调连通的要求 \\ +2 & 细化分区 & 结合地方实际,明确以矿产资源开采加工为主导功能的区域,采矿、加工、尾矿、塌陷区以及为开采加工配套的办公、服务、后勤等区域应划入矿产能源发展区。依据相关规划明确落实合法矿业权范围,除生态保护红线区、永久基本农田保护区以及城市重要控制线外,已探明的未开采区域在相关技术论证、环境影响评价后,可从其他分区调整至矿产能源发展区 \\ +3 & 管控要求 & 明确规划用途、禁止准入用途等管控要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 用地 & 优化内容 \\ +\hline +1 & 林草、水域、湿地资源 & 结合规划分区、资源保护利用规划、生态修复等内容优化林草资源各类用地的布局,统筹省级湿地、重点河湖岸线及周边土地保护利用 \\ +2 & 耕地资源 & 以保障和提高粮食生产为核心,稳定和优化农业生产空间。按照集中连片、避免碎片化的原则明确耕地、园地等各类农用地布局。提出农业产业园区、种植设施、畜禽养殖设施等用地的布局要求 \\ +3 & 城乡建设用地 & 落实市县总规的城乡建设用地指标。综合新产业新业态、乡村振兴等要求,统筹确定城镇、村庄建设用地规模与布局。分析村庄空心化趋势,提出村庄搬迁撤并方案与时序安排,明确规划撤并村庄及安置用地布局 \\ +4 & 其他建设用地 & 深化落实区域基础设施用地布局,划定采矿用地、特殊用地等其他建设用地布局,明确各类用地规模。有旅游发展潜力的乡镇,可依据相关规划预留旅游服务设施、游步道等设施或空间范围 \\ +5 & 机动用地指标 & 可因地制宜预留少量(不超过5\%)城乡规划建设用地指标,以满足农村公共公益、民生工程、农业生产等无法明确具体位置的用地需求,确保零星分散的农业生产服务、乡村旅游等农村产业融合发展用地建设。待建设项目规划审批时落地机动指标,明确规划用地性质,项目批准后更新数据库并备案 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 优化类别 & 具体内容 \\ +\hline +1 & 住宅保障优化 & 结合乡镇实际,优化居住用地结构和布局,确定集中建设区人均居住用地面积。制定低效用地改造、危房改造、人居环境整治等行动计划,并提出建设时序,严控高层高密度住宅 \\ +2 & 服务功能优化 & 完善乡镇中心商贸服务职能,合理布局、优化商业服务体系,引导乡镇商贸流通业发展。根据需求预测,合理预留休闲、旅游等服务设施空间。梳理分析乡镇现状公共服务设施情况,统筹确定文化、教育、体育、医疗、社会福利等公共服务设施的布局、数量和规模要求,构建层级性的公共服务设施体系 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 基础设施类别 & 具体内容 \\ +\hline +1 & 供水 & 预测需水总量,确定供水水源,选择供水模式,布置供水主干管网,确定供水设施的布局、规模。 \\ +2 & 排水 & 确定排水体制,划分排水分区,布局污水主干管网及处理设施,布局雨水管道(沟渠)及调蓄设施。 \\ +3 & 供电 & 落实市县总规中确定的电厂、66kV及以上变电站、高压走廊的规模及用地管控要求。预测用电需求,布局中压电力线路和变电设施。 \\ +4 & 通信 & 落实通信设施布局、用地规模及建设要求。 \\ +5 & 供热 & 根据乡镇实际选择供热方式,预测供热需求总量,确定热源,明确供热站场规模、用地及建设标准,布局供热主干管网及热交换站。 \\ +6 & 供燃气 & 预测燃气需求总量,确定供气方式,布局燃气主干管道,明确门站、供气储备站等燃气站场的供气规模、占地面积,明确对燃气管道及燃气站场的安全防护要求 \\ +7 & 环卫 & 落实市县总规确定的垃圾处理设施,明确乡镇垃圾分类收集、运输、处置体系,确定垃圾转运站等主要环境卫生设施布局、建设标准及用地管控要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 修复类型 & 具体内容 \\ +\hline +1 & 水环境生态 & 确定水环境综合治理目标,确定水土保护等级和要求,落实河流水系和流域治理重点工程,改善水体功能 \\ +2 & 森林草原 & 根据生态公益林地保护等级和措施,落实需要腾退还绿、退耕还绿的造林地块。落实风沙源治理、水土流失、防护造林等修复工程 \\ +3 & 矿山 & 以重要生态功能区及居民生活区历史遗留矿山治理为重点,明确矿山修复的地区范围,提出修复对策和措施,明确修复后的规划用途 \\ +4 & 其他土地 & 明确地质灾害隐患点的空间位置,落实需要搬迁的建设用地,确定修复利用废弃地、荒地、盐碱地、沙地等地块,因地制宜确定其用途 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 目标 & 具体内容 \\ +\hline +1 & 农用地整理 & 推进低效村庄建设用地的腾退与复垦,明确低效建设用地腾退后土地复垦计划,提出农村拆违方案与拆后土地综合利用的方向。推进低效林草地和园地整理、现有耕地提质改造、高标准农田建设等实施项目。以预防为主,提出土壤污染防治方案。提出各种污染源排放的控制要求,推进污染土壤农田基础设施建设项目 \\ +2 & 后备土地资源开发 & 在不破坏生态环境的前提下,慎重开发后备土地资源,因地制宜确定未利用地开发的用途和措施 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 目标 & 具体内容 \\ +\hline +1 & 城镇建设用地 & 在集中建设区内对存量建设用地和低效能建设用地进行梳理,明确可更新改造区域的位置、规模、范围和功能指引 \\ +2 & 农村建设用地 & 有序开展农村宅基地优化整理,充分利用农村现状集体经营性建设用地。在村庄建设用地规划范围内,可优先将腾退的宅基地等闲散建设用地,集中用于乡村产业发展 \\ +3 & 增减挂钩用地 & 明确增减挂钩用地位置与规模,通过农村建设用地、工矿废弃地整理,解决新增城镇建设用地指标不足的问题,提高乡镇土地整体利用效率。增减挂钩项目的减量建设用地和整体搬迁村庄应纳入农用地整理复垦项目,且在实施搬迁改造之前,相应置换的城乡建设用地指标不得使用。待实施搬迁改造后,以增减挂钩、指标统筹为原则,进行布局 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 文件类型 & 具体内容 \\ +\hline +1 & 规划文本、附表 & 应以法条化的格式表述规划结论,表述准确规范、简明扼要,突出强制性内容 \\ +2 & 规划图件 & 规划图件统一采用“2000国家大地坐标系”,高程基准面采用“1985国家高程基准”,投影系统采用“高斯—克吕格”投影,分带采用“国家标准分带”。比例尺原则要求一般乡镇域范围为1:10000-1:50000,乡镇集中建设区为1:1000-1:2000 ,满足上图入库要求。图件应符合相关制图规范要求,明确标示项目名称、图名、图号、比例尺、风玫瑰、图例、绘制时间、规划编制单位名称等 \\ +3 & 附件 & 包括人大审议意见、部门意见、专家论证意见、公众参与记录等 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 文件类型 & 具体内容 \\ +\hline +1 & 规划说明 & 对规划文本具体说明与解释,主要阐述规划决策的编制基础、分析过程和分析结论,是配合规划文本和图件使用的重要参考 \\ +2 & 图件 & 包括管控型图件、调查型图件、示意型图件三类 \\ +3 & 数据库 & 上报审批成果要求参照《市级国土空间总体规划数据库规范》和《黑龙江省县级国土空间总体规划数据库规范》执行 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|c|c|c|} +\hline +编号 & 指标项 & 基期年 & 2025年 & 2035年 & 指标层级 & 指标属性 & 备注 \\ +\hline +一、空间底线 & 一、空间底线 & 一、空间底线 & 一、空间底线 & 一、空间底线 & 一、空间底线 & 一、空间底线 & \\ +1 & 生态保护红线面积(万平方米) & & & & 乡镇域 & 约束性 & 传导 \\ +2 & 用水总量(万立方米) & & & & 乡镇域 & 约束性 & 传导 \\ +3 & 永久基本农田保护面积(万平方米) & & & & 乡镇域 & 约束性 & 传导 \\ +4 & 耕地保有量(万平方米) & & & & 乡镇域 & 约束性 & 传导 \\ +5 & 建设用地总面积(万平方米) & & & & 乡镇域 & 约束性 & 传导 \\ +6 & 城乡建设用地面积(万平方米) & & & & 乡镇域 & 约束性 & 传导 \\ +7 & 林地保有量(万平方米) & & & & 乡镇域 & 约束性 & 传导 \\ +8 & 基本草原面积(万平方米) & & & & 乡镇域 & 约束性 & 传导 \\ +9 & 湿地面积(万平方米) & & & & 乡镇域 & 约束性 & 传导 \\ +二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 & 二、空间结构与效率 & \\ +10 & 常住人口规模(人) & & & & 乡镇域/乡镇政府驻地 & 预期性 & 传导 \\ +11 & 常住人口城镇化率(\%) & & & & 乡镇域 & 预期性 & 审核 \\ +12 & 人均城镇建设用地面积(平方米) & & & & 乡镇政府驻地 & 约束性 & 传导 \\ +13 & 人均应急避难场所面积(平方米) & & & & 乡镇政府驻地 & 预期性 & 审核 \\ +14 & 道路网密度(千米/平方千米) & & & & 乡镇政府驻地 & 约束性 & 审核 \\ +三、空间品质 & 三、空间品质 & 三、空间品质 & 三、空间品质 & 三、空间品质 & 三、空间品质 & 三、空间品质 & \\ +15 & 公园绿地、广场步行 5 分钟覆盖率(\%) & & & & 乡镇政府驻地 & 约束性 & 审核 \\ +16 & 卫生、养老、教育、文化、体育等社区公共服务设施15分钟步行可达覆盖率(\%) & & & & 乡镇政府驻地 & 预期性 & 审核 \\ +17 & 人均住房面积(平方米) & & & & 乡镇域 & 预期性 & 审核 \\ +18 & 每千名老年人养老床位数(张) & & & & 乡镇域 & 预期性 & 审核 \\ +19 & 每千人口医疗卫生机构床位数(张) & & & & 乡镇域 & 预期性 & 审核 \\ +20 & 人均体育用地面积(平方米) & & & & 乡镇政府驻地 & 预期性 & 审核 \\ +21 & 人均公园绿地与开敞空间面积(平方米) & & & & 乡镇政府驻地 & 预期性 & 审核 \\ +22 & 城镇生活垃圾回收利用率(\%) & & & & 乡镇政府驻地 & 预期性 & 审核 \\ +23 & 农村生活垃圾处理率(\%) & & & & 乡镇域 & 预期性 & 审核 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 图纸名称 & 主要内容 \\ +\hline + & 管控型图件 & 管控型图件 \\ +1 & 乡镇域国土空间规划分区图 & 图纸内容与附表1-2相对应,主要图面要素包括集中建设区、村庄建设区等。原则上,生态保护区、城镇发展区、农田保护区三部分空间互相不重叠 \\ +2 & 乡镇域国土空间控制线规划图 & 在上位规划划定的三条控制线基础上,进行深化和细化 \\ +3 & 乡镇域国土空间用途规划图 & 农用地、建设用地、其他用地等各类用地规划用途,生态、农业、建设空间布局等内容 \\ +4 & 乡镇域生态修复和综合整治规划图 & 标明山水林田湖草系统修复、国土综合整治、矿山生态修复等重点区域和重大项目等内容 \\ +4 & 乡镇域历史文化保护规划图 & 各类历史文化遗存的保护范围和要求;表达各类历史文化遗产的位置与类型,历史文化保护线 \\ +6 & 乡镇域综合交通规划图 & 标明乡镇域范围内高速铁路、铁路客运站、高速公路(含城市快速路)等重大交通设施廊道空间分布,交通廊道规划用地的管控范围及互通式立交位置。标明镇域范围内轨道线路走廊及场站设施布局。标明镇域的公路等级,标明各等级城镇道路。标明机场、客运枢纽、货运枢纽、公路附属设施等要素。标明全区公交枢纽、公交场站、公共停车场、换乘停车场、加油充电站的空间分布 \\ +7 & 乡镇域基础设施规划图 & 在图面明确镇域内现状和规划的各类设施。在镇域范围不能体现用地的设施,应通过设置图例表述,并与文本的配套建设要求相对应 \\ +8 & 乡镇域村庄单元规划管控指引图 & 明确村庄规划编制范围,标示编制村庄规划和暂时没有条件编制规划的村庄单元 \\ +9 & 乡镇域村庄发展与布局规划图 & 表示乡镇域镇村发展布局结构和村庄居民点体系等级结构,标明乡镇政府驻地、乡镇其他组团和各级村庄,明确村庄类型,明确村庄的主体功能、建设用地规模、人口规模、各类设施配置内容、产业类型和布局等 \\ +10 & 乡镇政府驻地土地使用规划图 & 表达乡镇政府驻地规划建设范围、各类城乡建设用地规划布局 \\ +11 & 乡镇政府驻地绿地系统和开敞空间规划图 & 确定乡镇政府驻地绿地网络系统结构,标明重要的绿地节点和轴带,标明公园绿地、防护绿地、广场、附属绿地等 \\ +12 & 乡镇政府驻地道路交通规划图 & 确定乡镇政府驻地道路交通系统布局,标明乡镇政府驻地范围内主干路、干路、支路等走向、断面、名称、主要交叉口形式,明确站场、码头、公交场站、公共停车场及其他交通附属设施的位置与范围 \\ +13 & 乡镇政府驻地公共服务设施体系规划图 & 公共服务设施可在用地三级分类基础上结合实际进行细化。教育设施包括基础教育设施、特殊教育设施、中等专业学校以及高等院校等;医疗卫生设施包括综合医院、中医医院、专科医院、康复医院、护理院,以及疾病预防控制中心、急救分中心等;文化设施包含区级、镇级设施;体育设施包括体育场馆以及训练场等;社会福利设施包括养老、残疾、儿童福利设施等。添加设施名称的属性字段,在图面用图例或文字分别标明现状与规划设施用地 \\ +14 & 乡镇政府驻地市政基础设施和综合防灾减灾规划图 & 基础设施规划的图面表达包括雨水、污水设施、供水设施、供电设施、供热设施、燃气设施、电信基础设施、有线电视基础设施、环卫设施等内容。并标明联通相应设施的主管网。综合防灾图纸表达包括防洪工程、消防工程、抗震工程,可以包括但不仅限于地质灾害、危险品储存和运输、气象灾害等 \\ +15 & 乡镇政府驻地历史文化保护规划图 & 各类历史文化遗存的保护范围和要求;表达各类历史文化遗产的位置与类型。 \\ +16 & 乡镇政府驻地“五线”规划图 & 划定“五条控制线”,明确各控制线管控范围 \\ + & 调查型图件 & 调查型图件 \\ +17 & 乡镇域国土空间用地现状图 & 乡镇范围内农用地、建设用地、其他用地等各类用地现状;重要公共服务设施和基础设施的位置、线路、等级;铁路、公路、山体河流、自然保护地、自然资源分布等内容 \\ +18 & 乡镇域综合交通及区域基础设施现状图 & 表达乡镇域内现有的交通网络和设施,表明公交线路及公交站点;表明水利能源、给水排水、电力电信、供热燃气、殡葬、环卫等现状基础设施及主要干线走向;明确现有重大交通与基础设施廊道空间等内容 \\ +19 & 乡镇政府驻地国土空间用地现状图 & 表达乡镇政府驻地内各类城乡建设用地的现状;重要公共服务设施和基础设施的位置、线路、等级;铁路、公路、山体、河流等现状要素等内容 \\ + & 示意型图件 & 示意型图件 \\ +20 & 区位图 & 表达乡镇所在位置、周边交通状况、与周边地区相互关系等内容 \\ +21 & 乡镇域国土空间总体格局图 & 表示乡镇空间发展格局,标绘村镇发展轴带、重要节点等要素 \\ +22 & 乡镇域城乡生活圈及公共服务设施 & 表达乡镇社区生活服务圈规划配置体系要求,落位大型公共服务设施布局 \\ +23 & 乡镇域景观风貌规划图 & 表达全域自然、农业、人文景观风貌分区及重要节点等内容 \\ +24 & 乡镇域产业发展与布局规划图 & 表示乡镇重点发展产业及产业集聚区等空间布局 \\ +25 & 乡镇域增减挂钩实施引导图 & 表达乡镇剩余资源和减量的城乡建设用地分布,增减挂钩的新增建设用地分布 \\ +26 & 近期实施项目规划图 & 表达近期实施年度计划及各项分期实施项目的空间布局 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|} +\hline +文本 & 文本 & 文本 & 图纸 & 专题报告 \\ +\hline +1.规划基础与现状分析 & 1.1城镇基本情况 & & & \\ +1.规划基础与现状分析 & 1.2基数和底图 & & 乡镇域国土空间用地现状图、乡镇域综合交通及区域基础设施现状图、乡镇政府驻地国土空间用地现状图 & \\ +1.规划基础与现状分析 & 1.3现状评估、灾害和风险评估、规划实施评估 & & & \\ +1.规划基础与现状分析 & 1.4资源环境承载能力和国土空间开发适宜性评价 & & & “双评价”专题 \\ +2.目标与战略 & 2.1发展定位 & & & \\ +2.目标与战略 & 2.2发展目标 & & & \\ +2.目标与战略 & 2.3发展战略 & & & \\ +2.目标与战略 & 2.4指标体系 & & & \\ +2.目标与战略 & 2.5发展规模 & & & \\ +3.国土空间格局 & 3.1总体空间格局 & & & \\ +3.国土空间格局 & 3.2产业发展格局 & & & \\ +3.国土空间格局 & 3.3居民点体系 & 3.3.1居民点体系空间结构规划 & & 居民点体系专题 \\ +3.国土空间格局 & 3.3居民点体系 & 3.3.2居民点体系等级规模结构规划 & & \\ +3.国土空间格局 & 3.3居民点体系 & 3.3.3居民点体系职能结构规划 & & \\ +3.国土空间格局 & 3.4村庄分类及发展指引 & & 乡镇域村庄发展与布局规划图 & \\ +4.规划分区与控制线落实 & & & 乡镇域国土空间规划分区图、乡镇域国土空间控制线规划图 & \\ +5.国土空间用地结构与布局优化 & & & & \\ +6.基础保障体系 & 6.1综合交通规划 & & 乡镇域综合交通规划图 & \\ +6.基础保障体系 & 6.2公共服务设施规划 & & & \\ +6.基础保障体系 & 6.3基础设施规划 & & 乡镇域基础设施规划图 & \\ +6.基础保障体系 & 6.4安全防灾设施规划 & & & \\ +7.历史文化与地方特色风貌 & 7.1全域景观风貌体系 & & 乡镇域历史文化保护规划图 & 历史文化与地方特色风貌专题 \\ +7.历史文化与地方特色风貌 & 7.2乡村风貌管控 & & & \\ +7.历史文化与地方特色风貌 & 7.3镇政府驻地风貌管控 & & 乡镇政府驻地历史文化保护规划图 & \\ +8.乡镇政府驻地用地布局 & 8.1发展方向 & & & \\ +8.乡镇政府驻地用地布局 & 8.2镇政府驻地发展规模 & & & \\ +8.乡镇政府驻地用地布局 & 8.3用地结构和布局 & 8.3.1空间结构 & & \\ +8.乡镇政府驻地用地布局 & 8.3用地结构和布局 & 8.3.2用地布局 & 乡镇政府驻地土地使用规划图 & \\ +8.乡镇政府驻地用地布局 & 8.4道路交通规划 & & 乡镇政府驻地道路交通规划图 & \\ +8.乡镇政府驻地用地布局 & 8.5住房建设和人居环境保障 & 8.5.1住房保障 & & \\ +8.乡镇政府驻地用地布局 & 8.5住房建设和人居环境保障 & 8.5.2服务功能优化 & & \\ +8.乡镇政府驻地用地布局 & 8.6公共服务设施规划 & & 乡镇政府驻地公共服务设施体系规划图 & \\ +8.乡镇政府驻地用地布局 & 8.7绿地与开敞空间用地布局 & & 乡镇政府驻地绿地系统和开敞空间规划图 & \\ +8.乡镇政府驻地用地布局 & 8.8市政基础设施及安全防灾设施规划 & & 乡镇政府驻地市政基础设施和综合防灾减灾规划图 & \\ +8.乡镇政府驻地用地布局 & 8.9“五线”管控与战略留白 & 8.9.1“五线”管控 & 乡镇政府驻地“五线”规划图 & \\ +8.乡镇政府驻地用地布局 & 8.9“五线”管控与战略留白 & 8.9.2战略留白 & & \\ +9.生态修复与国土综合整治 & 9.1生态修复 & & 乡镇域生态修复和综合整治规划图 & 生态修复专题 \\ +9.生态修复与国土综合整治 & 9.2农用地综合整治 & & 乡镇域增减挂钩实施引导图 & \\ +9.生态修复与国土综合整治 & 9.3建设用地综合整治 & & & \\ +10.规划传导与实施 & 10.1落实县级国土空间总体规划要求 & & & 规划传导与实施专题 \\ +10.规划传导与实施 & 10.2划分详细规划编制单元 & & & \\ +10.规划传导与实施 & 10.3城镇单元的传导与管控 & & & \\ +10.规划传导与实施 & 10.4村庄单元的传导与管控 & & 乡镇域村庄单元规划管控指引图 & \\ +10.规划传导与实施 & 10.5规划实施 & & & \\ +\hline +\end{tabular} +\end{table} + diff --git a/data/book/chapter05.tex b/data/book/chapter05.tex new file mode 100644 index 0000000..3404ff8 --- /dev/null +++ b/data/book/chapter05.tex @@ -0,0 +1,774 @@ +\chapter{国土空间规划的技术工具与方法} +技术工具与方法是国土空间规划的基础,通过调查勘测、系统评价、预测和标准化的制度是开展国土空间规划的前提,在此基础上运用以土地信息技术和遥感技术,实现空间决策支持及数据分析是国土空间准确、详实目的的必要手段,将各阶段、各级工作成果以“一张图”和与之相关的管理信息平台建设相结合,是国土空间体系规范化和标准化的保障。 + +\section{国土空间规划基础方法} +\subsection{调查勘测方法} +\subsubsection{1.调查勘测主要类型} +各级各类现状情况调查、分析研究是各类空间规划工作最基础性的步骤。在国土空间规划战略及体系规划中,同样各级各类要对开发利用现状信息资料进行分析和研究。国土空间规划量大面广,涉及土地、城市、乡村、田野等各类空间及社会、政治、经济等多个领域,它主要包括以下几种类型(见表5.1)。 + +表5. 1调查勘测类型表 + +\subsubsection{2.国土资源信息调查} +国土信息资源调查包括内容,来源和使用方式三方面工作。 + +(1)国土资源信息调查的内容(见表5.2)。 + +表5. 2国土资源信息调查内容 + +(2)国土资源信息来源 + +国土资源信息来源丰富,类型多样,具体内容(见表5.3)。 + +表5. 3国土资源信息来源 + +(3)国土资源信息的使用原则方式 + +国土空间规划阶段的国土资源信息获取,主要不应采取实地调查、实时监测、测绘勘探等一切从零开始的手段进行,而应主要采取收集、汇总、分析各有关部门、行业、单位和个人的调查研究成果的方式进行。但是,对于国土空间规划的底线控制指标,必须采取实地调查勘测的方法进行落地。例如,永久基本农田划定,就需要应用土地利用现状调查成果,建立已有基本农田划定成果与土地利用现状调查成果对应关系,将基本农田保护专题信息落到土地利用现状调查成果上,由基本农田划定部门进行核实、认定:依据土地利用总体规划成果,确定拟调出、调入的地块,并到实地察看定界,应用农用地分等成果,核实拟调出、调入基本农田的空间位置、数量、质量等级、地类等现状信息。 + +\subsection{系统评价方法} +\subsubsection{1.概述} +(1)新时期国土空间规划的技术要求 + +在旧的规划体系下,城乡、主体功能区和生态功能区等不同的规划由不同的部门负责编制,经常出现规划目标相抵触、内容相矛盾等问题。对于“多规”衔接复杂、部门协调困难、规划立法薄弱等难题。随着国家机构改革方案颁布、自然资源部成立,落实的一系列新规指引规划行业朝变更与发展的新方向迈进,规划学科正在经历前所未有的由传统工程学科向新型交叉学科、由单一主导向多规合一、由面状规划向空间规划转变的变革期(如图5.1所示)。 + +在国家空间规划体系改革和规划管理机构调整的背景下,进行国土空间规划基础知识教育,有助于了解学科发展的动态和方向俨然已成为相关学科教育的刚性需求。 + +学科发展带来了一系列知识体系上的变更,传统的城市规划已经不能满足当下以生态文明建设为主导的空间规划需求,规划类教育体系需要顺应时代的发展进行相应的调整与革新;规划类学科应当以学科知识体系的更新为基础拓展学科边界,在课程中渗透学科交叉的范畴。接受多元化的背景知识教育,才有助于拓宽学术眼界,丰富知识储备;行业的变革将不止于学术,逐步渗透到社会各个层面。 + +\textbf{图}\textbf{5.}\textbf{ }\textbf{1}\textbf{国土空间规划}\textbf{评价流程内容解析(}\textbf{笔者自会)} + +(2)技术评价体系的重要作用与意义 + +从规划层级体系上来说,以前主体功能区规划、城市规划、土地利用规划、乡村规划和各类专项规划等均涉及国土空间规划内容,统一的新的国土空间规划体系将其全部整合为统一的国土空间规划,分为全国、省、市、县、乡镇五级,真正建立了从全国到省、市、县、乡镇国土空间规划管控的完整规划体系。 + +《省级国土空间规划编制指南》和《市级国土空间总体规划编制指南》中对国土空间规划评价体系不同层级适用的评价方法做出了详细的分类和说明,这些不同的评价方法共同完善了国土空间规划评价体系。评价体系是国土空间规划的重要环节,是优化国土空间开发格局、合理布局建设空间的依据,也是对国土空间规划成果的支撑和预判。 + +(3)国空评价体系的主要内容 + +省级国土空间规划评价体系中包括三方面的评价分析:生态功能重要性评价、农业功能适宜性评价和城镇建设适宜性评价;市级国土空间规划评价体系包括三项,其中两项(资源环境承载力评价和国土开发适宜性评价)属于国土空间规划“双评价”的范畴,另外还包括灾害风险评估。 + +\subsubsection{2.省级国土空间规划的评价方法} +通过资源环境承载力和国土空间开发适宜性评价,分析区域资源环境禀赋特点,识别省域重要生态系统,明确生态功能极重要和极脆弱区域,提出农业生产、城镇发展的承载规模和适宜空间。具体评价方法及评估流程详见市级国土空间评价技术。 + +(1)生态功能重要性评价 + +主要内容 + +国土空间生态功能指生态系统与生态过程形成的、维持人类生存的自然条件及其效用,包括气候调节、水调节、土壤保持等。生态功能重要性指生态系统在发挥这些功能时的重要程度。生态功能重要性评价为全域评价,从生态保护底线、生态系统服务重要性、生态敏感性和生态修复必要性等四个方面评价生态功能重要性。其中,生态保护底线是生态功能重要性最高等级,而生态系统服务重要性、生态敏感性和生态修复必要性则根据其程度来进行重要性的评估。 + +作用与适用范围 + +生态功能重要性评价是对自然生境作出评价、实施措施的重要依据,是国土空间规划对生态系统与生态过程演进所作出的重要回应,对于构建景观生态安全格局、维持用地平衡、协调公共发展与自然关系有着重要的意义和作用。 + +(2)农业功能适宜性评价 + +主要内容 + +国土空间的农业功能是指以利用土地资源为生产对象,培育动植物产品从而生产食品及工业原料的一种功能。农业功能适宜性指农业空间构建过程中不同土地用于农业生产功能的适合程度。 + +农业功能适宜性评价是指农业生产适宜性,重点对耕地、园地、牧草地和其他适合农业种植业生产的土地利用类型,考虑其现状土地利用情况,对农业耕作的适宜程度,再结合土壤污染、土层厚度、障碍层、坡度等对农业耕作的限制程度进行评价。最终,将全域国土空间划分为农业功能适宜、较适宜、较不适宜、不适宜四个等级。 + +作用与适用范围 + +农业功能适宜性评价最重要的意义在于在农业生产中协调环境与经济二者的平衡,对农业面源污染治理、发展模式探索、问题及对策、政策体系构建等方面都具有支撑和预判作用,对于农业发展与城市建设之间关联性的探索也有着重要的意义。 + +(3)城镇建设适宜性评价 + +主要内容 + +城镇建设适宜性指土地用于建设开发的适合程度。城镇建设适宜性为全域评价,主要从地形坡度、生态敏感性、岩土稳定性、矿山占用、地质灾害等方面考虑城镇开发建设的自然适宜性。 + +作用与适用范围 + +城镇建设适宜性评价最终目的是服务于城市发展中最关键一环的城镇化建设, 区分城市范围内不同区域的城镇建设适宜性等级。打造五位一体战略布局,落实绿色、共享、创新、协调和开放的发展理念。 + +(4)案例:广东省实践 + +以广东省为例介绍实践经验,结合广东省资源环境本底特征。落实国家重大战略,明确省域重点区域的引导方向和协调机制,综合考虑数据可获取性,精选指标,构建广东省指标体系。 + +在生态保护重要性评价方面,生态系统服务功能重要性评价采用水源涵养、水土保持、生物多样性维护和海岸防护等指标,不采用防风固沙指标;农业生产适宜性评价采用土地资源、水资源、土壤环境、光热资源和气象灾害等指标,不采用盐渍化指标,同时在土地资源和气象灾害指标评价中增加考虑石漠化地区土层厚度、沿海地区台风灾害危险性的影响;城镇建设适宜性评价采用土地资源、水资源、气候舒适度、环境、地质灾害危险性和区位优势度等指标,在环境指标中增加放射性偏高场所的影响。 + +\subsubsection{3.市级国土空间规划评价方法} +市级总规要体现综合性、战略性、协调性、基础性和约束性,落实和深化上位规划要求,为编制下位国土空间总体规划、详细规划、相关专项规划和开展各类开发保护建设活动、实施国土空间用途管制提供基本依据。 + +(1)资源环境承载力评价 + +基本概念与意义 + +资源环境承载力探讨的是人类及其社会经济活动与资源环境协调发展的关系。资源环境承载力源于早期生态学领域所提出的承载力概念,逐渐演变为反映资源环境本底和经济社会活动间交互程度的科学度量概念。资源环境承载力泛指在自然环境和生态系统不受危害的前提下,一定地域空间的资源禀赋和环境容量所能承载的人口与经济规模。也可以将资源环境承载力理解为:基于一定发展阶段、经济技术水平和生产、生活方式,一定地域范围内资源环境要素能够支撑的农业生产、城镇建设等人类活动的最大规模。开展资源环境承载力评价具有3方面重要意义(见表5.4)。 + +表5. 4资源环境承载力评价的重要意义 + +评价内容 + +根据资源环境承载主体的涵盖范围划分,可将承载力评价分为两类:第一类是以某一具体的自然要素作为研究对象,即单要素承载力评价,主要包括土地、水、环境、生态等;另一类则是从要素整合的角度出发进行的综合承载力评价,如区域承载力等。资源环境承载力具有地域性、限制性、外部性、非线性和不确定性等显著特征,且越来越强调综合性与系统性。 + +如今,资源环境承载力评价已不再是仅仅关注某一单项资源或单一环境要素约束的可承载水平,而是强调人类发展对区域资源开发与利用、生态退化与破坏、环境损益与污染等多维度的综合影响,即对资源环境承载力的综合评估与集成评估。 + +评价原理 + +资源环境承载力评价旨在衡量区域资源环境本底条件对人类特定生产、生活的承载水平,其科学基础一方面在于资源可得性、最大持续产量与资源支持力;另一方面则是环境容量、环境吸收或同化能力,以及环境支撑力。资源环境承载力评价将经济社会同人口、资源、生态环境予以集成,探索经济社会与资源环境要素间的相互作用机理,建立要素间的定量关系。 + +资源环境承载力评价的核心内容之一,在于评价指标体系构建。科学、合理的资源环境承载力评价指标体系,不仅应涵盖特定区域经济社会、自然环境、资源生态系统中诸多要素的现状,还可以在时间和空间维度上进行比较,反映区域环境承载力的变化状况,以辅助决策。国际学界和诸多机构都提出了具有代表性的评价体系,其中最具影响力的为联合国环境规划署所提出的集合驱动力、压力、状态、影响和响应五大概念框架的DPSIR 模型。同时,基于评价指标体系研发评价模型亦是资源环境承载力评价的重要方面,当前较为常用的方法理论包括多要素叠置分析法、比较法、短板原理法等(见表5.5)。 + +表5. 5资源环境承载力评价方法 + +评价流程与方法 + +资源环境承载力评价侧重于区域综合承载力评价,即在多要素单项评价的基础上,运用空间叠加、线性加权等方法展开资源环境承载力集成评价(见表5.6)。 + +表5. 6资源环境承载力评价流程与方法 + +(2)国土空间开发适宜性评价 + +基本概念与意义 + +所谓国土空间开发适宜性,是指在资源环境承载力评价的基础上,在维系生态系统健康可持续的前提下,综合考虑资源环境要素、区位条件以及经济社会发展情况等,判定具体国土空间进行农业生产、城镇建设等人类活动的适宜程度。我们也可以将国土空间开发适宜性评价理解为:依据国土空间的自然、生态和社会经济属性,评价国土空间对预定功能用途的适宜与否、适宜程度以及限制状况。 + +国土空间开发适宜性反映了人类对国土空间的开发和建设用地的占用,强调以土地空间承载的多宜性来满足人类对国土空间开发的多样化、多层次需求。主要包括三个方面的内涵(见表5.7)。 + +表5. 7国土空间开发适宜性评价内涵 + +评价方法 + +国土空间开发适宜性评价是面向国土空间用途管制的综合评价,鉴于此,国土空间开发适宜性评价具有空间尺度大、评价目标多两大特点。首先,国土空间开发适宜性评价往往以行政区全域为评价范围,涉及国家、省域、市域等大尺度空间,侧重于宏观尺度的评价;其次,国土空间开发适宜性评价是一种多维度、多目标的技术手段,是集成建设用地适宜性评价、农业用地适宜性评价、生态适宜性评价等多功能用途的全域国土空间的综合性评价。开展国土空间开发适宜性评价需先进行土地资源、水资源、环境、生态以及灾害等自然要素单项评价,以确定农业、城镇和生态等不同适宜功能的承载等级,并划分各功能的备选区域,最后综合各修正因素以确定不同的适宜性等级(如图5.2所示)。 + +国土空间开发适宜性评价旨在衡量国土空间对支撑人类生产、生活的适宜程度,同样基于指标选取和模型构建。一方面,国土空间开发适宜性指标体系具有综合性、多维度、系统性等特征;另一方面,随着地理信息系统(GIS)技术、人工智能算法等新兴模型方法的引入,国土空间开发适宜性评价方法呈现出多元化特征。国土空间开发适宜性评价主要包括以下三个方面(见表5.8)。 + +表5. 8国土空间开发适宜性评价内容 + +图5. 2双评价技术流程图(资源环境承载能力和国土空间开发适宜性评价指南) + +应该注意的是,资源环境承载力评价、国土空间开发适宜性评价都不可能也不应该作为“精确科学”,其更重要的价值是作为一种我们必须尊重自然环境、追求空间适宜可持续用途的规划理念,其评价结果可以作为国土空间布局的重要参考,而不是僵化、固化的最终结论。 + +(3)“双评价”之间的内在关联 + +双评价间关系密不可分,既有价值取向的双向性,又有逻辑间的关联性。 + +“双评价”的差异性 + +从发展定位、管理取向和评价结果等方面来看,“双评价”之间存在着较大的差异性(见表5.9)。 + +表5. 9“双评价”的差异性比较 + +“双评价”关联性 + +同时,这两个评价在国空规划的体系中并列提及,说明“双评价”之间存在着密切的关联(见表5.10)。 + +表5. 10“双评价”的关联性分析 + +(4)案例:长沙市国土空间规划“双评价” + +以长沙市实践成果为例。面对近年来由于经济快速发展带来的生态环境和资源问题,长沙市以摸清国土空间自然资源本底、为国土空间规划提供基础为目的,对“双评价”开展了探索。从查找问题和短板、确定空间开发保护格局、确定开发规模和空间、划定生态控制线及打造高品质生态空间等方面探索了“双评价”在国土空间规划中的应用。 + +首先,构建评价模型的基本框架(如图5.3所示);其次,构建指标体系。根据地方适宜性、根据地方适宜性、数据可获得性、典型代表性与科学性等原则进行调整,针对 3 个不同的功能指向选取具有代表性的指标;再次,分析评价结果。生态重要性区域占比较高,呈“两屏多点”的结构、农业开发适宜度较高,呈“一区多片”的结构、城镇开发适宜程度较高,呈“一区两翼”的空间形态:最后,充分发挥“双评价”结果在长沙市国土空间规划中的指导作用。 + +\textbf{图}\textbf{5.}\textbf{ }\textbf{3}\textbf{长沙市“双评价”技术路径} + +(5)灾害风险评估 + +灾害评价主要表征区域灾害对农业生产和城镇建设的影响。灾害评估主要包括:选择气象灾害风险作为农业生产影响评价指标,通过干旱、洪涝、寒潮等灾害影响的大小和可能性综合反映(如图5.4所示);选择地质灾害危险性作为城镇建设影响评价指标,分别通过活动断层以及崩塌、滑坡、泥石流等地质灾害影响的大小和可能性综合反映(如图5.5所示);沿海地区还需进一步评价海洋灾害风险,并针对海洋牧场功能影响和滨海城镇建设影响分别遴选评价指标,通过海浪和海冰灾害危险性综合反映海洋灾害对海洋牧场功能的影响,通过风暴潮和海啸灾害危险性综合反映海洋灾害对滨海城镇建设功能的影响(如图5.6所示)。 + +图5. 4气象灾害评价步骤(作者自绘) + +\textbf{图 }\textbf{5.5}\textbf{地质灾害评价步骤(作者自绘)} + +\textbf{图 }\textbf{5.6}\textbf{海洋灾害评价步骤(作者自绘)} + +\subsection{预测分析方法} +\subsubsection{1.预测分析的原理} +广义说预测,是人们对未来或不确定事件的行为和状态做出的主观判断,立足点是过去和现在,目标点是未来,狭义地说,预测的实质是预测者选择和使用一种逻辑结构使过去、现在与未来相通,以达到描述未来状态和特征的目的。预测的主要原理(见表5.11)。 + +表5. 11国土空间预测分析原理 + +在国土空间各类规划的预测过程中,每一项内容的预测、每一种方法的选择,都要看是否符合上述预测的基本原理,如果违背预测的基本原理,预测也可能会变成“陷阱”。 + +\subsubsection{2.预测分析的程序} +国土空间规划预测分为确定的预测任务、确定预测因素、搜集和审核资料、选择模型进行预测、误差分析与模型实验、预测结果等重要程序(如图5.7所示)。 + +图5.7预测分析程序 + +\subsubsection{3.预测分析的方法} +国土空间规划预测的内容主要包括:产业、就业、人口、住房、土地、基础设施、交通、绿色空间等。其中就业和人口预测是核心,知道了就业和人口,土地、住房、基础设施、交通需求等的预测就变得相对简单。而人口分布又与就业机会高度相关,因而就业预测就成为关键的关键。但就业机会与产业发展高度关联,因此在国土空间规划预测过程中,产业发展和就业机会的预测就变得更加重要。从产业和就业的角度看,预测方法可分为直观预测法、因果预测法和时间序列预测法。其中,直观预测法一般用于定性预测,而因果预测和时间序列预测法主要用于定量预测。在选择预测方法时,一般考虑6个基本要素:预测的应用范围、预测的资料性质、模型的类型、预测方法的精确度、适用性和使用预测费用。对于较为常用的预测方法从以上6个方面进行比较。 + +直观预测法 + +直观预测法一般用于定性预测,常用的有头脑风暴法、专家会议法、主观概率法、特尔菲法等。特尔菲预测法也称专家匿名调查征询法,是目前预测中使用最为广泛的定性预测法。特尔菲法的基本思路是由预测工作小组对每一轮意见进行整理汇总,并作为参考资料再发给每位专家,供他们分析判断,作为提出新一轮意见的参考依据,如此多次反复,专家的意见日趋一致,使结论的可靠性增大,从而取得满意的预测结果。 + +使用特尔菲法必须坚持如下三条原则: + +第一条是匿名性。对被选中的专家要求保密,不让他们彼此互通信息,使他们不受权威、资历等方面的影响。 + +第二条是反馈性。在预测过程中,要进行几轮(3\textasciitilde{}5轮)征询专家意见。由于每一轮预测之间的反馈和信息沟通,可进行比较分析,因而能达到相关启发,提高预测准确度的目的。这样,征询过程通常都会呈现逐步收敛的趋势,容易集中各种正确的意见。 + +第三条是统计特性。特尔菲法的每次信息反馈,都要用数理统计方法进行整理分析。运用特尔菲法进行预测通常按以下程序进行(如图5.8所示)。 + +图 5.8特尔菲法进行预测流程 + +时间序列预测法 + +时间序列预测是以某一指标的时间序列反映的区域社会经济现象发展形态为依据,进行趋势外推,预测其未来发展趋势和水平的常用方法。时间序列预测的模型方法很多,较常用的有曲线(直线、抛物线、指数、对数)外推模型、指数平滑模型、移动平均模型、灰色预测模型等。其中曲线外推模型本质上就是回归预测法(即观测样本为时间序列数据)。 + +4.空间分区方法 + +(1)国土空间分区基本方法 + +国土空间分区是国土空间规划的重要基础,是国土空间优化配置的核心内容,是制定差别化国土资源管理政策的主要依据。国土空间分区一般以地域分异规律为理论基础,确定不同的理论和方法准则作为指导思想,并指导选取分区指标、建立分级系统、方法体系。针对国土空间分区的多主题集成和多尺度融合,采用自上而下的国土空间现状要素分析与自下而上国土空间功能表达相结合,形成一个有机整体,评价单元原则上不打破行政界线或产权界线的完整性,而分区实施过程中对评价单元界线与数据单元尺度不一致的情况可运用地理信息系统空间分析方法予以解决。几种常见的具体分区方法(见表5.12)。 + +表5. 12国土空间分区方法 + +在采用空间叠置法时,因不同地区情况有很大差异,在各类图件叠置时,不可能把多种图件同时叠置在一起,所以有一个前后顺序问题,叠置顺序可根据采取先重点后一般的方法进行。通常是将土地利用现状图作为叠置的底图,将同比例尺的永久基本农田保护图、生态保护红线图、城市开发边界图等以经纬网和明显地物为标志进行叠置套合,然后再叠置交通、水利、城市、乡村、旅游等专项规划图件。如果叠置后分区界线一致的,就直接作为分区界线;对于不重叠界线,需结合适宜性评价和资源环境承载力评价结果及规划要求和行业特点进行判别处理。 + +在采用空间叠置法进行用途分区划定的过程中,应注意以下三点:一是界线明确无争议的可直接采用,并同时在底图上标注分区名称;二是对界线不太明确或与实地有争议的,要与有关部门协商,并通过科学的研究和论证后确定;三是对一些重叠图,如风景旅游区内出现自然保护区,要根据其双重作用,以主要用途和资源保护优先的原则确定。对于某些部门为了自身利益而扩大的界线,如林业与果园之间的矛盾等,应本着生态环境优先、资源保护优先的原则,采用特尔菲法进行辅助判别。 + +除了上述分区方法以外,还要结合公众参与、创新理念分析和空间模型应用等综合分区思想,最终实现多主题集成和多尺度融合的国土空间分区。 + +(2)国土空间地域分区类型 + +国土空间地域分区通常是指在地市级以上大尺度的国土空间规划中,按照自然、生态、社会、经济及国土空间开发保护的一致性和管理方针的一致性,所划分的区域。地域分区方法是依据地域共轭性原理,以自然区划方法为基础,按照国土空间开发保护一致性和差异性的大小进行区域划分。这样划分的区域内部以某一类国土空间开发利用保护为主,但同时存在其他非主导的开发利用保护类型,实际上是一种不同开发利用保护类型的组合分区。地域分区中的同一区域不能在空间上断续分布,一般区域命名以地理差异为主命名。这种分区方法对认识区域内部不同地方的国土资源特点和确定不同地方国土资源开发保护方向无疑是非常有帮助的。 + +国土空间规划的地域分区除了按以上综合方法进行以外,还可以有以下三种类型(见表5.13)。 + +表5. 13国土空间分区方法 + +究竟应该采用何种类型地域分区,应当视国土空间规划的类型和主体任务而定。如果主要是整治自然环境,如流域治理,可以按照自然分区;如果主要是重大产业基地布局,可以采用经济分区;如果是为了更好地发布政府在国土空间规划中的作用,可以按照行政分区。但如果需要综合考虑自然生态和社会经济等的作用,可采用综合地域分区。 + +(3)国土空间用途分区类型 + +国土空间规划是全域全类型覆盖的,其用途分区类型必然不同于土地利用总体规划的用途分区类型,不同于城市总体规划的功能分区类型,也应该区别于传统的海洋功能分区。从空间覆盖范围和传统各类空间规划用途分区的深度来看,国土空间用途分区类型应该是土地、城市、海洋等各类空间规划用途分区类型的系统整合和创新。在具体操作层面上,可以土地利用总体规划的用途分区为基础,充分吸收城市总体规划功能分区和海洋功能分区的成果,相互之间优势互补,形成全新的国土空间用途分区类型。按照这种思路,国土空间用途分区类型从城市到乡村再到海洋,在一级层面至少应当包括以下基本的用途分区类型:城镇区、村落区、采矿区、农地区、林地区、自然环境保护区、水资源保护区、历史遗产保护区、观光休养区、海洋农渔业区、海洋非农利用区、海洋保护区等。在一级分类之下,可根据空间尺度和用途管制的需要,续分二级甚至三级。例如,在城镇区续分居住区、工业区、仓库区、对外交通区等,还可以有行政区、商业区、文教区、休养疗养区等;在农村地区可以续分基本农田保护区、基本草场保护区、一般农地区;林地区可以续分生态林区、生产林区等。 + +\subsection{系统制图方法} +\subsubsection{1.制图数学基础} +平面坐标系统采用 CGCS2000坐标系;高程基准采用1985国家高程基准;地图投影采用高斯-克吕格投影。1:2000、1:1000和1:500等比例尺成果按3°分带,图件比例尺小于1:10万,采用6°分带,平面坐标单位采用“米”。 + +\subsubsection{2.图件比例尺} +国土空间规划的制图比例尺从乡镇到全国依次为:1:5000、1:1万、1:2.5万、1:5万、1:10万、1:25万、1:50万、1:100万等8种,具体视各级规划区域的空间范围大小而定。通常情况下,国家规划图件比例尺为1:100万,省级规划图件比例尺为1:50万,市级规划图件比例尺为1:10万,县级规划图件比例尺为1:5万,乡镇级规划图件比例尺为1:1万,中心城区规划图件比例尺1:1万。 + +\subsubsection{3.图件内容} +国土空间规划图主要反映规划期内国土空间开发保护引导和调控,重点是国土空间用途分区和工程设施建设,将国土空间用途管制落实到每一个地块图斑,实现国土空间开发格局控制和引导。 + +\subsubsection{4.图件种类} +国土空间规划图件包括必备图件和可选择图件。必备图件作为国土空间规划必须编制的图件,可选择图件根据需要选择编制。 + +必备图件包括:①国土空间利用现状图;②国土空间规划图及永久基本农田、生态保护红线、城镇开发边界、重大工程设施建设等专题规划图件。 + +可选图件包括:规划区位图、国土空间开发适宜性评价图、资源环境承载力评价图、国土空间整治图、国土空间生态修复图、遥感影像图和数字高程模型图等。 + +\subsubsection{5.制图的地理要素和注记} +地理要素主要包括行政界线、政府驻地、高程特征点和等高线等;注记主要包括各级政府驻地、公路、铁路、机场、港口、水利设施和河流湖泊等,在制图过程应正确和合理标注,一般同一图像内注记字体种类以不超过4种为宜,界线和等高线按分级显示。 + +\subsubsection{6.图幅配置} +国土空间规划图的图幅配置内容应包括图名、图廓、地理位置示意图、指北针与风向玫瑰图、比例尺、图例、署名和制图日期等要素。制图应注意图幅的平衡和饱满。 + +\section{国土空间规划空间分析技术} +国土空间属于复杂空间系统,编制过程是规模巨大的系统工程,涉及大量的空间数据,如物理层和生物层包括从基础岩层到大气环境、从景观生态到植被野生生物,从自然灾害到景观资源等;经济层和文化层包括土地利用、交通运输到街区模式、从人文历史到人口分布、从基础设施到发展潜力等数据。为提高国土空间规划决策的科学性,及规划实施后的有效管理,将全球定位系统 GPS(Global Positioning System)技术、遥感技术(Remote Sensing, RS)和地理信息系统(Geographic Information System,GIS)技术和应用在国土规划中成为必然趋势。 + +RS技术是支撑国土资源调查的最基本技术,同时RS 技术也是国土空间规划的实施监测管理的必要技术手段之一;GPS技术主要服务于国土资源调查的定位需求,同时支撑规划实施过程中的定位需求;GIS是国土空间规划中最重要的技术支撑,空间数据的存储、统计、分析、规划、推演等都需要建立在GIS平台上的国土空间规划数据库的支撑,特别是国土空间规划“一张图”,就是以GIS数据库形式呈现的。 + +\subsection{地理信息系统(GIS)空间分析} +地理信息系统出现于20世纪60年代,得益于80年代和90年代UNIX工作站和个人计算机等技术的飞速发展,到20世纪末得到普遍应用,是以采集、存储、管理、描述、分析地球表面和地理分布有关的数据的信息系统(陈述彭,1999),具有数据录入、编辑、修改、信息查询和统计、测量和空间分析、模拟和专题地图制作等功能。空间分析技术是地理信息系统区别于其他信息管理系统的标志在国土空间规划工作中,运用GIS进行输入、统计、绘图外,更主要的是运用GIS进行空间分析,进行规划决策。空间分析技术主要包括叠加分析、缓冲区分析、网络分析、空间统计分析、三维空间分析等。 + +\subsubsection{1.空间叠加分析} +叠加分析(Overlay analysis)是GIS中的一项非常重要的空间分析功能,指在统一的坐标系下将同一区域、同一比例尺的两组或两组以上的多边形要素的数据文件进行叠置,叠加不仅产生新的空间关系,还将输入数据层的属性联系起来,产生新的属性关系,能够发现多层数据间的相互差异、联系和变化等特征,并提取具有多重指定属性特征的区域,或者根据区域的多重属性进行分级、分类。叠加分析的目标是分析在空间位置上有一定关联的空间对象的空间特征和专属属性之间的相互关系。 + +GIS叠加分析分为基于矢量数据的叠加分析和基于栅格数据的叠加分析两大类。矢量数据叠加分析包括视觉信息叠加,点、线、多边形与多边形叠加等,栅格数据属于数学运算的叠加运算,在GIS中称为地图代数。地图代数功能有三种不同的类型:基于常数对数据层面进行的代数运算;基于数学变换对数据层面进行的数学变换(指数、对数、三角变换等);多个数据层面的代数运算(加、减、乘、除、乘方等)和逻辑运算(与、或、非、异或等),有时简称为栅格计算器。在国土空间规划编制过程中主要运用叠加分析进行建设适宜性分析,方案比较、优化等,便于提高规划的科学性。 + +\subsubsection{2.缓冲区分析} +缓冲区分析(Buffer Analysis)是为了识别某一地理实体或空间物体对其周围地物的影响度而在其周围建立的具有一定宽度的带状区域。空间物体可以是点、线、面等,是用来解决邻近度问题的空间分析工具之一。邻近度描述了地理空间中两个地物距离相近的程度。缓冲区分为匀质缓冲区和非均质缓冲区两种,均质缓冲区是空间物体与邻近对象只呈现单一的距离关系,缓冲区内各点影响度相等,如服务范围的划定。非均质缓冲区是空间物体对邻近对象的影响度随距离变化而呈不同强度的扩散或衰减,如道路噪声影响范围随距离地增大而减弱的范围及程度等。 + +\subsubsection{3.网络分析} +网络分析(Network Analysis)是矢量数据特有的空间分析方法。网络模型是现实世界中网络系统(如生态网络、游憩网络、交通网、市政基础设施网络等)的抽象表示,目的是研究网络的结构和功能,模拟分析资源在网络上的流动和分配情况实现对网络结构及其功能等的优化。国土空间规划的应用主要包括路径分析、资源分配、连通分析、地址配置等。 + +\subsubsection{4.空间统计分析} +空间统计分析(Spatial Statistical Analysis)。地理信息要素的属性(面积、长度、朝向、近邻关系等)及位置是 GIS 数据的固有信息,可用于创建视觉上可分析的地图,空间统计分析就是在此固有信息的基础上,研究与空间位置相关的事物和现象的空间关联和空间关系,有助于从 GIS 数据中提取只靠查看地图无法直接获得的额外信息,例如各属性值如何分配,数据中是否存在空间趋势或者要素是否能够形成空间模式。与提供单个要素信息的查询功能不同(如识别或选择),统计分析可整体显示一组要素的特征。在国土空间规划中主要应用于景观生态学、土地利用空间自相关分析以及土地资源的适宜性研究等,是科学分析利用土地资源的重要技术手段。 + +\subsubsection{5.三维空间分析} +三维空间分析(3D Analysis)是指国土空间规划中的地形分析及三维空间的可视化分析技术。包括数字高程(DEM),坡度、坡向计算和剖面分析,阴影分析、水文分析,谷脊特征分析、可视域分析等,为国土空间规划中进行区域、流域空间分析,城市的天际线、视线、体量、高度、通视、淹没等规划分析,为各尺度国土空间规划提供依据。 + +\subsection{遥感(RS)技术} +遥感技术作为一种空间信息技术,对于国土空间规划中所面临的基础资料、人口、资源和环境等问题,都可以借助于遥感技术进行调查、监测和评价,主要用于资源的调查与评价、环境的监测与评价、规划的实施监测(吴次芳等,2003)。资源调查和评价包括用于生态资源、土地利用资源、水资源、矿产资源、资源的调查和评价;生态环境的监测与评价包括用于大气环境监测、水环境监测、土壤环境监测、城乡污染监测的遥感信息获取、定量分析、灾情预报与监测等方面;规划的实施监测包括用于土地利用变化监测、检查规划批准项目的落实情况和监测未经批准进行建设占地的案件,以及监测违反土地利用总体规划的违法用地情况。 + +由于遥感技术的应用,使得规划中的外业工作周期缩短、成本降低,极大地提高了工作效率。遥感技术能够提供及时、详细、准确、宏观视野、多层面的地表信息,弥补了以往规划技术方法的不足,同时遥感技术为国土空间信息系统提供了强大的查询、分析、统计的基础数据,是国土空间规划不可或缺的基础资料。 + +\subsubsection{1.遥感技术的概念} +遥感(Remote Sensing),从远处探测、感知物体或事物的技术。即不直接接触物体本身,从远处通过各种传感器探测和接收来自目标物体的信息,经过信息的传输及其处理分析,来识别物体的属性及其分布等特征的综合技术。按照遥感的工作平台分类可以分为地面遥感、航空遥感、航天遥感;按照探测电磁波的工作波段分为可见光遥感、红外遥感、微波、激光遥感等;按照遥感应用的目的可分为大气遥感和环境遥感(农业遥感、林业遥感、地质遥感等);按照资料的记录方式可分为成像方式、非成像方式;按照传感器工作方式可分为:主动遥感、被动遥感。 + +遥感技术具有全局视野、可进行重复观测、一般不会干扰对象、数据采集可避免人工采样偏差等优点,特别是还可以观测一些由于自然或政治因素无法访问的区域。但是遥感只提供一些空间、光谱和时间信息,仅提供物理、生物或社会科学研究所需要的信息,遥感信息处理过程的图像处理、解译等人为参与过程可能会引起一定的误差。 + +\subsubsection{2.遥感图像处理技术} +遥感图像处理技术包括彩色、图像校正、图像变换和增强、多平台数据融合技术等,为遥感信息提取做准备。 + +(1)彩色合成技术。为了充分利用色彩在遥感图像判读和信息提取中的优势,常常利用彩色合成的方法对多光谱图像进行处理,以得到彩色图像。单波段图像显示为黑白图像,根据色彩合成原理进行对多光谱图像进行合成,波段决定色调,可以将不同波段的图像合成为彩色图像。设定的波段影像的色调与实际地物色调是否一致,决定图像是真彩色图像和假彩色图像(伪彩色);也可以通过密度分割方法密度分割将原始图像的灰度值被分成等间隔的离散的灰度级(层),然后对每一灰度级赋新灰度值或颜色,从而得到一幅密度分割图像,形成的彩色图像为伪彩色图像。 + +(2)遥感图像校正技术。为减少遥感图像因传感器本身性能、地形及光照条件变化、大气散射和吸收等因素引起的辐射误差影响,二进行的校正为辐射校正。为避免卫星在运行过程中,由于姿态、地球曲率、地形起伏、地球旋转、大气折射、以及传感器自身性能所引起的几何位置偏差,图像上像元的坐标与地图坐标系统中相应坐标之间的差异引起的误差进行的矫正技术为几何校正。为将同一地区的不同特性的相关影像(如不同传感器,不同日期,不同波段或传感器在不同位置获取的同一地区地物)在几何上互相匹配,即实现影像与影像间地理坐标及像元空间分辨率上的统一而进行的校正为图像配准。将两幅或多幅影像拼在一起,构成一幅整体影像的技术过程为影像镶嵌技术。 + +(3)图像变换和增强。图像变换是图像空间的图像以某种形式转换到另外一些空间(如频率域,图像能量集中分布在低频率成分上,边缘、线状信息反映在高频率成分上)或称为变换域,包括傅立叶变换、统计变换、 彩色变换等,目的在于使图像处理问题简化,有利于图像特征提取,有助于从概念上加强对图像信息的理解,利用变换域中特有的性质方便地进行一定的加工,再转换回图像空间得到所需的结果。遥感图像增强是为特定目的,突出遥感图像中的某些信息,削弱或除去增强感兴趣目标和周围背景图像间的反差。增强技术不能增加原始图像的新的信息,但会使图像更易判读,属于是计算机自动分类一种预处理方法。 + +(4)多平台数据融合技术。遥感数据具有多波段、多时相、多平台的特点,多波段图像对应像元进行代数运算,将不同类型传感器获得的同一地区的数据进行空间配准后,将各数据中的优势或互补性有机结合起来进行融合。目的是保留光谱信息和提高几何特征。 + +\subsubsection{3. 遥感信息提取技术} +遥感信息提取是将空间规划数据识别为空间信息的过程,包括目视解译、自动分类,定量化提取等方法,通过专题制图过程完成空间信息的存储和表达。解译是根据遥感图像的影像特征,结合地物光谱特性、专业知识进行比较、推理、判断和综合分析,最后提取出关注的信息,并进行专题图绘制的过程。 + +(1)目视解译是使用眼睛目视观察,借助一些光学仪器或在计算机显示屏幕上,凭借丰富的解译经验,扎实的专业知识和手头的相关资料,通过人脑的分析、推理和判断,提取有用的信息的过程。自动分类 + +(2)自动分类。遥感图像分类就是利用计算机对遥感图像中各类地物的光谱信息和空间信息进行分析,选择特征,并用一定的方法将特征空间划分为互不重叠的子空间,然后将图像的各个像元划归到各个子空间中去,或者说对图像所有像元进行分类。其中非监督分类是指在没有先验类别知识的情况下,根据图像本身的统计特征对图像所有像元进行分类。其分类的结果只是对不同类别达到了区分,但并不能确定类别的属性。其类别的属性是通过分类结束后实地调查或其他资料确定的。监督分类是遥感图像上地物的类别已知的前提下,在已知类别的训练场地上提取各类别的训练样本,通过选择特征变量、确定判别函数或判别规则把图像中各个像元划归到相应的类别中去的分类方法。 + +(3)定量化提取。目视解译、自动分类等都属于定性信息提取,用来确定某个地物是什么、空间属于什么类型。相对于定性信息提取,定量遥感信息提取是从地物反射或发射的电磁辐射里,推演得到空间、地物某些特征定量化描述的方法。简单表达就是在遥感获取的各项电磁辐射信号的基础上,通过数学的或者物理的模型,将遥感信息与观测地表目标联系起来,定量地反演或推算目标的各种自然属性信息的方法,定量遥感是遥感技术的重要发展方向之一。 + +\section{国土空间规划决策方法} +\subsection{空间决策博弈方法} +地理设计(Geodesign,省级国土空间规划编制指南,附录A19)框架指出决策过程直接或间接地影响了国土空间的结构、布局与质量。从决策理论的来看,国土空间规划方案存在着“目标是否合理,方案是否可行,代价是否最小,副作用是否最小”的问题,因此,空间决策问题的研究对于自然资源优化配置,推动国土空间利用方式由粗放型向集约型转变,实现社会效益、经济效益和生态效益协调发展具有十分重要的意义。 + +国土空间是复杂空间系统,处理复杂系统的方法是将复杂空间划分为若干个子系统,并在完善子系统的基础上,对子系统之间的冲突进行博弈,形成最终的空间规划方案。国土空间规划涉及诸多的国土空间利用利益相关者,对空间系统的目标、实施策略都有着不同的需求和目的,所以地理设计框架提供的动态协同方法,非常适用于解决国土空间决策博弈问题:地理设计框架将国土空间利用的利益相关者分为政府、专家、居民、开发建设者,与规划人员、研究人员和信息技术支持人员等一起,将国土空间规划过程分为分析、设计、实施三个迭代过程与表达、过程、评估、改变、影响、决策六个过程,并在过程中对利益相关者等分别设定了角色和方法,决策过程中设定了在流程之间和在迭代过程之间的博弈方法,为高效地决策提供了框架和流程。 + +\subsection{空间决策支持系统} +Geodesign HUB国土空间规划设计涉及现状的、规划的、推演的海量空间数据,涉及大量的利益相关者,决策过程极其复杂,因此需要开发基于信息技术的空间决策支持系统。决策支持系统(Decision Support System,DSS)是在管理信息系统(Management Information System,MIS)基础上增加了模型库及管理系统,借助计算机技术,运用数学方法、信息技术和人工智能为管理者提供了分析问题、构建模型、模拟决策过程及评价最终效果的决策支持环境(闫鑫,2016),由人机界面、数据库及其管理系统、模型库及其管理系统三单元结构组成。 + +随着信息科学理论的不断发展与进步,决策支持系统集合了专家系统、遗传算法、神经网络等技术,将原有的三单元结构加以完善,逐渐添加方法库、知识库及其各自的管理系统,使决策支持更加智能。为增加DSS的空间数据巨册功能,可以将GIS 和 DSS 相结合,形成空间决策支持系统,为国土空间规划的一大技术保障。为在地理设计框架下,进行空间系统博弈,可以开发基于地理设计框架的空间决策系统为Geodesign HUB。 + +\subsubsection{1.国土空间规划决策支持系统实现方式} +国土空间规划的计算机辅助决策支持一般有三种方式(见表5.14)。 + +表5. 14计算机辅助决策支持方式 + +基于数据形式的决策支持是传统的辅助决策支持方式;基于模型和方法形式的规划设计决策支持是目前空间决策的常用手段。知识主导形式的决策支持是最为先进的辅助解决支持方式,由于引入了利益相关者参与决策,将大幅度地提高国土空间规划效率。 + +\subsubsection{2.国土规划空间决策的开发} +系统分析。系统分析需采用系统工程的方法,进行需求分析和可行性分析。结合空间决策过程的复杂性进行综合分析,制定可行方案,为系统设计提供依据。在需求分析中总的来说有三个问题(见表5.15)。 + +表5. 15空间决策开发系统分析问题 + +据此进行可行性分析并提出方案。空间决策支持系统要求将云技术,基于Web的GIS 与 DSS 相结合,根据功能、时间和经费等进行一体化、模块化设计开发,可通过 GIS 的组件结合 DSS 工具进行开发。 + +系统设计原则: + +系统主要遵循科学性、实用性、规范性、可扩展性的设计原则(见表5.16)。 + +表5. 16空间决策开发系统设计原则 + +系统实现。决策系统旨在支持协作和博弈,以达成协同。应尽可能地简单:易于学习、设置、使用,特别是易于理解。决策系统的实现包括数据准备、各协作子系统的建立和系统的整体集成,系统应该是基于云的、免费和开放访问的、开放的平台,可以通过API与其他工具和模型进行链接。数据库管理系统现有的 主流GIS 数据库系统;模型库系统一般利用程序设计语言自行进行设计与开发;地理数据分析系统可利用 GIS 软件所提供的接口进行调用。人机交互系统要通过API实现与其他系统的调用接口,设计良好的界面,并嵌入集成式的 DSS 语言支持。实现的系统应经过系统测试与评价,形成最终可靠灵活的决策支持系统。 + +\subsection{空间模拟与仿真技术} +对国土空间规划方案进行决策时,需要先对其进行演进评估。由于方案的实施目标和策略不同,会对国土空间产生不同结果,特别是参与规划方案决策者的利益相关者的目标差异,会导致决策过程高度复杂,且实施结果的不确定性大大增加,降低决策的科学性和并且可实施性产生偏差。为解决此问题,需要通过空间的模拟与仿真对国土空间规划方案进行推演、模拟仿真,便于直观科学地决策。 + +当前主流的空间推演模型主要包含基于方程的模型(Equation-Based Model)、系统动力学模型(SD,System Dynamics Model)、元胞自动机模型(Cellular Automata Model)、基于主体模型(Agent-Based Model/ Multi-agent Model)及综合模型。从不同技术对国土空间变化预测的时空维度上,可以大致划分为:国土空间需求预测模型、国土空间预测模型和时空耦合的综合模型三类。 + +\subsubsection{1.系统动力学} +系统动力学(System Dynamics, SD)模型可以反映系统(或子系统)的信息、物质、能量的流动结构与反馈关系。SD模型始于20世纪50年代,由Forrester基于工业企业管理过程中关于系统库存控制、生产调节、劳动力雇佣等复杂关系提出。在构建流程上,SD模型需要将复杂系统的变量进行抽象和符号化,在分析变量之间的信息反馈关系的基础上搭建变量之间的因果关系方程,以此研究和分析复杂系统中要素的行为变化。相对于基于方程的统计模型,SD模型擅长处理具有长期性和周期性的问题,并且可以充分考虑变量之间可能存在的包括高阶、非线性和时变性等反馈机制。因此在分析社会经济变化对国土空间需求的影响以及政策情景预测方面具有一定的优势。目前SD模型已经广泛应用到国土空间规划的土地利用需求的预测中,分析过程主要由下述步骤组成。 + +定义系统。定义系统就是确定国土空间规划发展的目标和解决的问题。通过对规划方案的分析,预测规划的空概念方案可能出现的期望状态,然后分析规划的空间系统有关特征,最后确定空间方案的问题,并描述与问题有关的状态,估计问题产生的边界与范围、选择适当的变量等。 + +分析因果关系。对于国土空间规划的演进模拟,SD模型是把研究的对象作为空间系统来处理的,依据反馈动力学原理,将反馈环定义为空间系统的基本组件。多个反馈环的组合构成了空间复杂系统。空间系统在与外界的相互作用以及内部各要素之间的作用,使得空间系统总处于不断变化之中,SD通过因果关系图分析空间系统各子空间要素之间作用的因果关系。因果关系的分析将空间系统的要素通过箭头表示。然后根据空间系统边界各个子空间要素之间的因果关系形成反馈环。 + +建立空间系统流图。SD模型流图包括流位(空间系统内部的定量指标)、流率(描述系统实体在单位时间内的变化率)、流线(表示对系统的控制方式)和决策机构(由流位传来信息所确定的决策函数)等。 + +构造方程与运行模型。根据空间系统的对应关系构造符合时空变化的方程,然后利用计算机仿真语言,将SD模型转化成系统的仿真模型。 + +结果分析。借助计算机软件,输入对应参数以及相关控制语句运行建立的空间仿真模型,根据得的结果,再对结果进行分析迭代,若存在问题可对模型进行修正,一直到得到满意的空间推演结果。 + +\subsubsection{2.元胞自动机} +元胞自动机模型(Cellular Automata Model),简称CA模型,在国土空间模拟中的应用始于20世纪60-70年代,主要应用于城市空间扩散模型的研究。20世纪80-90年代以来,CA模型在土地利用/土地覆被变化(简称LUCC)模拟的理论框架基本形成,而自90年代以来,CA模型被广泛应用LUCC模拟,并取得丰硕的研究成果。CA模型框架相对简单和开放,加之具备强大的复杂计算能力,能够从微观尺度上构建决策规则并模拟空间复杂的时空动态变化过程。 + +CA模型由四个部分组成:元胞(Cells)、状态(States)、邻域(Neighbors)和规则(Rules)。CA的基本运行法则是:判断元胞自身与领域的状态,并依据所制定的局部规则确定下一时刻状态。CA模型中的转换规则是影响国土空间演进模拟精度的重要部分。目前,诸多学者采用不同的方法挖掘国土空间转换规则,主要包括:从驱动土地利用类型转移的影响因素出发,通过引入如人工神经网络、支持向量机和随机森林等算法提高规则制定的准确性;从土地利用变化类型及其空间关系出发,在挖掘地类之间相互作用关系的基础上,增加局部土地利用竞争关系,以提高模型预测的精度。 + +CA 模型在模拟土地利用变化时具有一定的优势:第一、作为一种空间动力学模型,基于“自下而上”的建模思路,能够从微观尺度上构建决策规则并模拟空间复杂的时空动态变化过程;第二、具备复杂且强大的计算能力,可以模拟国土空间变化中的复杂行为;第三、CA模型的离散性、同步性和局部性等特征,在处理大尺度的国土空间数据时具备并行计算的能力。所以,国土空间变化作为一种复杂的时空动态变化过程,CA模型与GIS技术的结合增强了模型对土地利用在空间上的模拟和分析能力。 + +\subsubsection{3.多智能体} +多智能体系统(Multi-Agent System, 简称MAS)理论和技术是在复杂适应系统理论及分布式人工智能(distributed artificial intelligence, DA1)技术的基础之上发展起来的,目前已经成 为一种进行复杂系统分析与模拟的思想方法与工具。 + +基于空间的多智能体一般都是借助于CA的思想,Agent分布在规则的二维网格上,二维网格相当于CA的元胞空间。利用Agent的局部连接规则、函数及局部细节模型,建立国土空间复杂系统的整体模型。空间Agent可以根据一定的移动规则在二维网格中自由移动。多个Agent可以占据同一个网格点,不同的网格点上可以拥有不同数量的Agent。空间Agent表现一定的智能性,具有空间决策能力和学习能力,能够对环境的变化做出适应性的反应,基于以上特点,MAS非常适合进行国土空间系统的模拟与仿真,进行演进分析。国土空间系统是一个典型的复杂系统,空间的动态发展是基于微观空间个体相互作用的结果。MAS的核心思想就是微观个体的相互作用能够产生宏观全局的格局。通过观察微观Agent与系统之间及Agent之间的交互作用,来研究系统层面整个区域的国土空间的演化过程,在国土空间规划的复杂模拟中,可以建立通过社会、经济、政策等因子反映不同类型智能体的决策偏好,为不同类型的智能体定义行为以实现智能体之间、智能体与环境之间的交互。 + +\section{国土空间规划“一张图”系统} +2019年7月18日,自然资源部办公厅为贯彻共中央 国务院《关于建立国土空间规划体系并监督实施的若干意见》精神,落实《自然资源部关于全面开展国土空间规划工作的通知》要求,依托国土空间基础信息平台,发布《关于开展国土空间规划“一张图”建设和现状评估工作的通知》自然资办发〔2019〕38 号。在通知中提出,要求依托国土空间规划基础信息平台,全面开展国土空间规划一张图建设和市县国土空间开发保护现状评估工作。 + +\subsection{国土空间规划“一张图”建设步骤} +国土空间规划“一张图”是指“一张现状底图+ 一张规划蓝图+一张管理用途”。一张现状底图是指以第三次全国国土调查成果(以下简称“三调”)为基础,融合规划编制所需的自然资源、社会经济、城乡建设、基础设施以及其他相关数据与信息, 形成以2000国家大地坐标系(CGCS2000),同时高程基准采用“1985国家高程基准”等坐标统一、边界一致的全国范围内的一张底图, 并进行一定时间间隔的时空数据更新。一张地图的建设能够有效支撑规划编制、 实施及监测等规划全周期。一张规划蓝图是指在一张底图的国土空间规划数据系统基础上,将规划成果通过标准转换、数据匹配、底图一致等工作,将规划成果向本级平台入库,通过数据库中多重叠加各类国土空间规划成果的图层数据,形成国土 空间规划的“一张图”,并定期通过更新规划修改、审批等信息,实现国土空间规划“一张图”的动态更新;一张管理用图是指以规划一张蓝图为指导,将各类国土空间开发与保护活动纳入一张管理业务图,管理好国土空间规划实施全部业务活动,实现国土空间治理的全面监管,促进国土空间规划的实时监测与动态管理。 + +\subsubsection{1.统一的底图} +以第三次全国国土调查成果为基础,整合规划编制所需的空间关联现状数据和信息,形成坐标一致、边界吻合、上下贯通的一张底图,用于支撑国土空间规划编制。以“三调”成果为基础,整合空间规划所需的 相关数据和信息,包括基础测绘、资源调查、资源感知、城乡建设、资源管理、社会数据、经济数据、人口活动、城乡建设等多元数据,通过数据融合、集成、汇总、叠加等过程形成坐标一致、边界统一的现状“一张图”底图。 + +“三调”成果数据中符合入库要求的直接入库,不能直接入库的各类数据需按照国土空间用途分类进行数据转换,空间关联数据需通过细化与补充调查后才能入库。其他入库数据主要分为四大类,现状类数据:土地利用现状、遥感影像、基础地理信息数据等;管控类数据:土地利用规划、功能区划、专项规划等;管理类数据:自然资源确权登记、生态修复、测绘管理等;社会经济类数据:社会、经济、人口、产业、行政机构等。现状数据通过图斑处理、图层构建、字段建立、属性赋值、冲突分析、图数核对、优化完善、整合成库等过程,构建统一数据格式、坐标标准、属性表达等的现状底图。 + +\subsubsection{2.国土空间规划“一张图”的构建} +各地自然资源主管部门在推进省级国土空间规划和市县国土空间总体规划编制中,将批准的规划成果向本级平台入库,作为详细规划和相关专项规划编制和审批的基础和依据。经核对和审批的详细规划和相关专项规划成果由自然资源主管部门整合叠加后,形成以一张地图为基础,可层层叠加打开的国土空间规划“一张图”,为统一国土空间用途管制、实施建设项目规划许可、强化规划实施监督提供支撑。 + +以现状底图为基础,进行“双评价”工作。通过评价区域资源环境承载能力,根据生态环境保护、农业生产、城镇建设发展的功能导向,划定区域资源环境承载能力等级,总结其环境优势与生态环境发展禀赋条件。通过评价区域国土空间开发适宜性,划定生态保护重要性分区以及农业生产和城镇建设适宜性分区,探测国土空间开发的风险区域,综合分析区域国土空间开发的潜力。“双评价”的成果主要用以指导“三区三线”的划定,即城镇空间、农业空间与生态空间;生态保护红线、永久基本农田保护红线和城镇开发边界。基于此,叠加国土空间规划的“五级三类”规划图层,总体规划层面包括国土空间格局、城乡统筹结构、重大基础设施廊道、城镇建设区、地下空间布局、产业发展分区、国土空间综合整治等; 详细规划层面包括用地布局、公共服务设施、道路交通规划等要素;专项规划包括资源利用类、 要素配置类、安全保护类、城市特色类等。叠合的要素通过数据集成、处理、融合、校正等步骤,形成统一用地分类标准、统一数据标准和统一事权的规划蓝图。 + +\subsubsection{3.建设国土空间信息平台} +自然资源部门建设国土空间基础信息平台,并与国家级平台对接,实现纵向联通,同时推进与其他相关部门信息平台的横向联通和数据共享。基于平台,建设从国家到市县级的国土空间规划“一张图”实施监督信息系统,开展国土空间规划动态监测评估预警。管理用图一般是基于国土空间基础信息平台建设的“一张图”规划实施监测系统,具有规划实施监测与评估的作用,并涵盖规划从编制、审批、 实施等全过程。它可有效应用于自然资源管理与开发、空间用途管制、生态修复、耕地保护、 确权登记、执法管理等方面,以期达到规划编制更智能、规划实施更精准、规划管控更科学的总体目标。 + +\subsection{国土空间规划“一张图”实施路径} +\subsubsection{1.支撑规划编制的底图} +2019年,自然资源部颁发的《关于开展国土空间规划“一张图”建设和现状评估工作的通知》中,要求全国国土空间规划的开展以第三次全国国土调查成果为基础,整合规划编制所需的空间关联现状数据和信息,形成坐标一致、边界吻合、上下贯通的一张底图,用于支撑国土空间规划编制。并强调,国土空间规划编制及其中三条控制线、自然保护地和历史文化保护范围的划定等内容必须与一张图底图相对应。为了保障数据的实效性,要求底图随年度土地变更调查、补充调研等工作及时更新。“一张底图”的形成是工作开展的第一步,需要根据国土空间规划编制和现状评估的具体要求,梳理并形成数据资源目录。 + +\subsubsection{2.开展评估“一张图”的流程} +以一张底图为基础,借助信息化手段,依据《国土空间开发保护现状评估技术指南》工作要求,建立国土空间开发保护现状评估指标体系和指标计算模型,开展国土空间开发保护现状评估,形成指标库和模型库,实现指标的计算与存储管理,辅助规划管理者就开发保护的底线管控、结构效率和生活品质等方面,摸清现状、找准问题、识别风险、研判趋势、提出对策,为科学编制国土空间规划提供决策依据(如图5.9所示)。 + +\subsubsection{3.支持下位规划的一张图} +将各级各类的规划编制成果汇集为规划“一张图”,需要通过三个阶段:预备工作阶段、质检审查阶段、入库汇交阶段。各级总体规划编制成果依此工作实施路径,及时在本级平台入库并向国家级平台汇交,作为详细规划和相关专项规划编制和审批的基础和依据;详细规划和专项规划成果在本级整合叠加后,逐级向国家级平台汇交,为空间用途管制和建设项目规划许可提供依据。 + +\subsubsection{4.一张图的重要责任} +为国土空间用途管制、实施建设项目规划许可等国土开发利用、耕地保护和生态修复等规划实施相关业务提供规划空间管控的工作支撑。根据国土空间规划空间控制体系确定的管控要点和管控规则,将生态保护红线、永久基本农田保护红线、城镇开发边界以及主导功能区、规划分区和用途分类等统一纳入空间管控体系中,对规划实施行为开展合规性审查,生成合规性审查“体检表”,保障管控底线不突破。 + +\subsubsection{5.一张图的风险识别} +明确规划实施监督的对象与目标,以指标体系为核心,梳理支撑落实监测评估预警的数据体系需求。基于平台与系统,采集与接入多源数据,通过构建实施监督指标库与模型库,实现指标的计算与存储管理,动态监测约束性指标、管控边界现状和各类国土空间开发保护行为,定期评估规划目标执行情况、国土空间开发保护现状及其结构、效率和宜居水平,及时预警规划实施过程和实施成效中出现的有底线突破风险、指标执行不力和发现疑似违法行为等情况,为领导干部绩效考核,实施相关用途管制政策,以及规划动态调整完善提供参考。 + +图 5.9国土空间规划一张图工作流程 + +\subsection{国土空间规划“一张图”实施意义} +建立坐标一致、边界吻合、上下贯通的国土空间规划“一张图”,是贯彻落实习近平总书记“统一底图、统一标准、统一规划、统一平台”重要指示和《中共中央 国务院关于建立国土空间规划体系并监督实施的若干意见》(以下简称《若干意见》)的基础性制度。为指导全国加快形成国土空间规划“一张图”,推进“智慧规划”建设,2018年10月,自然资源部会同有关方面,启动相关国家标准研制工作。2021年3月,经国家市场监督管理总局批准,《国土空间规划“一张图”实施监督信息系统技术规范》(GB/T 39972-2021)(以下简称《规范》)正式发布,成为“多规合一”改革后国土空间规划领域首个国家标准,明确依托全国统一的国土空间基础信息平台,以第三次全国国土调查数据形成底图,叠合各级各类国土空间规划,形成全国国土空间规划“一张图”,作为规划编制审批、实施监督全周期管理及专项规划“一张图”衔接核对的权威依据(见图19)。 + +\subsubsection{1.顶层设计支撑规划管理} +坚持国土空间的新发展理念,对照社会经济和人民群众高质量发展需求,深入贯彻落实数字中国的战略部署,始终把数字化智能化智慧化监管平台建设作为国土空间规划体系建设的重要内容,并摆在优先位置深入谋划。根据“科学、简明、可操作”的原则,以整合空间类规划、落实“多规合一”、形成“一本规划”“一本蓝图”为目标,着眼于强化规划全周期管理,推动解决过去各类规划内容重叠冲突、重规划编制轻规划实施、规划调整修改随意等突出问题,在总结提炼各地实践、广泛听取多领域专家意见基础上,高标准高质量地建设国土空间规划“一张图”系统。 + +以目标为导向,强化标准引领。国土空间规划“一张图”实施监督信息系统(以下简称规划“一张图”系统)是构建五级三类国土空间规划体系的统一数字化技术支撑。《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》明确了“四个层次、两个体系”的总体框架,即设施层、数据层、支撑层、应用层和标准规范体系、安全运维体系;阐明了与其他业务系统的关系;明确了国、省、市、县一体建设,部门间共享协同的运转机制;规定了数据类型和要求以及主要功能应用等;确立了规划“一张图”系统建设的目标。 + +以问题为导向,提升规划全周期管理能力。规划“一张图”系统是实现国土空间规划全周期管理的有力手段。为防止出现违规编制、擅自调整、违规许可、未批先建、监管薄弱等乱象,《自然资源部办公厅关于加强国土空间规划监督管理的通知》(自然资办发〔2020〕27号)明确提出“实行规划全周期管理”,要求将国土空间规划“一张图”作为统一国土空间用途管制、实施建设项目规划许可、强化规划实施监督的依据和支撑。《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》紧紧围绕规划编制、审批、修改和实施监督全流程,明确了国土空间规划的“一张图应用”“国土空间分析评价”“成果审查与管理”“实施监督”“指标模型管理”和“社会公众服务”等6大类23项功能。其中,重点强化了规划的智能化编制、智能化审查、智能化监管功能;并保持分析评价指标模型、算法的开放性,为适应不断发展的国土空间规划编制管理实践预留了接口。 + +以服务为导向,注重共建共享共治。规划“一张图”系统是保障各级政府、各相关部门单位、社会公众共同参与国土空间治理的数字化基础设施。国土空间数据是数字空间的基础数据底盘。《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》要求规划“一张图”系统以数据为“细胞”,加强多源数据归集,赋能国土空间智慧治理;以共建共享为原则,分类有序推进上下级、部门间数据共享,鼓励跨部门跨层级多场景应用开发;设置社会公众服务模块,在满足公开公示、意见征询、公众监督等基本功能基础上,着力对接民众急需的高频应用场景,切实加强规划的公众参与,提高人民群众的获得感、幸福感和安全感;旨在依托规划“一张图”系统推动国土空间治理机制流程的重塑、治理方式效能的提升,把数据优势切实转化为治理优势,促进国土空间治理体系和治理能力的质量变革、效率变革、动力变革。 + +\subsubsection{2.系统功能的完善} +《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》要求,各地推进规划“一张图”系统建设应本着节约和从实际需求出发的原则,统筹协调相关已建成的国土空间、土地调查、环境保护、农田、林业、水利、草原、水系等方面的基础地理信息化工作,整合既有地理信息要素资源和数据资源。 + +加强相关国土空间规划数据的标准规范、数据统一。《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》要求基于国土空间基础信息平台要强化标准的规范性建设和数据格式与基础信息的统一平台建设。依据统一的测绘基准以及统一的用地用海分类标准,集成基础地理信息和自然资源调查监测成果数据,形成覆盖全域、三维立体、权威统一的国土空间数字化“底板”。在此基础上,逐级汇交纳入国土空间总体规划、详细规划成果数据,叠加相关专项规划成果数据,形成国土空间规划“一张图”。同时,着力营造安全、开放、充满活力的数字化治理生态,充分运用物联网、5G、大数据、云计算、区块链、人工智能等先进技术,促进国土空间数据与经济社会综合数据的融合应用,推动建设全要素、多类型、全覆盖、实时更新的权威国土空间数据库,将海量数据转化为“数据红利”,夯实“可感知、能学习、善治理、自适应”的智慧规划建设基础。 + +推动多元化国土空间规划“一张图”数据的共建共享。《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》要求开发专项规划与“一张图”的核对衔接功能,对专项规划开展符合性审查,并将经衔接一致的专项规划成果纳入规划“一张图”系统,统一各类开发保护建设活动的国土空间用途管制依据。同时,强调要为其他部门提供规划成果数据共享。“共建”与“共享”是一个硬币的两面,相辅相成、互为促进,共建是为了更高水准的共享,共享有助于推动更广范围的共建。《若干意见》提出,“整合各类空间关联数据,建立全国统一的国土空间基础信息平台。”国土空间基础信息平台积累了原国土资源部时期以来丰富的调查监测、地理国情、遥感影像等数据,是支撑包括规划“一张图”系统在内的各部门涉空间治理信息系统和应用的统一数据基底。为不折不扣落实党中央“多规合一”改革的重大决策部署,各地在推进有关信息系统和应用建设过程中,应严格按照中央文件要求,将各类空间关联数据统一整合到国土空间基础信息平台上来,为智慧城市、城市信息模型等各类应用提供统一的空间数据服务支撑,坚决杜绝各自为政、另搞一套,影响统一国土空间用途管制制度落地;最大程度避免财政重复投资,发挥出行政资源的集成综合效应。 + +强化国土空间规划“一张图”的数据贯通传导。《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》以因地制宜、统分结合为原则,要求国、省、市、县分级完成规划“一张图”系统建设,实现上下贯通,确保规划目标要求逐级传导落地。同时,鼓励各地扩展开发符合当地需要、更加精细化的应用场景和功能模块,增强动态感知城乡发展态势、智能分析城乡空间治理问题短板的能力,促进政府决策科学化、社会治理精细化、公共服务高效化。 + +增进国土空间规划“一张图”的开放共享。《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》鼓励以方便企业和群众为出发点和落脚点,在应用层开发完善服务社会公众、企事业单位、科研院所的相关功能模块,鼓励相关机构与个人接入“一张图”数据基础平台,构建国土空间规划“一张图”领域的大众创新、万众创业。增进“一张图”基础新平台与外部数据接口的畅通沟通渠道,支持科学研究、创新创业、便民服务以及公众展示等各类型数据平台开发服务,打造基于国土空间规划“一张图”的宜居、宜业、宜游的数字开放城市。 + +\subsubsection{3.系统协同以构建“一张图”系统} +各级自然资源主管部门要进一步深入贯彻落实党中央国务院的“多规合一”改革的重大决策部署,深刻认识规划“一张图”系统在推进国土空间治理体系和治理能力现代化、提升城乡治理水平、服务民生改善等方面的重要作用和重大意义,按照各级国土空间规划的统一工作部署和《国土空间规划“一张图”实施监督信息系统技术规范(GB/T 39972-2021)》要求,充分发挥主观能动性和创造性,加快推进系统建设,完善配套制度规则,拓展丰富应用服务。 + +积极推动国土空间规划“一张图”系统构建工作。《自然资源部办公厅关于开展国土空间规划“一张图”建设和现状评估工作的通知》(自然资办发〔2019〕38号)明确要求,未完成系统建设的市县不得先行报批国土空间总体规划。各地应对照《规范》,抓紧完成规划“一张图”系统建设,确保不影响各级规划报批,为国土空间规划实施管理提供及时的技术支撑(如图5.10所示)。 + +构建国土空间规划“一张图”的意义在于解决规划的矛盾与冲突,实现主体功能区战略格局精准落地、优化国土空间格局等﹒具体体现如目标对接、技术标准对接、用地分类对接等多方面的矛盾,在统一的基础上,完成数字工作底图的绘制,为区域空间布局及成果编制奠定基础;开展“双评价”工作(资源环境承载能力评价和国土开发适宜性评价),科学划定“三区三线”,统筹全域空间,确保主体功能区的精准落地;“一张图”是统领区域各规划的总图,基于区域的本底条件与基础,构建科学、合理的城乡用地、农业发展和生态安全格局,引导国土空间格局良性发展,从而有效提升管控效率。 + +国土空间规划“一张图”的构建,能够打通数据采集、融合、共享和应用全链条,让数据“跑”起来。数据的生命在于应用。要进一步强化主动服务意识,以用促建,在数据汇集、系统集成、上下联动、有序共享上下更大功夫,不断提高数据汇集的能力、效率和质量,持续提升数据分析应用的水平。 + +加大探索创新力度,延伸拓展国土空间规划“一张图”系统的多场景应用。结合国家创新创业的发展战略机遇和科研机构、小微企业、便民服务等多类型用户需求视角,积极延伸互联网+国土空间规划“一张图”的应用场景,会同有关部门,在城乡治理、民生需求的重点领域,聚焦社会经济发展重大需求和国计民生的重点问题,针对性地开发应用场景,助力智慧城市与数字乡村建设,努力提供更多普惠便捷、优质高效的数字服务,让人们更好共享信息化发展成果。 + +加强完善配套体系标准,建立健全国土空间规划“一张图”制度建设。加快制定公开公正的国土空间规划“一张图”制度建设,增强规则层面的“一张图”建设内容,完善制度建设“一张图”与技术层面的“一张图”的统筹协调。健全完善有利于“多规合一”、有利于共建共享的规划“一张图”系统建设应用规则标准,推进业务标准化、工作流程化、管理规范化。同时,统筹发展与安全,严格落实安全发展的要求,建立健全管理制度,保证数据安全。 + +图 5.10国土空间规划“一张图”应用与指标模型管理功能 + +\section{国土空间规划管理信息平台} +《自然资源部办公厅关于开展国土空间规划“一张图”建设和现状评估工作的通知》(自然资办发〔2019〕38号)明确指出,国土空间基础信息平台(以下简称“平台”)是形成国土空间规划“一张图”的基础载体,省、市、县各级所建平台既要能够与国家级平台对接,全面实现纵向联通,亦要能够与其他相关部门信息平台横向联通、数据共享(如图5.11所示)。 + +平台建设首先需要完成数据资源体系建设,建立资源中心,保证各类数据能够“进得来”、“管得住”、“出得去”。其次,平台需要提供服务的统一管理,建立服务中心,促进政府部门的现有数字基础设施的建设成果向资产化、服务化方向发展,提升政务服务水平。 + +基于国土空间基础信息平台,构建国土空间规划“一张图”实施监督信息系统,有效支撑国土空间规划分析评价和现状评估,识别风险,发现问题;支撑国土空间规划成果审查,落实规划逐级传导与管控;有效支撑用途管制,保障空间管控要求落地;有效支撑监测评估预警,对约束性指标和管控边界实现动态监测,对目标执行情况、开发保护现状等方面开展评估,对底线突破有风险、目标执行不力以及疑似违法等行为进行及时预警。从而实现规划、实施、监测、评估和预警全过程的信息化支撑,全面提升空间治理体系和治理能力现代化水平。 + +图 5.11国土空间基础信息平台 + +\subsection{满足国土空间规划需求} +国土空间规划“一张图”管理信息平台要满足全流程、多层级的国土空间规划建设和管理的业务需求。相关国土空间规划的管理业务应对的是各级国土空间规划主管部门的国土空间规划管理事权,支撑分级分类型、全域全要素和全程全方位的国土空间规划体系的建立并监督实施。整个业务过程和相关工作需求主要包括各级各类国土空间规划的编制(修编)、各级各类国土空间规划的规划审批、规划实施、规划监督和规划评估,要将业务需求形成闭环管理模式。系统应穿透国土空间规划的全覆盖、全流程、全生命周期的管理系统。 + +\subsection{构建标准的数据体系} +国土空间规划“一张图”管理信息平台系统要服务规划全业务过程闭环,实际上就是要能够形成多套图,包括服务规划编制的“一张图”,规划实施的“一张图”、规划监督的“一张图”和监测预警评估的“一张图”,并依工作要求对应层层打开或关闭。因此,上述要求绝不是机械的、简单地完成数据的罗列堆砌和叠加展示所能解决的,而必须要构建一套基于业务需求、管理机制、应用要求的数据资源体系。在“一张图”系统构建初期就要从数据工程的角度,构建规范化、标准化的数据管理规范,解决整个系统的数据构成、数据关系、数据标准及质量管控、动态更新的问题。 + +按照这个要求,“一张图”的具体建设就需要考虑以下几个重点: + +(1)梳理出“一张图”数据资源目录体系。理清每一项数据的业务来源、生产和管理单位、业务使用场景。 + +(2)建立统一、可以执行的数据标准规范体系。包括数据生产和采集规范、存储和管理规范、应用和共享规范等。 + +(3)建立可执行的数据动态更新机制。“一张图”的建设,不是一次性工程,而是需要让数据动起来,用起来,能够为将来国土空间规划的编制、管理、实施、监督提供决策依据,使管控要素精确落地。所以,明确主体责任、设立专门的保障部门,将数据的动态更新机制落到可执行层面非常关键。 + +(4)提供标准化的配套工具保障。从数据资源可用性角度出发,必须建立完善的数据管理制度,但制度的最终落地执行,则需要依赖一套工具支撑。 + +\subsection{国土空间规划信息平台的建设} +为了响应国土空间规划的治理目标,支持国土空间规划全环节业务管理,系统在应用层面,需要形成一套覆盖国土空间规划编制、审批、实施、监测、评估、预警全过程的功能体系。通过开放共享以及多类型多权限管理等方式,增进国土空间规划“一张图”管理信息平台的应用场景建设和应用服务领域建设。系统应用体系的搭建,服务于国土空间规划的改革、服务于规划管理。所以,在搭建应用体系的时候,既要考虑功能背后的管理诉求,也要考虑功能之间的横向联动,纵向对接,还要考虑功能的随需扩展。 + +\subsection{构建稳健中台保障体系} +国土空间规划“一张图”管理信息平台系统建设,跟过去“规划一张图”、“国土一张图”、“多规合一一张图”最大的不一样,就是业务上的贯穿,不是为了解决单一业务问题,而是注重在纵向的垂直管理、横向的空间治理、环向业务过程不同维度的系统性支撑。随着整个国土空间规划工作的逐渐递进和深化,未来还涉及更多的功能拓展和延伸。 + +如果在建设之时仅仅局限或关注解决某个点状问,建立一个或几个业务应用,那么显然是会造成业务和信息孤岛,不可持续。为此,跟国土空间规划要“四梁八柱”的框架支持一样,建设系统,也应当从整体性、系统性、协同性、可扩展性等技术层面考虑进行技术体系的搭建,从技术层面解决信息孤岛和无法支撑全业务环节的数据流动问题,解决全过程数字化决策在数据库管理、指标管理、模型管理的衔接问题,解决业务随需应变、持续深化的拓展问题,保障上层应用系统不至于成为“一次性工程”。 + +要坚持稳健、完善的中台系统建设,丰富标准化的中台架构及配套研发运营体系的深入理解和落地,要通过将技术和业务能力进行沉淀,为“前台”业务变化及创新的快速响应提供专业、高价值、低成本、可复用的专业能力。按照中台架构进行能力的解耦合增强,形成数据中台、技术中台、业务中台三大中台,为国土空间规划提供有一定领域和行业深度的产品和能力,有效支撑系统的建设实施。 + +\subsection{建设“一张图”平台服务体系} +新时期的国土空间规划“一张图”管理信息平台是针对国土空间全域全要素的规划,涉及多领域、多学科,要落实建立国土空间规划体系并监督实施的目标,就需要按照软件工程化到角度,面向用户提供全环节的服务支持。要将国土空间规划“一张图”管理信息平台作为我国社会经济高质量发展和创新驱动国土空间高质量发展的重要保障设施,加强国土空间规划“一张图”管理信息平台对接社会经济发展的重大需求,满足科研机构、企事业单位、人民群众等多元化的地理信息数据服务需求。基于标准、流程和经验的融合,精细把控业务、标准、数据、应用、技术等各环节,为建设能用、管用、实用的系统提供坚实的服务支撑(如图5.12所示)。 + +(1) “一张图”的系统支撑能力的增强 + +国土空间规划“一张图”管理信息平台系统建设涉及标准、数据、指标模型、功能、运维一系列的工程建设;横向需要与政务服务系统、多规合一系统、国土空间基础信息平台对接;纵向需要与不同层级的系统对接。通过数据标准模板、数据资源规划与数据工程纲要、指标模型基础算法、成熟产品体系、接口规范实践对每一项工作进行有力的工程支撑。 + +(2)“一张图”的建设内容的完善 + +国土空间规划“一张图”管理信息平台建设由于其业务的复杂性、综合性,具有干系人复杂、涉及多部门、多团队的特点。为了使工作有序开展、按时完成,需要科学运用项目管理的相关理论知识和方法,各业务管理部门、信息中心、规划编制单位、软件开发单位、数据处理单位等应明确分工与时序。在承建单位内部,要形成合理的项目组织结构,划分标准规范、数据资源、指标模型、应用系统、硬件保障等不同的职能小组,明确各小组的职责,指定小组成员和负责人。最终,各部门、多团队衔接协同,才能保障国土空间规划“一张图”建设的各项工作能够有序落实。 + +(3)“一张图”的技术体系的创新 + +国土空间规划“一张图”管理信息平台建设要增强创新技术体系的建设。打造建设能用、管用、实用的系统,在有效的团队协作之上,还要建立有序的工程方法,不能仅仅关注于系统功能的开发实现,而是需要实现从需求调研、业务分析、系统设计、编码实现、集成部署、系统测试、试用反馈到上线运行、项目交付的全过程贯穿。针对系统建设的业务需求具有不确定性和多样性的特点,鼓励“一张图”管理信息平台建设实施过程中各类创新技术、创新管理以及创新模式等方面对系统建设涉及的业务逻辑和系统逻辑,创新驱动国土空间规划编制、审批(查)、实施、监督各环节的业务流程和管理规范,在保证用户需求被准确传递的同时,让业务应用系统开发人员能够实行高效、准确的沟通交流,使架构师、业务分析员和项目经理等人员能够有效介入项目进度和质量的全程管控。 + +(4)稳定的“一张图”运维体系的打造 + +国土空间规划“一张图”管理信息平台在系统上线运行之后,仍然需要与业务部门的日常工作进行持续进行数据更新与运维系统的不断升级。系统在使用过程中因为各种各样的问题,同时,在“全网通办”、“数字政务服务”等营商环境完善战略的要求下,全国不少省、市都明确了业务系统向“互联网+政务服务”的转变过程,强调了便捷性与营商环境改善的重要性,对“一张图”管理信息平台的运维工作提出了新的挑战。这些问题都需要通过日常专业的运维服务来解决。打造持续稳定的“一张图”更新与运维服务体系,通过建立包括自动化监控、系统安全加固、政务云迁移、容灾建设等内容的运维服务体系,保障系统的稳定运行、数据的持续更新、功能的升级完善,降低运维管理压力和成本。 + +国土空间规划“一张图”实施监督信息系统集中承载了新时期国土空间规划的治理逻辑,要让系统在各级自然资源部门中发挥实际作用,就必须摆脱“建系统”和拼功能的思维,转向系统性、整体性、协同性思维,在理解新时代国土空间规划的治理逻辑、用户业务特性和现实需求的前提下,按照系统性、工程化、持续化的角度,综合考虑业务、数据、应用和技术平台等内容,给用户提供一个实用、好用、管用的系统。 + +图5.12国土空间一张图系统 + +第5章国土空间规划的技术工具与方法 148 + +5.1国土空间规划基础方法 148 + +5.1.1调查勘测方法 148 + +5.1.2系统评价方法 149 + +5.1.3预测分析方法 160 + +5.1.4系统制图方法 164 + +5.2国土空间规划空间分析技术 165 + +5.2.1地理信息系统(GIS)空间分析 165 + +5.2.2遥感(RS)技术 167 + +5.3国土空间规划决策方法 169 + +5.3.1空间决策博弈方法 169 + +5.3.2空间决策支持系统 169 + +5.3.3空间模拟与仿真技术 171 + +5.4国土空间规划“一张图”系统 173 + +5.4.1国土空间规划“一张图”建设步骤 173 + +5.4.2国土空间规划“一张图”实施路径 175 + +5.4.3国土空间规划“一张图”实施意义 176 + +5.5国土空间规划管理信息平台 180 + +5.5.1满足国土空间规划需求 181 + +5.5.2构建标准的数据体系 181 + +5.5.3国土空间规划信息平台的建设 182 + +5.5.4构建稳健中台保障体系 182 + +5.5.5建设“一张图”平台服务体系 183 + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 类型 & 内容 \\ +\hline +1 & 工程勘测 & 航片判读调绘、遥感图像识别、工程测绘 \\ +2 & 国土调查 & 分布数量、权属、利用结构、现状问题调查 \\ +3 & 资源调查 & 山水林田湖草沙等自然资源的调查 \\ +4 & 在野调查 & 生态环境、农业环境、水体现状等野外踏查与评测 \\ +5 & 人居环境调查 & 城、镇、乡村各级各类人居空间人口、交通网络、生产力布局与经济环境等的调查 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 分类 & 内容 \\ +\hline +1 & 国土文字信息 & ①调查与收集规划区内国土资源的种类、数量、质量、规模、分布、组合、结构数据与信息。②收集规划区周边地区及评价区域的上一级行政区域的国土资源特征及开发利用保护现状数据和信息。③收集与调查规划区国土资源开发利用保护历史与现状资料。④收集规划区的经济社会发展状况资料。⑤收集规划区国土资源及其开发利用保护的科学研究成果档案资料。⑥收集国内外国土资源开发利用比较成功的国家和地区国土资源开发利用研究成果及经验数据资料。⑦收集与调查各类国土资源的开发利用保护规划及实施效果、各种国土资源调查评价报告等 \\ +2 & 国土图像信息 & ①图像信息包括遥感图像,如航空相片、卫星图片以及各种地图。彩色航空相片,可用于国家和区域制定综合的国土资源开发利用保护规划,还可以用于各种专项的国土空间整治规划,同时还可以被利用于探测地壳变动,判断森林、水体等各种资源的数量消长,发现淹没迹地等,或是地形、地质、土壤、土地利用及其他有关国土空间基础调查研究的重要资料。②地图可划分为综合地图和专题地图。专题地图是指对特定主题有突出表现的地图,主要以自然条件为对象的,如水文地质、地形分类、植被、湖沼图等;有主要以人文条件为对象的,如地籍图、行政区划图、道路图、工业分布图等;③自然与经济社会相关的图,如土地分级图、土地利用图等 \\ +3 & 国土数值信息 & 国土数值信息有表示位置的坐标资料与特定网格内属性的网格资料。它是将地形、地质、土壤、高程、土地利用现状、流域、铁路与道路、湖泊与海岸线,行政界线及重大工程、公共设施等有关信息,通过网格或坐标的形式,存储于纸、光盘、磁盘等相关媒介中形成的。网格信息作为表示位置数值化的方法,原则上是采用经纬线将地区分为网格状的“标准区域网格”。标准网格,是按大体等形、等积进行划分的。网格的大小,是由区域的特点、研究工作的深度及精度所决定的。坐标信息包括重大工程、公共设施等点的信息,以及海岸线、行政界线、河川、道路等线状信息 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 来源 & 类型 \\ +\hline +1 & 政府部门的数据档案 & 统计年鉴、经济发展年鉴、环境统计年鉴、城市统计年鉴、国土资源开发利用保护及经济社会发展计划、工作总结、研究报告等 \\ +2 & 各部门各行业规划资料 & 土地利用规划、矿产开发利用规划、农业发展规划、农业区划、林业发展规划、水资源开发利用规划、旅游发展规划、环境整治规划等 \\ +3 & 典型调查勘测资料 & 城乡居民收入调查、人口普查、国土资源大调查、耕地普查等,也可以是各行业和科研部门、企事业单位组织的调查勘测资料 \\ +4 & 地图和遥感资料 & 地质图、地形图、矿产资源图、土壤图、水资源分布图、土地利用现状图、航空相片、卫星图像等 \\ +5 & 各类政策法规资料 & 各级权力机构的法令、法规、政策、政府工作报告等 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 重要意义 & 具体内容 \\ +\hline +1 & 优化国土空间开发格局和协调“三生空间”的现实需要 & 控制区域国土开发强度,调整空间功能布局结构,促进生产空间集约高效、生活空间宜居适度、生态空间山清水秀,亟须以资源环境承载力评价为依据,对国土空间进行分区分类管理,并严格加强用途管制。 \\ +2 & 主体功能区规划编制和空间用途管制的必要前提 & 主体功能区划明确将国土空间划分为不同的分区,不同主体功能区资源环境承载力的差异,使得其国土空间用途、开发利用与保护方式各异;同时,划定生产、生活、生态空间开发管制界限,落实用途管制,明确资源环境承载力与国土空间开发保护的关系,也要以承载力相应指标的监测作为国土空间用途管制的基础与依据。 \\ +3 & 建立国土空间规划体系的重要基础 & 国土空间规划体系是全域全要素的综合性空间规划,需要从空间层面上对地区产业、人口等要素的集聚特征,以及资源环境要素的整合效应进行综合把控,也必须将资源环境承载力评价作为规划编制的重要基础。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 方法 & 内容 \\ +\hline +1 & 多要素叠置分析法 & 基于一系列评价指标,通过数学模型处理和指标加权,展开叠置分析,最终得出一个表征资源环境承载水平的综合指数 \\ +2 & 比较法 & 首先选定一个资源环境承载状态合理的区域,然后将研究区域的各项指标与其对比,从而评价研究区的承载情况 \\ +3 & 短板原理法 & 依据短板效应,认为区域综合承载力水平最终取决于对经济社会发展具有“瓶颈”作用的制约因素,在计算出各个单因素承载力后,取各单因子最小值作为最终的综合承载水平 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 方法 & 内容 \\ +\hline +1 & 资源环境要素单项评价 & 按照评价对象和尺度差异遴选评价指标,对土地资源、水资源、环境、生态和灾害五类自然要素进行单项评价,并针对不同功能指向与评价层级分别构建相应的评价指标与方法。具体而言,土地资源评价涵盖坡度、高程、土壤质地等指标,以农业生产和城镇建设为功能指向;水资源评价涵盖降水量、水资源可利用量等水资源丰度指标,以农业生产和城镇建设为功能指向;环境评价涵盖土壤、大气和水环境容量等指标,以农业生产和城镇建设为功能指向;生态评价涵盖生态系统服务功能重要性、生态敏感性和盐渍化敏感性等指标,以生态保护和农业生产为功能指向;灾害评价涵盖气象灾害、地质灾害和风暴潮灾害危险性等指标,以农业生产和城镇建设为功能指向。 \\ +2 & 资源环境承载力集成评价 & 基于资源环境要素单项评价的分级结果,根据生态保护、农业生产、城镇建设三方面的差异化要求,综合划分生态指向的生态保护等级以及农业、城镇指向的承载力等级,表征国土空间的自然本底条件对人类生活生产活动综合支撑能力;承载力等级按取值由低到高划分为一级、二级、三级、四级、五级等若干不同的等级。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 内涵 & 内容 \\ +\hline +1 & 人类发展 & 即城镇建设空间的选址应在自然条件良好、避开灾害风险的稳定区域,以保障人类安全与发展需要; \\ +2 & 粮食保障与经济效率 & 即在保障粮食供应等人类生活基本需要的同时,形成高效有序的经济空间组织形态; \\ +3 & 生态安全 & 即要求各类开发建设活动需与自然生态、资源环境本底条件相协调,维护生态系统服务功能并实现可持续发展。以国土空间开发适宜性评价为基础,实施国土空间用途管制并进行“三区三线”等区界的划定,这是国土空间规划编制的核心内容之一。国土空间开发适宜性评价是优化国土空间开发格局,合理布局农业、生态与建设空间的基础和依据。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 评价方面 & 内容 \\ +\hline +1 & 生态保护重要性评价 & 开展生态系统服务功能重要性评价、生态感性评价,集成得到生态保护重要性,划分为极重要、重要、一般等不同等级。生物多样性维护、水源涵养、水土保持、防风固沙、海岸防护等生态系统服务功能越重要,或水土流失、石漠化、土地沙化、海岸侵蚀等生态敏感性越高,且生态系统完整性越好、生态廊道的连通性越好的区域,其生态保护的重要性等级越高。 \\ +2 & 农业生产适宜性评价 & 开展农业生产的土地资源、水资源、气候、环境、生态、灾害等单项评价,集成得到农业生产适宜性,则分为适宜、一般适宜、不适宜等不同等级。地势越平坦,水资源丰度越高,光热越充足,土壤环境容量越高,气象灾害风险越低,且地块规模和连片程度越高的区域,其农业生产适宜性的等级越高 \\ +3 & 城镇建设适宜性评价 & 开展城镇建设功能指向的土地资源、水资源、气候、环境、灾害、区位等单项评价,集成得到城镇建设适宜性,划分为适宜、一般适宜、不适宜等不同等级。地势越平缓,水资源越丰富,水气环境容量越高,人居环境条件越好,自然灾害风险越低,且地块规模和集中程度越高,地理及交通区位条件越好的区域,其城镇建设适宜性的等级越高。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|c|c|} +\hline +评价类型 & 战略定位 & 管理导向 & 空间治理 & 出口指向 \\ +\hline +资源环境承载力评价 & 约束性 & 严格调控 & 空间保护 & 数量规模 \\ +资源环境承载力评价 & 优先关注的是“承载力的超载”“超限”“高压力”“红色预警”等。 & 承载力状态好坏是判断管理政策是否需要干预的晴雨表,评价结果侧重为“政策调控”做依据。 & 宏观上倒逼国土空间规划对部分“高承载”区域进行空间保护;微观上为管理部门提供线索,调整治理时序。 & 以数量规模为评价出口。通过分析资源环境各因子的量化数据,筛查出短板要素,对国土空间开发利用格局形成规模约束。 \\ +国土空间开发适宜性评价 & 发展性 & 积极引导 & 空间开发 & 空间布局 \\ +国土空间开发适宜性评价 & 优先关注的适宜区,重在辨识区域某项开发活动最具潜力的区域。 & 适宜性大小是判断空间综合功能效用是否可以发挥到最大的标准,评价结果可引导国土空间规划的合理布局。 & 宏观上探索高效有序的经济空间组织形态和空间结构;微观上考虑地区发展模式与管理成本收益,深入认知区域开发的综合效益。 & 以空间布局为评价出口。通过应用评价结果,划定三区三线,对国土空间开发利用格局开形成空间约束。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +国空规划的决策作用 & 国空规划的实践内容 & 国空规划的编制过程 \\ +\hline +先后关系 & 并列关系 & 辩证统一关系 \\ +资源环境承载力评价为国土空间规划实施提供基础判断,可以说是国空规划开展的“决策基础”; +国土空间开发适宜性评价为国土空间规划实施奠定深层的理解与引导,可以说是国空规划进行的“决策引领”。 & 在《中共中央国务院关于加快推进生态文明建设的意见》提出了“树立底线思维、设定并严守资源消耗上限、环境质量底线、生态保护红线,将各类开发活动限制在资源环境承载能力之内”,其中三大任务需要双评价分别实现,因此二者之间存在并列关系 & 矛盾关系表现在现状与理想潜能本身就存在矛盾关系:承载力评价侧重阐述开发的现存状态、适宜性评价侧重阐述开发的理想潜能。统一关系表现在两者缺一不可:国空规划本质就在于区域空间要素的重构,离不开对现状的参考,也离不开对理想潜能的预测。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 原理 & 概要 \\ +\hline +1 & 惯性原理 & 事物的发展和系统的运行在没有受到外力强烈干扰的情景下,通常都会有一定的惯性,即过去和现在的情景将会持续到未来。 \\ +2 & 类比原理 & 它是根据两个具有相同或相似特征的事物间的对比,从某一事物的某些已知特征去推测另一事物的相应特征,从而对预测对象的未来作出判断的预测方法。类比方法是在两个特殊事物之间进行分析比较,它不需要建立在对大量特殊事物分析研究并发现它们的一般规律的基础上。因此,它可以在归纳与演绎无能为力的一些领域中发挥独特的作用,尤其是在那些被研究的事物个案太少或缺乏足够的研究、科学资料的积累水平较低、不具备归纳和演绎条件的领域 \\ +3 & 关联原理 & 在社会经济系统中,许多社会经济变量之间常存在着关联关系或相关关系,如正相关、负相关等。通过这种关联关系分析,就可以对预测事物的未来变化进行判断。多元回归分析的预测技术,就是根据这种关联原理,从样本对整体进行估计、验证和模拟,对事物的未来进行预测 \\ +4 & 概率原理 & 它是指任何事物的发展都有一定的必然性和偶然性,社会经济发展过程也不例外。通过对事物发展偶然性的分析,找出其发展规律,从而进行预测。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 方法 & 内容 \\ +\hline +1 & 聚类分析法 & 利用统计手段进行聚类分析,可以从影响自然、经济和社会等指标对区域内各地区进行分析,找出地区间的差异和地区经济发展特征,这是国土空间规划分区的重要参考基础 \\ +2 & 空间叠置法 & 适用于规划图和区划图齐全的情况下,将有关图件上规划界线重叠在一起,以确定共同的区界。对于不重叠的地方要具体分析其将来主导的国土空间用途并据以取舍 \\ +3 & 综合分析法 & 一种带有定性分析的分区方法,主要适用于区域差异显著、分区明显易定的情况,要求操作人员非常熟悉当地的实际情况,一般为专家个人或集体 \\ +4 & 主导因素法 & 它是在微观的规划单元划分基础上,适当地加以归并,逐步扩大国土空间利用区,再将地域相连的类型区合并成为区域,以主导的国土空间用途作为国土空间区域名称 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 分区 & 具体内容 \\ +\hline +1 & 自然分区 & 它是根据国土空间地质、地貌、气候、水文、土壤和生物等因素及其发生、发展和演替方向的相对一致性所划分的自然地理综合体。 \\ +2 & 经济分区 & 它是根据经济发展的资源条件、经济发展水平、经济发展内在联系、经济发展目标和方向的相对一致性所划分的地域生产综合体 \\ +3 & 行政分区 & 它是按照地方政权存在的区域和管辖范围所划分的行政管理地域单元。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 决策支持方式 & 具体内容 \\ +\hline +1 & 基于空间数据形式的决策支持 & 数据是事物的特征和状态的数量化表现。在国土空间规划中涉及大量的空间数据、属性数据和统计数据,如何利用这些数据快速、高效提取规划信息,这是智能决策支持,开放的GIS空间数据库为数据支持提供了数据平台。 \\ +2 & 基于模型和方法形式的决策支持 & 研究人员为了描述国土空间的变化规律建立了大量的模型和方法,均可在GIS平台上实现,特别是利用GIS平台的空间分析功能等,为辅助决策提供支持。 \\ +3 & 基于知识主导形式的决策支持 & 在建立模型库和方法的基础上,建立知识库推理机制,结合模拟仿真技术、演进技术,人机交互系统,基于Web技术的异构终端,使利益相关者高效地参与决策过程,最终形成决策方案。 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|} +\hline +序号 & 问题 \\ +\hline +1 & 要明确国土空间规划的三个迭代及六个过程模型 \\ +2 & 要明确系统开发时间的要求 \\ +3 & 对系统开发费用的要求 \\ +\hline +\end{tabular} +\end{table} + +\begin{table}[H] +\centering +\begin{tabular}{|c|c|c|} +\hline +序号 & 特性 & 内容 \\ +\hline +1 & 科学性 & 系统需采用新思想、新技术。在空间数据库设计、系统功能设计方面应具有科学、清晰的结构与组织,为满足决策分析的需求,确保系统运行的稳定 \\ +2 & 实用性 & 系统应结构简洁,操作方便,界面友好 \\ +3 & 规范性 & 系统与国内主流空间数据库能很好地接轨,应遵循统一、规范的信息编码和坐标系统、规范的数据精度和符号系统 \\ +4 & 可扩充性 & 系统应具有一定兼容性,方便系统将来的升级与移植 \\ +\hline +\end{tabular} +\end{table} + diff --git a/data/book/main.pdf b/data/book/main.pdf new file mode 100644 index 0000000..4f2a889 Binary files /dev/null and b/data/book/main.pdf differ diff --git a/data/book/main.tex b/data/book/main.tex new file mode 100644 index 0000000..c46b43e --- /dev/null +++ b/data/book/main.tex @@ -0,0 +1,46 @@ +\documentclass[12pt,a4paper]{book} +\usepackage[UTF8]{ctex} +\usepackage{geometry} +\geometry{left=2.5cm,right=2.5cm,top=3cm,bottom=3cm} +\usepackage{graphicx} +\usepackage{amsmath} +\usepackage{amsfonts} +\usepackage{amssymb} +\usepackage{hyperref} +\usepackage{booktabs} +\usepackage{longtable} +\usepackage{multirow} +\usepackage{array} +\usepackage{float} +\usepackage{caption} + +\title{国土空间规划:概念、原理、方法} +\author{} +\date{} + +\begin{document} + +\frontmatter + +\maketitle + +\input{abstract} + +\tableofcontents + +\mainmatter + +\input{preface} +\input{chapter01} +\input{chapter02} +\input{chapter03} +\input{chapter04} +\input{chapter05} + +\backmatter + +% 如果需要添加参考文献,请取消以下注释并创建references.bib文件 +% \bibliographystyle{unsrt} +% \bibliography{references} + +\end{document} diff --git a/data/book/preface.tex b/data/book/preface.tex new file mode 100644 index 0000000..1816731 --- /dev/null +++ b/data/book/preface.tex @@ -0,0 +1,15 @@ +\section{前 言} +我国作为历史悠久的文明古国,从聚落现象开始到封建社会的发展,从近代开端初始到中西文化交流,空间规划经历了长期的实践探索,为我们积累了丰富的文化遗产和营造理念。建国以后,特别是改革开放以后,随着国家发展环境以及行政体制改革的变化,我国的空间规划逐渐趋于多元,除传统的城乡规划外,逐步出现了土地利用规划、主体功能区划、生态环境保护规划等法定或“主流类型”的空间规划,这些规划的发展为社会主义建设起到了积极的作用和良好的效果,并且基本形成了三个共识:一是各种类型、各个系列的空间规划是国家发展的重要公共政策之一,也是服务于国家经济社会发展的重要的技术性工具之一,更是国家治理体系重要组成部分之一。正基于此,各项规划之间由于各种原因,形成了一定的相互掣肘的问题,迫切需要以“多规合一”的思想,统一到生态文明视角下的国土空间资源体系一盘棋的主要方向上来。 + +2019年5月中共中央、国务院印发《关于建立国土空间规划体系并监督实施的若干意见》,提出以习近平新时代中国特色社会主义思想为指导,全面贯彻党的十八大、十九大和历届全会精神,紧紧围绕统筹推进“五位一体”总体布局和协调推进“四个全面”战略布局,坚持新发展理念,坚持以人民为中心,坚持一切从实际出发,按照高质量发展要求,做好国土空间规划顶层设计,发挥国土空间规划在国家规划体系中的基础性作用,为国家发展战略落地实施提供空间保障。新组建的国土资源部将我国国土空间规划体系概括为“五级三类四体系”,标志着我国国土空间规划体系顶层设计“四梁八柱”的基本形成。 + +国土空间规划是落实治国理政,推进生态文明建设,提升国土空间治理效能,服务人居环境发展的重要政策工具。国土空间规划能够解决以往规划体系繁杂、各部门规划事权交叉重叠、审批流程复杂等系列问题,是政府调控和引导空间资源配置的基础,编制国土空间规划是生态文明建设、自然资源保护的历史必然选择,是国家国土空间治理体系和治理能力现代化的重要表现。 + +按国土空间发展规划,原计划到2020年,基本建立国土空间规划体系,逐步建立“多规合一”的规划编制审批体系、实施监督体系、法规政策体系和技术标准体系;基本完成市县以上各级国土空间总体规划编制,初步形成全国国土空间开发保护“一张图”。目前此项工作还在不断完善之中。2025年,健全国土空间规划法规政策和技术标准体系;全面实施国土空间监测预警和绩效考核机制;形成以国土空间规划为基础,以统一用途管制为手段的国土空间开发保护制度。2035年,全面提升国土空间治理体系和治理能力现代化水平,基本形成生产空间集约高效、生活空间宜居适度、生态空间山清水秀,安全和谐、富有竞争力和可持续发展的国土空间格局。 + +国土空间规划全面拉开帷幕,其指导思想、技术标准、法规体系成为学科教学的基本依据;其规划体系、评价方法、用地分类、基本编制原则与内容等构成了国土空间规划基本原理与方法;未来的国土空间规划仍然需要多个学科共同支撑,城乡规划、国土资源管理、生态环境,地理等学科,必将通过深刻的整合和体系的重构,实现国土空间规划学科与人居环境学科的相互支撑、相互融合发展。在以上背景下,本书参考了已陆续出版的各类指导资料,结合国土空间的规划领域人才培养需求,构建了从生态文明到人居环境认知入手的内容体系,以期为人居环境科学向国土空间规划学科转型提供基本教学参考。 + +基于此,我们编著了这部国土空间规划原理,本书由哈尔滨工业大学建筑学院吴松涛教授拟定大纲并负责统稿,周小新、苏万庆协助组织全书,全书包括5章,其中第一章由董珂、周小新编写;第二章由吴松涛、王永德编写;第三章由苏万庆、吴冰编写,第四章由吴松涛、周小新、杜立柱编写;第五章由吴远翔、吴冰、许大明编写。 + +国土空间是我国面向新时代需求而架构的全新的空间规划体系,其内容的成熟稳定必须要经过长久的探索和积累才能完成,由于编者能力、水平时间有限,书中存在着不当甚至错误之处,甚至可能会出现引用专家观点标注不全面等问题,请各位专家读者不吝指正,我们将在未来的教学和研究中不断的校正、丰富和完善。 + diff --git a/data/book/toc.tex b/data/book/toc.tex new file mode 100644 index 0000000..183342c --- /dev/null +++ b/data/book/toc.tex @@ -0,0 +1,222 @@ +第1章生态文明下的人居环境和国土空间 1 + +1.1我国人居环境发展历程 1 + +1.1.1原始时期 1 + +1.1.2古代时期 1 + +1.1.3近代时期 2 + +1.1.4现代时期 3 + +1.2我国传统人居环境的理念与人居环境学科发展 9 + +1.2.1人居环境的核心理念 9 + +1.2.2人居环境的科学发展 11 + +1.3生态文明演进与我国国土空间的生态安全问题 12 + +1.3.1生态文明的演进 12 + +1.3.2我国生态资源的基本情况 13 + +1.3.3我国生态资源环境挑战 13 + +1.4生态文明建设的基本观念 15 + +1.4.1历史思维:“生态兴则文明兴,生态衰则文明衰” 16 + +1.4.2全球思维:“共谋全球生态文明建设” 16 + +1.4.3底线思维:“坚守资源上限、环境底线、生态红线” 17 + +1.4.4民本思维:“良好生态环境是最普惠的民生福祉” 17 + +1.4.5整体思维:“坚持人与自然和谐共生” 17 + +1.4.6系统思维:“山水林田湖草是生命共同体” 18 + +1.4.7辩证思维:“绿水青山就是金山银山” 18 + +1.4.8法制思维:“用最严格制度最严密法治保护生态环境” 19 + +1.5生态文明建设的总体路径 19 + +1.5.1高水平保护——框定生态资源环境安全底线 20 + +1.5.2高质量发展——促进要素向优势地区集聚 20 + +1.5.3高品质生活——满足人民美好生活需要 21 + +1.5.4高效能治理——推进空间治理体系和治理能力现代化 21 + +1.6生态文明下的人居环境与国土空间和谐共存 21 + +1.6.1探索以生态优先、人居环境绿色发展为导向的新路子 22 + +1.6.2生态文明下的国土空间导向 22 + +第2章自然资源与土地利用 24 + +2.1自然资源的概念、构成与属性 24 + +2.1.1自然资源的概念 24 + +2.1.2自然资源的类型 24 + +2.2土地定义与土地管理制度 26 + +2.2.1土地的定义 27 + +2.2.2土地制度 28 + +2.2.3土地利用规划与管理 31 + +2.3国土空间土地用途管制 32 + +2.3.1空间用途管制的源起与发展 32 + +2.3.2国土空间用途管制的方法 33 + +2.3.3国土空间用途管制的内容 34 + +2.3.4城乡建设用地的统筹管控 36 + +2.3.5土地用途分区 37 + +第3章 城乡空间规划思想与理论发展 39 + +3.1我国城乡规划思想与理论发展 39 + +3.1.1中国古代城市规划思想与理论 39 + +3.1.2中国近代城市规划思想与理论 41 + +3.1.3新中国成立后城市规划思想与理论 42 + +3.2西方城市规划思想与理论发展 46 + +3.2.1西方古代城市规划思想与理论 46 + +3.2.2西方近代城市规划思想与理论 49 + +3.2.3 20世纪以来西方现代城市规划思想与理论 51 + +3.2.4 21世纪的城市规划思想与理论变革 57 + +3.3我国土地利用规划理论与实践 58 + +3.3.1第一轮土地利用总体规划(1986-1996年) 59 + +3.3.2第二轮土地利用总体规划(1996-2006年) 59 + +3.3.3第三轮土地利用总体规划(2006一2020年) 59 + +3.4我国主体功能区规划理论与实践 60 + +3.4.1主体功能区的发展历程 60 + +3.4.2主体功能区的核心思想 61 + +3.4.4主体功能区的理论与技术方法 61 + +3.4.5主体功能区的相关实践 62 + +3.5我国生态规划理论与实践 63 + +3.5.1国内外城市生态理论研究与实践新动向 63 + +3.5.2中国生态城市的理论与实践 64 + +3.6多规合一与国土空间规划 66 + +3.6.1“多规合一”的历程 67 + +3.6.2“多规合一”的目标 67 + +3.6.3多规合一的政策演进 68 + +3.6.4“多规合一”与国土空间规划 69 + +第4章 国土空间规划基本原理与体系构成 71 + +4.1国土空间规划编制总则与基本术语 71 + +4.1.1国土空间规划编制总则 71 + +4.1.2国土空间规划基本术语 72 + +4.1.3国土空间用地分类 74 + +4.2国土空间规划体系 76 + +4.2.1国土空间规划体系的“五级” 77 + +4.2.2国土空间规划体系的“三类” 79 + +4.2.3国土空间规划体系的“四体系” 81 + +4.3国土空间规划编制基本方法 82 + +4.3.1国土空间规划基本原理 82 + +4.3.2国土空间规划管控方法 84 + +4.4国土空间规划编制基本内容 86 + +4.4.1省级国土空间规划编制基本内容 86 + +4.4.2市级国土空间规划编制基本内容 98 + +4.4.3县级国土空间规划编制基本内容 114 + +4.4.4乡镇级国土空间规划编制基本内容 132 + +第5章国土空间规划的技术工具与方法 148 + +5.1国土空间规划基础方法 148 + +5.1.1调查勘测方法 148 + +5.1.2系统评价方法 149 + +5.1.3预测分析方法 160 + +5.1.4系统制图方法 164 + +5.2国土空间规划空间分析技术 165 + +5.2.1地理信息系统(GIS)空间分析 165 + +5.2.2遥感(RS)技术 167 + +5.3国土空间规划决策方法 169 + +5.3.1空间决策博弈方法 169 + +5.3.2空间决策支持系统 169 + +5.3.3空间模拟与仿真技术 171 + +5.4国土空间规划“一张图”系统 173 + +5.4.1国土空间规划“一张图”建设步骤 173 + +5.4.2国土空间规划“一张图”实施路径 175 + +5.4.3国土空间规划“一张图”实施意义 176 + +5.5国土空间规划管理信息平台 180 + +5.5.1满足国土空间规划需求 181 + +5.5.2构建标准的数据体系 181 + +5.5.3国土空间规划信息平台的建设 182 + +5.5.4构建稳健中台保障体系 182 + +5.5.5建设“一张图”平台服务体系 183 + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..91e8465 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,114 @@ +services: + # PostgreSQL数据库 + db: + image: postgres:16-alpine + restart: always + environment: + POSTGRES_DB: course_agent_db + POSTGRES_USER: user + POSTGRES_PASSWORD: password + POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C" + volumes: + - postgres_data:/var/lib/postgresql/data + - ./backend/init_postgres.sql:/docker-entrypoint-initdb.d/init.sql + ports: + - "5433:5432" # 外部端口改为5433,避免与本地PostgreSQL冲突 + healthcheck: + test: ["CMD-SHELL", "pg_isready -U user -d course_agent_db"] + interval: 5s + timeout: 5s + retries: 5 + deploy: + resources: + limits: + memory: 1G + reservations: + memory: 512M + + # 整合的前后端服务(单容器) + app: + build: + context: . + dockerfile: Dockerfile + ports: + - "8000:8000" # 后端API + - "8001:8001" # 前端应用 + environment: + # 数据库配置 + DATABASE_URL: postgresql+psycopg://user:password@db:5432/course_agent_db + + # JWT配置 + SECRET_KEY: ${SECRET_KEY:-your-super-secret-key-change-in-production} + ALGORITHM: HS256 + ACCESS_TOKEN_EXPIRE_MINUTES: 30 + + # 硅基流动API配置 + SILICONFLOW_API_KEY: ${SILICONFLOW_API_KEY:-sk-pvvtosiglncktlucwarxilvsypqcttqizgpcfdvodgcuaezn} + SILICONFLOW_BASE_URL: ${SILICONFLOW_BASE_URL:-https://api.siliconflow.cn/v1} + SILICONFLOW_MODEL: ${SILICONFLOW_MODEL:-Qwen/Qwen3-30B-A3B-Thinking-2507} + + # 向量数据库配置 + VECTOR_STORE_PATH: /app/vector_store + EMBEDDING_MODEL: shibing624/text2vec-base-chinese + HF_ENDPOINT: https://hf-mirror.com + + # 应用配置 + APP_NAME: 国土空间规划课程智能体 + APP_VERSION: 0.1.0 + DEBUG: ${DEBUG:-False} + HOST: 0.0.0.0 + # 后端端口在uvicorn命令中指定,不需要PORT环境变量 + + # CORS配置 + ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-http://localhost:8001,http://127.0.0.1:8001} + + # 文件上传配置 + UPLOAD_DIR: /app/uploads + MAX_FILE_SIZE: 10485760 + ALLOWED_EXTENSIONS: ".pdf,.docx,.txt,.md" + + # 知识库配置 + KNOWLEDGE_BASE_DIR: /app/data/knowledge_base + ENABLE_FILE_WATCHER: True + + # 日志配置 + LOG_LEVEL: INFO + LOG_FILE: /app/logs/app.log + + # 时区配置 + TZ: Asia/Shanghai + + # 前端配置 + NEXT_PUBLIC_BACKEND_URL: http://localhost:8000 + NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:-your-nextauth-secret-change-in-production} + NEXTAUTH_URL: http://localhost:8001 + PORT: 8001 # Next.js前端端口 + HOSTNAME: 0.0.0.0 + volumes: + - ./data:/app/data + - ./runtime:/app/runtime + depends_on: + db: + condition: service_healthy + restart: always + healthcheck: + test: ["CMD", "sh", "-c", "curl -f http://localhost:8000/health && curl -f http://localhost:8001"] + interval: 30s + timeout: 10s + retries: 3 + deploy: + resources: + limits: + memory: 4G + cpus: '2.0' + reservations: + memory: 2G + cpus: '1.0' + +volumes: + postgres_data: + +networks: + default: + driver: bridge + diff --git a/docker/start-local.bat b/docker/start-local.bat new file mode 100644 index 0000000..50a8e66 --- /dev/null +++ b/docker/start-local.bat @@ -0,0 +1,40 @@ +@echo off +echo ==================================== +echo 启动国土空间规划课程智能体 +echo ==================================== +echo. + +REM 检查Docker是否运行 +docker info >nul 2>&1 +if errorlevel 1 ( + echo [错误] Docker未运行,请先启动Docker Desktop + pause + exit /b 1 +) + +REM 检查.env文件 +if not exist .env ( + echo [提示] .env文件不存在,正在从env.example创建... + copy env.example .env + echo [提示] 请编辑.env文件配置必要的参数(API密钥等) + echo. +) + +REM 启动服务 +echo [信息] 正在启动服务... +docker-compose up -d + +echo. +echo [信息] 服务启动完成! +echo. +echo 访问地址: +echo 前端应用: http://localhost:8001 +echo 后端API: http://localhost:8000 +echo API文档: http://localhost:8000/docs +echo. +echo 查看日志: docker-compose logs -f +echo 停止服务: docker-compose down +echo. +pause + + diff --git a/docker/start-local.sh b/docker/start-local.sh new file mode 100644 index 0000000..b6510f1 --- /dev/null +++ b/docker/start-local.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +echo "====================================" +echo "启动国土空间规划课程智能体" +echo "====================================" +echo + +# 检查Docker是否运行 +if ! docker info > /dev/null 2>&1; then + echo "[错误] Docker未运行,请先启动Docker" + exit 1 +fi + +# 检查.env文件 +if [ ! -f .env ]; then + echo "[提示] .env文件不存在,正在从env.example创建..." + cp env.example .env + echo "[提示] 请编辑.env文件配置必要的参数(API密钥等)" + echo +fi + +# 启动服务 +echo "[信息] 正在启动服务..." +docker-compose up -d + +echo +echo "[信息] 服务启动完成!" +echo +echo "访问地址:" +echo " 前端应用: http://localhost:8001" +echo " 后端API: http://localhost:8000" +echo " API文档: http://localhost:8000/docs" +echo +echo "查看日志: docker-compose logs -f" +echo "停止服务: docker-compose down" +echo + + diff --git a/docker/start.sh b/docker/start.sh new file mode 100644 index 0000000..212e498 --- /dev/null +++ b/docker/start.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +# 等待数据库就绪(如果使用PostgreSQL) +if [ -n "$DATABASE_URL" ] && [[ "$DATABASE_URL" == postgresql* ]]; then + echo "Waiting for database to be ready..." + until pg_isready -h db -p 5432 -U user; do + echo "Database is unavailable - sleeping" + sleep 1 + done + echo "Database is ready!" +fi + +# 启动supervisor(管理后端和前端进程) +exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf + + diff --git a/docker/supervisord.conf b/docker/supervisord.conf new file mode 100644 index 0000000..f8e68c9 --- /dev/null +++ b/docker/supervisord.conf @@ -0,0 +1,28 @@ +[supervisord] +nodaemon=true +logfile=/dev/stdout +logfile_maxbytes=0 +pidfile=/var/run/supervisord.pid + +[program:backend] +command=/app/.venv/bin/python -m uvicorn main:app --host 0.0.0.0 --port 8000 +directory=/app +autostart=true +autorestart=true +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +environment=PYTHONPATH="/app",PYTHONUNBUFFERED="1" + +[program:frontend] +command=node server.js +directory=/app/web +autostart=true +autorestart=true +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +environment=PORT="8001",HOSTNAME="0.0.0.0",NODE_ENV="production" + diff --git a/env.example b/env.example new file mode 100644 index 0000000..7308477 --- /dev/null +++ b/env.example @@ -0,0 +1,57 @@ +# 硅基流动API配置 +SILICONFLOW_API_KEY=your-api-key-here +SILICONFLOW_BASE_URL=https://api.siliconflow.cn/v1 +SILICONFLOW_MODEL=Qwen/Qwen3-30B-A3B-Thinking-2507 + +# 数据库配置(本地开发默认使用SQLite) +DATABASE_URL=sqlite:///../data/database/course_agent.db +# Docker部署使用PostgreSQL +# DATABASE_URL=postgresql+psycopg://user:password@db:5432/course_agent_db + +# JWT配置 +SECRET_KEY=your-super-secret-key-change-in-production +ALGORITHM=HS256 +ACCESS_TOKEN_EXPIRE_MINUTES=30 + +# 向量数据库配置 +VECTOR_STORE_PATH=../runtime/vector_store +EMBEDDING_MODEL=shibing624/text2vec-base-chinese +HF_ENDPOINT=https://hf-mirror.com + +# 应用配置 +APP_NAME=国土空间规划课程智能体 +APP_VERSION=0.1.0 +DEBUG=True +HOST=127.0.0.1 +PORT=8000 + +# CORS配置 +ALLOWED_ORIGINS=["http://localhost:8001","http://127.0.0.1:8001"] + +# 文件上传配置 +UPLOAD_DIR=../data/uploads +MAX_FILE_SIZE=10485760 +ALLOWED_EXTENSIONS=[".pdf",".docx",".txt",".md"] + +# 知识库配置 +KNOWLEDGE_BASE_DIR=../data/knowledge_base +ENABLE_FILE_WATCHER=True + +# 书籍配置 +BOOK_DIR=../data/book + +# 图像生成配置 +GENERATED_IMAGES_DIR=../runtime/generated_images +IMAGE_GENERATION_TIMEOUT=120 +MAX_IMAGE_SIZE=10485760 + +# 日志配置 +LOG_LEVEL=INFO +LOG_FILE=../runtime/logs/app.log + +# 前端配置 +NEXT_PUBLIC_BACKEND_URL=http://localhost:8000 +NEXTAUTH_SECRET=your-nextauth-secret-change-in-production +NEXTAUTH_URL=http://localhost:8001 + + diff --git a/web/.playwright-mcp/page-2026-05-22T01-32-31-519Z.yml b/web/.playwright-mcp/page-2026-05-22T01-32-31-519Z.yml new file mode 100644 index 0000000..dbe847c --- /dev/null +++ b/web/.playwright-mcp/page-2026-05-22T01-32-31-519Z.yml @@ -0,0 +1,1486 @@ +- generic [ref=e3]: + - banner [ref=e4]: + - heading "MIT SCL" [level=1] [ref=e6]: + - link "MIT SCL" [ref=e7] [cursor=pointer]: + - /url: / + - img "MIT SCL" [ref=e8] + - link "MIT" [ref=e10] [cursor=pointer]: + - /url: https://web.mit.edu + - img "MIT" [ref=e11] + - separator [ref=e12] + - generic [ref=e13]: + - heading "Urban imagination and social innovation through design & science" [level=2] [ref=e15] + - paragraph [ref=e17]: The real-time city is real! As layers of networks and digital information blanket urban space, new approaches to the study of the built environment are emerging. The way we describe and understand cities is being radically transformed—as are the tools we use to design them. The mission of the Senseable City Laboratory—a research initiative at the Massachusetts Institute of Technology—is to anticipate these changes and study them from a critical point of view. + - paragraph [ref=e19]: "Not bound by the methodologies of a single field, the Lab is characterized by an omni-disciplinary approach: it speaks the language of designers, planners, engineers, physicists, biologists and social scientists. Senseable is as fluent with industry partners as it is with metropolitan governments, individual citizens and disadvantaged communities. Through design and science, the Lab develops and deploys tools to learn about cities—so that cities can learn about us." + - paragraph [ref=e21]: + - text: The Senseable Global Labs initiative has established labs in + - link "Amsterdam (SCA)" [ref=e22] [cursor=pointer]: + - /url: https://senseableamsterdam.mit.edu + - text: "," + - link "Dubai (SCD)" [ref=e23] [cursor=pointer]: + - /url: https://senseabledubai.mit.edu + - text: "," + - link "Rio de Janeiro (SCR)" [ref=e24] [cursor=pointer]: + - /url: https://senseablerio.mit.edu + - text: ", and" + - link "Seoul (SCS)" [ref=e25] [cursor=pointer]: + - /url: http://senseableseoul.mit.edu + - text: ", each addressing unique urban challenges. Senseable Global Labs involves cities to become active participants in their transformation, aiming at targeted solutions for a more sustainable and inclusive future." + - generic [ref=e26]: + - generic [ref=e27]: + - heading "Projects" [level=2] [ref=e28] + - generic [ref=e29]: + - generic [ref=e30]:  + - textbox [ref=e31] + - generic [ref=e33]: + - link "Fleeting Emissions 2026" [ref=e34] [cursor=pointer]: + - /url: https://senseable.mit.edu/fleeting-emissions/ + - generic [ref=e35]: + - heading "Fleeting Emissions" [level=4] [ref=e36] + - paragraph [ref=e37]: "2026" + - img [ref=e39] + - link "Octopus 2026" [ref=e40] [cursor=pointer]: + - /url: https://senseable.mit.edu/octopus/ + - generic [ref=e41]: + - heading "Octopus" [level=4] [ref=e42] + - paragraph [ref=e43]: "2026" + - img [ref=e45] + - link "Shaded Politics 2026" [ref=e46] [cursor=pointer]: + - /url: https://senseable.mit.edu/shaded-politics/ + - generic [ref=e47]: + - heading "Shaded Politics" [level=4] [ref=e48] + - paragraph [ref=e49]: "2026" + - img [ref=e51] + - link "Data Clouds 2025" [ref=e52] [cursor=pointer]: + - /url: https://senseable.mit.edu/data-clouds-global/ + - generic [ref=e53]: + - heading "Data Clouds" [level=4] [ref=e54] + - paragraph [ref=e55]: "2025" + - img [ref=e57] + - link "Senseable Open Lab 2025" [ref=e58] [cursor=pointer]: + - /url: https://senseable.mit.edu/open-lab-2025/ + - generic [ref=e59]: + - heading "Senseable Open Lab" [level=4] [ref=e60] + - paragraph [ref=e61]: "2025" + - img [ref=e63] + - link "Global Interiors 2025" [ref=e64] [cursor=pointer]: + - /url: https://senseable.mit.edu/global-interiors/ + - generic [ref=e65]: + - heading "Global Interiors" [level=4] [ref=e66] + - paragraph [ref=e67]: "2025" + - img [ref=e69] + - link "Senseable City Seoul 2025" [ref=e70] [cursor=pointer]: + - /url: https://senseableseoul.mit.edu + - generic [ref=e71]: + - heading "Senseable City Seoul" [level=4] [ref=e72] + - paragraph [ref=e73]: "2025" + - img [ref=e75] + - link "Japan Uniqueness 2025" [ref=e76] [cursor=pointer]: + - /url: http://senseable.mit.edu/japan-uniqueness + - generic [ref=e77]: + - heading "Japan Uniqueness" [level=4] [ref=e78] + - paragraph [ref=e79]: "2025" + - img [ref=e81] + - link "Cooling Path 2025" [ref=e82] [cursor=pointer]: + - /url: https://senseable.mit.edu/cooling-path + - generic [ref=e83]: + - heading "Cooling Path" [level=4] [ref=e84] + - paragraph [ref=e85]: "2025" + - img [ref=e87] + - link "Re-leaf 2025" [ref=e88] [cursor=pointer]: + - /url: https://senseable.mit.edu/re-leaf/ + - generic [ref=e89]: + - heading "Re-leaf" [level=4] [ref=e90] + - paragraph [ref=e91]: "2025" + - img [ref=e93] + - link "Street Scores 2025" [ref=e94] [cursor=pointer]: + - /url: https://senseable.mit.edu/street-scores/ + - generic [ref=e95]: + - heading "Street Scores" [level=4] [ref=e96] + - paragraph [ref=e97]: "2025" + - img [ref=e99] + - link "Traveling Tastes 2025" [ref=e100] [cursor=pointer]: + - /url: https://senseable.mit.edu/traveling-tastes + - generic [ref=e101]: + - heading "Traveling Tastes" [level=4] [ref=e102] + - paragraph [ref=e103]: "2025" + - img [ref=e105] + - link "Slowing by Design 2025" [ref=e106] [cursor=pointer]: + - /url: https://senseable.mit.edu/slowing-design + - generic [ref=e107]: + - heading "Slowing by Design" [level=4] [ref=e108] + - paragraph [ref=e109]: "2025" + - img [ref=e111] + - link "Dust Bloom 2025" [ref=e112] [cursor=pointer]: + - /url: https://senseable.mit.edu/dust-bloom/ + - generic [ref=e113]: + - heading "Dust Bloom" [level=4] [ref=e114] + - paragraph [ref=e115]: "2025" + - img [ref=e117] + - link "Data Slots 2025" [ref=e118] [cursor=pointer]: + - /url: https://senseable.mit.edu/data-slots/ + - generic [ref=e119]: + - heading "Data Slots" [level=4] [ref=e120] + - paragraph [ref=e121]: "2025" + - img [ref=e123] + - link "Beijing Inside Out 2025" [ref=e124] [cursor=pointer]: + - /url: https://senseable.mit.edu/beijing-inside-out/ + - generic [ref=e125]: + - heading "Beijing Inside Out" [level=4] [ref=e126] + - paragraph [ref=e127]: "2025" + - img [ref=e129] + - link "Fiberspace 2025" [ref=e130] [cursor=pointer]: + - /url: https://senseable.mit.edu/fiberspace + - generic [ref=e131]: + - heading "Fiberspace" [level=4] [ref=e132] + - paragraph [ref=e133]: "2025" + - img [ref=e135] + - link "Feeling Nature 2025" [ref=e136] [cursor=pointer]: + - /url: https://senseable.mit.edu/feeling-nature/ + - generic [ref=e137]: + - heading "Feeling Nature" [level=4] [ref=e138] + - paragraph [ref=e139]: "2025" + - img [ref=e141] + - link "Green Bias 2025" [ref=e142] [cursor=pointer]: + - /url: https://senseable.mit.edu/green-bias/ + - generic [ref=e143]: + - heading "Green Bias" [level=4] [ref=e144] + - paragraph [ref=e145]: "2025" + - img [ref=e147] + - link "Boxing Reactions 2025" [ref=e148] [cursor=pointer]: + - /url: https://senseable.mit.edu/boxing-reactions/ + - generic [ref=e149]: + - heading "Boxing Reactions" [level=4] [ref=e150] + - paragraph [ref=e151]: "2025" + - img [ref=e153] + - link "Being Physical 2024" [ref=e154] [cursor=pointer]: + - /url: https://senseable.mit.edu/being-physical/ + - generic [ref=e155]: + - heading "Being Physical" [level=4] [ref=e156] + - paragraph [ref=e157]: "2024" + - img [ref=e159] + - link "Sidewalk AI 2024" [ref=e160] [cursor=pointer]: + - /url: http://senseable.mit.edu/sidewalk-ai + - generic [ref=e161]: + - heading "Sidewalk AI" [level=4] [ref=e162] + - paragraph [ref=e163]: "2024" + - img [ref=e165] + - link "Senseable City Rio 2024" [ref=e166] [cursor=pointer]: + - /url: https://senseablerio.mit.edu + - generic [ref=e167]: + - heading "Senseable City Rio" [level=4] [ref=e168] + - paragraph [ref=e169]: "2024" + - img [ref=e171] + - link "B++ 2024" [ref=e172] [cursor=pointer]: + - /url: https://senseable.mit.edu/b++ + - generic [ref=e173]: + - heading "B++" [level=4] [ref=e174] + - paragraph [ref=e175]: "2024" + - img [ref=e177] + - link "Trucking Data 2024" [ref=e178] [cursor=pointer]: + - /url: https://senseable.mit.edu/trucking-data/ + - generic [ref=e179]: + - heading "Trucking Data" [level=4] [ref=e180] + - paragraph [ref=e181]: "2024" + - img [ref=e183] + - link "Breathing Disparity 2024" [ref=e184] [cursor=pointer]: + - /url: https://senseable.mit.edu/breathing-disparity/ + - generic [ref=e185]: + - heading "Breathing Disparity" [level=4] [ref=e186] + - paragraph [ref=e187]: "2024" + - img [ref=e189] + - link "Clocking Emissions 2024" [ref=e190] [cursor=pointer]: + - /url: https://senseable.mit.edu/clocking-emissions/ + - generic [ref=e191]: + - heading "Clocking Emissions" [level=4] [ref=e192] + - paragraph [ref=e193]: "2024" + - img [ref=e195] + - link "Visual AI 2024" [ref=e196] [cursor=pointer]: + - /url: https://senseable.mit.edu/visual-AI/ + - generic [ref=e197]: + - heading "Visual AI" [level=4] [ref=e198] + - paragraph [ref=e199]: "2024" + - img [ref=e201] + - link "Timber Loops 2024" [ref=e202] [cursor=pointer]: + - /url: https://senseable.mit.edu/timber-loops/ + - generic [ref=e203]: + - heading "Timber Loops" [level=4] [ref=e204] + - paragraph [ref=e205]: "2024" + - img [ref=e207] + - link "US-15 2024" [ref=e208] [cursor=pointer]: + - /url: http://senseable.mit.edu/us-15 + - generic [ref=e209]: + - heading "US-15" [level=4] [ref=e210] + - paragraph [ref=e211]: "2024" + - img [ref=e213] + - link "What is a City? 2024" [ref=e214] [cursor=pointer]: + - /url: https://senseable.mit.edu/what-city + - generic [ref=e215]: + - heading "What is a City?" [level=4] [ref=e216] + - paragraph [ref=e217]: "2024" + - img [ref=e219] + - 'link "Forum on Future Cities: Decarbonizing Cities 2023" [ref=e220] [cursor=pointer]': + - /url: scl-forum-2023 + - generic [ref=e221]: + - 'heading "Forum on Future Cities: Decarbonizing Cities" [level=4] [ref=e222]' + - paragraph [ref=e223]: "2023" + - img [ref=e225] + - link "Dust Tracker 2023" [ref=e226] [cursor=pointer]: + - /url: https://senseable.mit.edu/dust-tracker/ + - generic [ref=e227]: + - heading "Dust Tracker" [level=4] [ref=e228] + - paragraph [ref=e229]: "2023" + - img [ref=e231] + - link "Senseable City Dubai 2023" [ref=e232] [cursor=pointer]: + - /url: https://senseabledubai.mit.edu + - generic [ref=e233]: + - heading "Senseable City Dubai" [level=4] [ref=e234] + - paragraph [ref=e235]: "2023" + - img [ref=e237] + - link "Jackson Boiling 2023" [ref=e238] [cursor=pointer]: + - /url: https://senseable.mit.edu/jacksonboiling/ + - generic [ref=e239]: + - heading "Jackson Boiling" [level=4] [ref=e240] + - paragraph [ref=e241]: "2023" + - img [ref=e243] + - link "Flatburn 2023" [ref=e244] [cursor=pointer]: + - /url: https://senseable.mit.edu/flatburn + - generic [ref=e245]: + - heading "Flatburn" [level=4] [ref=e246] + - paragraph [ref=e247]: "2023" + - img [ref=e249] + - link "Smart Curbs 2023" [ref=e250] [cursor=pointer]: + - /url: https://senseable.mit.edu/smart-curbs + - generic [ref=e251]: + - heading "Smart Curbs" [level=4] [ref=e252] + - paragraph [ref=e253]: "2023" + - img [ref=e255] + - link "Bike Tra|ffi|cking 2023" [ref=e256] [cursor=pointer]: + - /url: https://senseable.mit.edu/bike-trafficking/ + - generic [ref=e257]: + - heading "Bike Tra|ffi|cking" [level=4] [ref=e258] + - paragraph [ref=e259]: "2023" + - img [ref=e261] + - link "Slow Zones 2023" [ref=e262] [cursor=pointer]: + - /url: https://senseable.mit.edu/slow-zones/ + - generic [ref=e263]: + - heading "Slow Zones" [level=4] [ref=e264] + - paragraph [ref=e265]: "2023" + - img [ref=e267] + - link "Potato Project 2022" [ref=e268] [cursor=pointer]: + - /url: https://senseable.mit.edu/potato/ + - generic [ref=e269]: + - heading "Potato Project" [level=4] [ref=e270] + - paragraph [ref=e271]: "2022" + - img [ref=e273] + - link "Good Vibrations 2022" [ref=e274] [cursor=pointer]: + - /url: https://senseable.mit.edu/good_vibrations/ + - generic [ref=e275]: + - heading "Good Vibrations" [level=4] [ref=e276] + - paragraph [ref=e277]: "2022" + - img [ref=e279] + - link "Proximate 2022" [ref=e280] [cursor=pointer]: + - /url: http://senseable.mit.edu/proximate + - generic [ref=e281]: + - heading "Proximate" [level=4] [ref=e282] + - paragraph [ref=e283]: "2022" + - img [ref=e285] + - link "Senseable City Amsterdam 2022" [ref=e286] [cursor=pointer]: + - /url: https://senseableamsterdam.mit.edu + - generic [ref=e287]: + - heading "Senseable City Amsterdam" [level=4] [ref=e288] + - paragraph [ref=e289]: "2022" + - img [ref=e291] + - link "Space Bubbles 2022" [ref=e292] [cursor=pointer]: + - /url: https://senseable.mit.edu/space-bubbles/ + - generic [ref=e293]: + - heading "Space Bubbles" [level=4] [ref=e294] + - paragraph [ref=e295]: "2022" + - img [ref=e297] + - link "Stockholm-19 2022" [ref=e298] [cursor=pointer]: + - /url: https://senseable.mit.edu/stockholm-19/ + - generic [ref=e299]: + - heading "Stockholm-19" [level=4] [ref=e300] + - paragraph [ref=e301]: "2022" + - img [ref=e303] + - link "Roboat 2021" [ref=e304] [cursor=pointer]: + - /url: http://roboat.org/ + - generic [ref=e305]: + - heading "Roboat" [level=4] [ref=e306] + - paragraph [ref=e307]: "2021" + - img [ref=e309] + - link "Pointiest Path 2021" [ref=e310] [cursor=pointer]: + - /url: https://senseable.mit.edu/pointiest-path/ + - generic [ref=e311]: + - heading "Pointiest Path" [level=4] [ref=e312] + - paragraph [ref=e313]: "2021" + - img [ref=e315] + - link "Sensing Light 2021" [ref=e316] [cursor=pointer]: + - /url: https://senseable.mit.edu/sensing-light/ + - generic [ref=e317]: + - heading "Sensing Light" [level=4] [ref=e318] + - paragraph [ref=e319]: "2021" + - img [ref=e321] + - link "Wanderlust 2021" [ref=e322] [cursor=pointer]: + - /url: https://senseable.mit.edu/wanderlust/ + - generic [ref=e323]: + - heading "Wanderlust" [level=4] [ref=e324] + - paragraph [ref=e325]: "2021" + - img [ref=e327] + - link "Liminal Ghettos 2021" [ref=e328] [cursor=pointer]: + - /url: http://senseable.mit.edu/porto/ + - generic [ref=e329]: + - heading "Liminal Ghettos" [level=4] [ref=e330] + - paragraph [ref=e331]: "2021" + - img [ref=e333] + - link "Favelas 4D 2021" [ref=e334] [cursor=pointer]: + - /url: https://senseable.mit.edu/favelas/ + - generic [ref=e335]: + - heading "Favelas 4D" [level=4] [ref=e336] + - paragraph [ref=e337]: "2021" + - img [ref=e339] + - link "Diversitree 2021" [ref=e340] [cursor=pointer]: + - /url: https://senseable.mit.edu/diversitree/ + - generic [ref=e341]: + - heading "Diversitree" [level=4] [ref=e342] + - paragraph [ref=e343]: "2021" + - img [ref=e345] + - link "Stockholm Flows 2021" [ref=e346] [cursor=pointer]: + - /url: https://senseable.mit.edu/stockholm-flows/ + - generic [ref=e347]: + - heading "Stockholm Flows" [level=4] [ref=e348] + - paragraph [ref=e349]: "2021" + - img [ref=e351] + - link "Senseable City Guides 2021" [ref=e352] [cursor=pointer]: + - /url: https://senseable.mit.edu/senseable-guides/ + - generic [ref=e353]: + - heading "Senseable City Guides" [level=4] [ref=e354] + - paragraph [ref=e355]: "2021" + - img [ref=e357] + - link "Desirable Streets 2021" [ref=e358] [cursor=pointer]: + - /url: https://senseable.mit.edu/desirable-streets/ + - generic [ref=e359]: + - heading "Desirable Streets" [level=4] [ref=e360] + - paragraph [ref=e361]: "2021" + - img [ref=e363] + - link "Rebound 2021" [ref=e364] [cursor=pointer]: + - /url: https://senseable.mit.edu/rebound/ + - generic [ref=e365]: + - heading "Rebound" [level=4] [ref=e366] + - paragraph [ref=e367]: "2021" + - img [ref=e369] + - link "City Veins 2020" [ref=e370] [cursor=pointer]: + - /url: https://senseable.mit.edu/city-veins + - generic [ref=e371]: + - heading "City Veins" [level=4] [ref=e372] + - paragraph [ref=e373]: "2020" + - img [ref=e375] + - link "Sonic Cities 2020" [ref=e376] [cursor=pointer]: + - /url: https://senseable.mit.edu/sonic-cities + - generic [ref=e377]: + - heading "Sonic Cities" [level=4] [ref=e378] + - paragraph [ref=e379]: "2020" + - img [ref=e381] + - link "Waste Streams 2020" [ref=e382] [cursor=pointer]: + - /url: https://senseable.mit.edu/waste-streams/ + - generic [ref=e383]: + - heading "Waste Streams" [level=4] [ref=e384] + - paragraph [ref=e385]: "2020" + - img [ref=e387] + - link "SCL Webinar Series 2020" [ref=e388] [cursor=pointer]: + - /url: http://senseable.mit.edu/webinars/ + - generic [ref=e389]: + - heading "SCL Webinar Series" [level=4] [ref=e390] + - paragraph [ref=e391]: "2020" + - img [ref=e393] + - link "Solar Cities 2020" [ref=e394] [cursor=pointer]: + - /url: https://senseable.mit.edu/solar-cities/ + - generic [ref=e395]: + - heading "Solar Cities" [level=4] [ref=e396] + - paragraph [ref=e397]: "2020" + - img [ref=e399] + - link "American DNA 2020" [ref=e400] [cursor=pointer]: + - /url: https://senseable.mit.edu/american-dna + - generic [ref=e401]: + - heading "American DNA" [level=4] [ref=e402] + - paragraph [ref=e403]: "2020" + - img [ref=e405] + - link "Singapore Calling 2019" [ref=e406] [cursor=pointer]: + - /url: https://senseable.mit.edu/singapore-calling/ + - generic [ref=e407]: + - heading "Singapore Calling" [level=4] [ref=e408] + - paragraph [ref=e409]: "2019" + - img [ref=e411] + - link "Underworlds 2019" [ref=e412] [cursor=pointer]: + - /url: http://underworlds.mit.edu + - generic [ref=e413]: + - heading "Underworlds" [level=4] [ref=e414] + - paragraph [ref=e415]: "2019" + - img [ref=e417] + - link "roundAround 2019" [ref=e418] [cursor=pointer]: + - /url: https://senseable.mit.edu/roundaround/ + - generic [ref=e419]: + - heading "roundAround" [level=4] [ref=e420] + - paragraph [ref=e421]: "2019" + - img [ref=e423] + - link "AI Station 2019" [ref=e424] [cursor=pointer]: + - /url: https://senseable.mit.edu/ai-station/ + - generic [ref=e425]: + - heading "AI Station" [level=4] [ref=e426] + - paragraph [ref=e427]: "2019" + - img [ref=e429] + - link "Tasty Data 2019" [ref=e430] [cursor=pointer]: + - /url: https://senseable.mit.edu/tasty-data/ + - generic [ref=e431]: + - heading "Tasty Data" [level=4] [ref=e432] + - paragraph [ref=e433]: "2019" + - img [ref=e435] + - link "[In]distinct Cities 2019" [ref=e436] [cursor=pointer]: + - /url: https://senseable.mit.edu/indistinct_cities/ + - generic [ref=e437]: + - heading "[In]distinct Cities" [level=4] [ref=e438] + - paragraph [ref=e439]: "2019" + - img [ref=e441] + - link "Urban Sensing 2019" [ref=e442] [cursor=pointer]: + - /url: http://senseable.mit.edu/urban-sensing + - generic [ref=e443]: + - heading "Urban Sensing" [level=4] [ref=e444] + - paragraph [ref=e445]: "2019" + - img [ref=e447] + - 'link "Forum on Future Cities: Urban Intelligence 2019" [ref=e448] [cursor=pointer]': + - /url: https://senseable.mit.edu/urbanintelligence/ + - generic [ref=e449]: + - 'heading "Forum on Future Cities: Urban Intelligence" [level=4] [ref=e450]' + - paragraph [ref=e451]: "2019" + - img [ref=e453] + - link "Driving DNA 2019" [ref=e454] [cursor=pointer]: + - /url: https://senseable.mit.edu/driving_dna/ + - generic [ref=e455]: + - heading "Driving DNA" [level=4] [ref=e456] + - paragraph [ref=e457]: "2019" + - img [ref=e459] + - link "Weibo Smog 2019" [ref=e460] [cursor=pointer]: + - /url: https://senseable.mit.edu/weibo-smog/ + - generic [ref=e461]: + - heading "Weibo Smog" [level=4] [ref=e462] + - paragraph [ref=e463]: "2019" + - img [ref=e465] + - link "Unparking 2018" [ref=e466] [cursor=pointer]: + - /url: https://senseable.mit.edu/unparking + - generic [ref=e467]: + - heading "Unparking" [level=4] [ref=e468] + - paragraph [ref=e469]: "2018" + - img [ref=e471] + - link "Minimum Fleet 2018" [ref=e472] [cursor=pointer]: + - /url: https://senseable.mit.edu/MinimumFleet/ + - generic [ref=e473]: + - heading "Minimum Fleet" [level=4] [ref=e474] + - paragraph [ref=e475]: "2018" + - img [ref=e477] + - link "Summer Day in Amsterdam 2018" [ref=e478] [cursor=pointer]: + - /url: https://senseable.mit.edu/roboat_summer_day/ + - generic [ref=e479]: + - heading "Summer Day in Amsterdam" [level=4] [ref=e480] + - paragraph [ref=e481]: "2018" + - img [ref=e483] + - 'link "City Nature Challenge 2018: Boston Area 2018" [ref=e484] [cursor=pointer]': + - /url: https://senseable.mit.edu/city-nature-challenge + - generic [ref=e485]: + - 'heading "City Nature Challenge 2018: Boston Area" [level=4] [ref=e486]' + - paragraph [ref=e487]: "2018" + - img [ref=e489] + - link "Clean Air Nairobi 2018" [ref=e490] [cursor=pointer]: + - /url: https://senseable.mit.edu/cleanair-nairobi/ + - generic [ref=e491]: + - heading "Clean Air Nairobi" [level=4] [ref=e492] + - paragraph [ref=e493]: "2018" + - img [ref=e495] + - link "City Scanner 2018" [ref=e496] [cursor=pointer]: + - /url: http://senseable.mit.edu/city-scanner + - generic [ref=e497]: + - heading "City Scanner" [level=4] [ref=e498] + - paragraph [ref=e499]: "2018" + - img [ref=e501] + - link "Friendly Cities 2018" [ref=e502] [cursor=pointer]: + - /url: https://senseable.mit.edu/friendly-cities/ + - generic [ref=e503]: + - heading "Friendly Cities" [level=4] [ref=e504] + - paragraph [ref=e505]: "2018" + - img [ref=e507] + - link "Global Mobility Index 2018" [ref=e508] [cursor=pointer]: + - /url: https://senseable.mit.edu/global-mobility-index + - generic [ref=e509]: + - heading "Global Mobility Index" [level=4] [ref=e510] + - paragraph [ref=e511]: "2018" + - img [ref=e513] + - 'link "Forum on Future Cities: 4th Industrial Revolution (IR) 2017" [ref=e514] [cursor=pointer]': + - /url: https://senseable.mit.edu/future-cities-2017/ + - generic [ref=e515]: + - 'heading "Forum on Future Cities: 4th Industrial Revolution (IR)" [level=4] [ref=e516]' + - paragraph [ref=e517]: "2017" + - img [ref=e519] + - 'link "Gangnam Poop: Underworlds in Seoul 2017" [ref=e520] [cursor=pointer]': + - /url: https://senseable.mit.edu/underworlds-seoul + - generic [ref=e521]: + - 'heading "Gangnam Poop: Underworlds in Seoul" [level=4] [ref=e522]' + - paragraph [ref=e523]: "2017" + - img [ref=e525] + - link "City Ways 2017" [ref=e526] [cursor=pointer]: + - /url: http://senseable.mit.edu/cityways/ + - generic [ref=e527]: + - heading "City Ways" [level=4] [ref=e528] + - paragraph [ref=e529]: "2017" + - img [ref=e531] + - link "MIT World 2017" [ref=e532] [cursor=pointer]: + - /url: https://senseable.mit.edu/mit-world + - generic [ref=e533]: + - heading "MIT World" [level=4] [ref=e534] + - paragraph [ref=e535]: "2017" + - img [ref=e537] + - link "Shareable Cities 2017" [ref=e538] [cursor=pointer]: + - /url: https://senseable.mit.edu/shareable-cities + - generic [ref=e539]: + - heading "Shareable Cities" [level=4] [ref=e540] + - paragraph [ref=e541]: "2017" + - img [ref=e543] + - link "Sensing Vehicle 2017" [ref=e544] [cursor=pointer]: + - /url: https://senseable.mit.edu/vwsensing/ + - generic [ref=e545]: + - heading "Sensing Vehicle" [level=4] [ref=e546] + - paragraph [ref=e547]: "2017" + - img [ref=e549] + - link "Treepedia 2016" [ref=e550] [cursor=pointer]: + - /url: http://senseable.mit.edu/treepedia + - generic [ref=e551]: + - heading "Treepedia" [level=4] [ref=e552] + - paragraph [ref=e553]: "2016" + - img [ref=e555] + - link "PisaPOOL 2016" [ref=e556] [cursor=pointer]: + - /url: https://senseable.mit.edu/pisa/ + - generic [ref=e557]: + - heading "PisaPOOL" [level=4] [ref=e558] + - paragraph [ref=e559]: "2016" + - img [ref=e561] + - link "Urban Exposures 2016" [ref=e562] [cursor=pointer]: + - /url: https://senseable.mit.edu/urban-exposures + - generic [ref=e563]: + - heading "Urban Exposures" [level=4] [ref=e564] + - paragraph [ref=e565]: "2016" + - img [ref=e567] + - link "Monitour 2016" [ref=e568] [cursor=pointer]: + - /url: http://senseable.mit.edu/monitour + - generic [ref=e569]: + - heading "Monitour" [level=4] [ref=e570] + - paragraph [ref=e571]: "2016" + - img [ref=e573] + - 'link "Forum on Future Cities: Bits and Bricks 2016" [ref=e574] [cursor=pointer]': + - /url: https://senseable.mit.edu/bitsbricks/ + - generic [ref=e575]: + - 'heading "Forum on Future Cities: Bits and Bricks" [level=4] [ref=e576]' + - paragraph [ref=e577]: "2016" + - img [ref=e579] + - link "Light Traffic 2016" [ref=e580] [cursor=pointer]: + - /url: https://senseable.mit.edu/light-traffic + - generic [ref=e581]: + - heading "Light Traffic" [level=4] [ref=e582] + - paragraph [ref=e583]: "2016" + - img [ref=e585] + - link "Urban Lens 2016" [ref=e586] [cursor=pointer]: + - /url: https://senseable.mit.edu/urban-lens + - generic [ref=e587]: + - heading "Urban Lens" [level=4] [ref=e588] + - paragraph [ref=e589]: "2016" + - img [ref=e591] + - link "Waterfly 2015" [ref=e592] [cursor=pointer]: + - /url: https://senseable.mit.edu/waterfly/ + - generic [ref=e593]: + - heading "Waterfly" [level=4] [ref=e594] + - paragraph [ref=e595]: "2015" + - img [ref=e597] + - link "A Tale of Many Cities 2014" [ref=e598] [cursor=pointer]: + - /url: https://senseable.mit.edu/manycities/ + - generic [ref=e599]: + - heading "A Tale of Many Cities" [level=4] [ref=e600] + - paragraph [ref=e601]: "2014" + - img [ref=e603] + - link "The Road Ahead 2014" [ref=e604] [cursor=pointer]: + - /url: https://senseable.mit.edu/roadahead/ + - generic [ref=e605]: + - heading "The Road Ahead" [level=4] [ref=e606] + - paragraph [ref=e607]: "2014" + - img [ref=e609] + - link "Louvre Museum’s DNA 2014" [ref=e610] [cursor=pointer]: + - /url: https://senseable.mit.edu/louvre/ + - generic [ref=e611]: + - heading "Louvre Museum’s DNA" [level=4] [ref=e612] + - paragraph [ref=e613]: "2014" + - img [ref=e615] + - link "Drinking Data 2014" [ref=e616] [cursor=pointer]: + - /url: https://senseable.mit.edu/drinking-data/ + - generic [ref=e617]: + - heading "Drinking Data" [level=4] [ref=e618] + - paragraph [ref=e619]: "2014" + - img [ref=e621] + - link "DriveWAVE 2014" [ref=e622] [cursor=pointer]: + - /url: https://senseable.mit.edu/wave/ + - generic [ref=e623]: + - heading "DriveWAVE" [level=4] [ref=e624] + - paragraph [ref=e625]: "2014" + - img [ref=e627] + - link "Community Detection 2014" [ref=e628] [cursor=pointer]: + - /url: https://senseable.mit.edu/community_detection/ + - generic [ref=e629]: + - heading "Community Detection" [level=4] [ref=e630] + - paragraph [ref=e631]: "2014" + - img [ref=e633] + - link "Local Warming 2014 2014" [ref=e634] [cursor=pointer]: + - /url: https://senseable.mit.edu/localwarming2014/ + - generic [ref=e635]: + - heading "Local Warming 2014" [level=4] [ref=e636] + - paragraph [ref=e637]: "2014" + - img [ref=e639] + - link "Urban Villages 2014" [ref=e640] [cursor=pointer]: + - /url: https://senseable.mit.edu/urbanvillages/ + - generic [ref=e641]: + - heading "Urban Villages" [level=4] [ref=e642] + - paragraph [ref=e643]: "2014" + - img [ref=e645] + - link "Hubcab 2014" [ref=e646] [cursor=pointer]: + - /url: http://senseable.mit.edu/hubcab-legacy/ + - generic [ref=e647]: + - heading "Hubcab" [level=4] [ref=e648] + - paragraph [ref=e649]: "2014" + - img [ref=e651] + - link "Tweet Bursts 2014" [ref=e652] [cursor=pointer]: + - /url: https://senseable.mit.edu/tweetbursts/ + - generic [ref=e653]: + - heading "Tweet Bursts" [level=4] [ref=e654] + - paragraph [ref=e655]: "2014" + - img [ref=e657] + - link "Ambient Mobility 2014" [ref=e658] [cursor=pointer]: + - /url: https://senseable.mit.edu/ambient-mobility/ + - generic [ref=e659]: + - heading "Ambient Mobility" [level=4] [ref=e660] + - paragraph [ref=e661]: "2014" + - img [ref=e663] + - link "One Country Two Lungs 2014" [ref=e664] [cursor=pointer]: + - /url: https://senseable.mit.edu/twolungs/ + - generic [ref=e665]: + - heading "One Country Two Lungs" [level=4] [ref=e666] + - paragraph [ref=e667]: "2014" + - img [ref=e669] + - link "DataDrives 2014" [ref=e670] [cursor=pointer]: + - /url: https://senseable.mit.edu/datadrives/ + - generic [ref=e671]: + - heading "DataDrives" [level=4] [ref=e672] + - paragraph [ref=e673]: "2014" + - img [ref=e675] + - link "SkyCall 2013" [ref=e676] [cursor=pointer]: + - /url: https://senseable.mit.edu/skycall/ + - generic [ref=e677]: + - heading "SkyCall" [level=4] [ref=e678] + - paragraph [ref=e679]: "2013" + - img [ref=e681] + - link "Road Frustration Index 2013" [ref=e682] [cursor=pointer]: + - /url: https://senseable.mit.edu/rfi/ + - generic [ref=e683]: + - heading "Road Frustration Index" [level=4] [ref=e684] + - paragraph [ref=e685]: "2013" + - img [ref=e687] + - link "Makr Shakr 2013" [ref=e688] [cursor=pointer]: + - /url: http://makrshakr.com/OLD/index.html + - generic [ref=e689]: + - heading "Makr Shakr" [level=4] [ref=e690] + - paragraph [ref=e691]: "2013" + - img [ref=e693] + - link "Local Warming 2013" [ref=e694] [cursor=pointer]: + - /url: https://senseable.mit.edu/local-warming/ + - generic [ref=e695]: + - heading "Local Warming" [level=4] [ref=e696] + - paragraph [ref=e697]: "2013" + - img [ref=e699] + - link "Signature of Humanity 2013" [ref=e700] [cursor=pointer]: + - /url: https://senseable.mit.edu/signature-of-humanity/ + - generic [ref=e701]: + - heading "Signature of Humanity" [level=4] [ref=e702] + - paragraph [ref=e703]: "2013" + - img [ref=e705] + - link "Boston 311 2012" [ref=e706] [cursor=pointer]: + - /url: https://senseable.mit.edu/bos311/ + - generic [ref=e707]: + - heading "Boston 311" [level=4] [ref=e708] + - paragraph [ref=e709]: "2012" + - img [ref=e711] + - link "Guggenheim Berlin | Dynamic Places 2012" [ref=e712] [cursor=pointer]: + - /url: https://senseable.mit.edu/guggenheim/ + - generic [ref=e713]: + - heading "Guggenheim Berlin | Dynamic Places" [level=4] [ref=e714] + - paragraph [ref=e715]: "2012" + - img [ref=e717] + - link "Parcupine 2012" [ref=e718] [cursor=pointer]: + - /url: https://senseable.mit.edu/parcupine/ + - generic [ref=e719]: + - heading "Parcupine" [level=4] [ref=e720] + - paragraph [ref=e721]: "2012" + - img [ref=e723] + - link "Kinect Kinetics 2012" [ref=e724] [cursor=pointer]: + - /url: https://senseable.mit.edu/kinectkinetics/ + - generic [ref=e725]: + - heading "Kinect Kinetics" [level=4] [ref=e726] + - paragraph [ref=e727]: "2012" + - img [ref=e729] + - link "Future Olympic Village 2012" [ref=e730] [cursor=pointer]: + - /url: https://senseable.mit.edu/future-olympic-village/ + - generic [ref=e731]: + - heading "Future Olympic Village" [level=4] [ref=e732] + - paragraph [ref=e733]: "2012" + - img [ref=e735] + - link "Senseable Rio 2012" [ref=e736] [cursor=pointer]: + - /url: https://senseable.mit.edu/rio/ + - generic [ref=e737]: + - heading "Senseable Rio" [level=4] [ref=e738] + - paragraph [ref=e739]: "2012" + - img [ref=e741] + - link "Visual Exploration of Urban Mobility 2012" [ref=e742] [cursor=pointer]: + - /url: https://senseable.mit.edu/visual-explorations-urban-mobility/ + - generic [ref=e743]: + - heading "Visual Exploration of Urban Mobility" [level=4] [ref=e744] + - paragraph [ref=e745]: "2012" + - img [ref=e747] + - link "Spring Spree 2012" [ref=e748] [cursor=pointer]: + - /url: https://senseable.mit.edu/bbva/ + - generic [ref=e749]: + - heading "Spring Spree" [level=4] [ref=e750] + - paragraph [ref=e751]: "2012" + - img [ref=e753] + - link "United Cities of America 2012" [ref=e754] [cursor=pointer]: + - /url: https://senseable.mit.edu/unitedcities/ + - generic [ref=e755]: + - heading "United Cities of America" [level=4] [ref=e756] + - paragraph [ref=e757]: "2012" + - img [ref=e759] + - link "Forage Tracking 2012" [ref=e760] [cursor=pointer]: + - /url: https://senseable.mit.edu/foragetracking/ + - generic [ref=e761]: + - heading "Forage Tracking" [level=4] [ref=e762] + - paragraph [ref=e763]: "2012" + - img [ref=e765] + - link "World Economic Forum | Urban Anthologies 2012" [ref=e766] [cursor=pointer]: + - /url: https://senseable.mit.edu/wef/ + - generic [ref=e767]: + - heading "World Economic Forum | Urban Anthologies" [level=4] [ref=e768] + - paragraph [ref=e769]: "2012" + - img [ref=e771] + - link "MoMA Follow-up 2012" [ref=e772] [cursor=pointer]: + - /url: https://senseable.mit.edu/moma-followup/ + - generic [ref=e773]: + - heading "MoMA Follow-up" [level=4] [ref=e774] + - paragraph [ref=e775]: "2012" + - img [ref=e777] + - link "Trains of Data 2011" [ref=e778] [cursor=pointer]: + - /url: https://senseable.mit.edu/trainsofdata/ + - generic [ref=e779]: + - heading "Trains of Data" [level=4] [ref=e780] + - paragraph [ref=e781]: "2011" + - img [ref=e783] + - link "Matching Markets 2011" [ref=e784] [cursor=pointer]: + - /url: https://senseable.mit.edu/matchingmarkets/ + - generic [ref=e785]: + - heading "Matching Markets" [level=4] [ref=e786] + - paragraph [ref=e787]: "2011" + - img [ref=e789] + - link "BackTalk 2011" [ref=e790] [cursor=pointer]: + - /url: https://senseable.mit.edu/backtalk/ + - generic [ref=e791]: + - heading "BackTalk" [level=4] [ref=e792] + - paragraph [ref=e793]: "2011" + - img [ref=e795] + - link "Health Infoscape 2011" [ref=e796] [cursor=pointer]: + - /url: https://senseable.mit.edu/healthinfoscape/ + - generic [ref=e797]: + - heading "Health Infoscape" [level=4] [ref=e798] + - paragraph [ref=e799]: "2011" + - img [ref=e801] + - link "Open Source Architecture 2011" [ref=e802] [cursor=pointer]: + - /url: https://senseable.mit.edu/osarc/ + - generic [ref=e803]: + - heading "Open Source Architecture" [level=4] [ref=e804] + - paragraph [ref=e805]: "2011" + - img [ref=e807] + - link "The Connected States of America 2011" [ref=e808] [cursor=pointer]: + - /url: https://senseable.mit.edu/csa/ + - generic [ref=e809]: + - heading "The Connected States of America" [level=4] [ref=e810] + - paragraph [ref=e811]: "2011" + - img [ref=e813] + - link "AIDA 2 2011" [ref=e814] [cursor=pointer]: + - /url: https://senseable.mit.edu/aida2/ + - generic [ref=e815]: + - heading "AIDA 2" [level=4] [ref=e816] + - paragraph [ref=e817]: "2011" + - img [ref=e819] + - link "Senseable on Senseable 2011" [ref=e820] [cursor=pointer]: + - /url: https://senseable.mit.edu/sos/ + - generic [ref=e821]: + - heading "Senseable on Senseable" [level=4] [ref=e822] + - paragraph [ref=e823]: "2011" + - img [ref=e825] + - link "Bits & Bodies 2011" [ref=e826] [cursor=pointer]: + - /url: https://senseable.mit.edu/bits/ + - generic [ref=e827]: + - heading "Bits & Bodies" [level=4] [ref=e828] + - paragraph [ref=e829]: "2011" + - img [ref=e831] + - link "My Architect 2011" [ref=e832] [cursor=pointer]: + - /url: https://senseable.mit.edu/myarchitect/index.php + - generic [ref=e833]: + - heading "My Architect" [level=4] [ref=e834] + - paragraph [ref=e835]: "2011" + - img [ref=e837] + - link "TEDTalk 2011" [ref=e838] [cursor=pointer]: + - /url: https://senseable.mit.edu/ted2011/ + - generic [ref=e839]: + - heading "TEDTalk" [level=4] [ref=e840] + - paragraph [ref=e841]: "2011" + - img [ref=e843] + - link "CO2GO 2011" [ref=e844] [cursor=pointer]: + - /url: https://senseable.mit.edu/co2go/ + - generic [ref=e845]: + - heading "CO2GO" [level=4] [ref=e846] + - paragraph [ref=e847]: "2011" + - img [ref=e849] + - link "Borderline 2010" [ref=e850] [cursor=pointer]: + - /url: https://senseable.mit.edu/network/network&society2.html + - generic [ref=e851]: + - heading "Borderline" [level=4] [ref=e852] + - paragraph [ref=e853]: "2010" + - img [ref=e855] + - link "Seaswarm 2010" [ref=e856] [cursor=pointer]: + - /url: https://senseable.mit.edu/seaswarm/ + - generic [ref=e857]: + - heading "Seaswarm" [level=4] [ref=e858] + - paragraph [ref=e859]: "2010" + - img [ref=e861] + - link "LIVE Singapore! 2010" [ref=e862] [cursor=pointer]: + - /url: https://senseable.mit.edu/livesingapore/ + - generic [ref=e863]: + - heading "LIVE Singapore!" [level=4] [ref=e864] + - paragraph [ref=e865]: "2010" + - img [ref=e867] + - link "Network & Society 2010" [ref=e868] [cursor=pointer]: + - /url: https://senseable.mit.edu/network/ + - generic [ref=e869]: + - heading "Network & Society" [level=4] [ref=e870] + - paragraph [ref=e871]: "2010" + - img [ref=e873] + - link "Future ENEL 2010" [ref=e874] [cursor=pointer]: + - /url: https://senseable.mit.edu/enel/ + - generic [ref=e875]: + - heading "Future ENEL" [level=4] [ref=e876] + - paragraph [ref=e877]: "2010" + - img [ref=e879] + - link "Flyfire 2010" [ref=e880] [cursor=pointer]: + - /url: https://senseable.mit.edu/flyfire/ + - generic [ref=e881]: + - heading "Flyfire" [level=4] [ref=e882] + - paragraph [ref=e883]: "2010" + - img [ref=e885] + - link "the CLOUD 2010" [ref=e886] [cursor=pointer]: + - /url: http://www.raisethecloud.org + - generic [ref=e887]: + - heading "the CLOUD" [level=4] [ref=e888] + - paragraph [ref=e889]: "2010" + - img [ref=e891] + - link "Trash Track 2009" [ref=e892] [cursor=pointer]: + - /url: https://senseable.mit.edu/trashtrack/ + - generic [ref=e893]: + - heading "Trash Track" [level=4] [ref=e894] + - paragraph [ref=e895]: "2009" + - img [ref=e897] + - 'link "AIDA: Affective Intelligent Driving Agent 2009" [ref=e898] [cursor=pointer]': + - /url: https://senseable.mit.edu/aida/ + - generic [ref=e899]: + - 'heading "AIDA: Affective Intelligent Driving Agent" [level=4] [ref=e900]' + - paragraph [ref=e901]: "2009" + - img [ref=e903] + - link "The Copenhagen Wheel 2009" [ref=e904] [cursor=pointer]: + - /url: https://senseable.mit.edu/copenhagenwheel/ + - generic [ref=e905]: + - heading "The Copenhagen Wheel" [level=4] [ref=e906] + - paragraph [ref=e907]: "2009" + - img [ref=e909] + - link "Currentcity 2009" [ref=e910] [cursor=pointer]: + - /url: https://senseable.mit.edu/currentcity/ + - generic [ref=e911]: + - heading "Currentcity" [level=4] [ref=e912] + - paragraph [ref=e913]: "2009" + - img [ref=e915] + - link "Spacebook 2009" [ref=e916] [cursor=pointer]: + - /url: https://senseable.mit.edu/spacebook/ + - generic [ref=e917]: + - heading "Spacebook" [level=4] [ref=e918] + - paragraph [ref=e919]: "2009" + - img [ref=e921] + - link "GeoBlog 2009" [ref=e922] [cursor=pointer]: + - /url: https://senseable.mit.edu/geoblog/ + - generic [ref=e923]: + - heading "GeoBlog" [level=4] [ref=e924] + - paragraph [ref=e925]: "2009" + - img [ref=e927] + - link "EyeStop 2009" [ref=e928] [cursor=pointer]: + - /url: https://senseable.mit.edu/eyestop/ + - generic [ref=e929]: + - heading "EyeStop" [level=4] [ref=e930] + - paragraph [ref=e931]: "2009" + - img [ref=e933] + - link "Obama One People 2009" [ref=e934] [cursor=pointer]: + - /url: https://senseable.mit.edu/obama/ + - generic [ref=e935]: + - heading "Obama One People" [level=4] [ref=e936] + - paragraph [ref=e937]: "2009" + - img [ref=e939] + - link "Los Ojos del Mundo 2007" [ref=e940] [cursor=pointer]: + - /url: https://senseable.mit.edu/worldseyes/ + - generic [ref=e941]: + - heading "Los Ojos del Mundo" [level=4] [ref=e942] + - paragraph [ref=e943]: "2007" + - img [ref=e945] + - link "Real Time Copenhagen 2007" [ref=e946] [cursor=pointer]: + - /url: https://senseable.mit.edu/realtimecopenhagen/ + - generic [ref=e947]: + - heading "Real Time Copenhagen" [level=4] [ref=e948] + - paragraph [ref=e949]: "2007" + - img [ref=e951] + - link "The Wireless City 2007" [ref=e952] [cursor=pointer]: + - /url: https://senseable.mit.edu/florence/ + - generic [ref=e953]: + - heading "The Wireless City" [level=4] [ref=e954] + - paragraph [ref=e955]: "2007" + - img [ref=e957] + - link "Digital Water Pavilion 2007" [ref=e958] [cursor=pointer]: + - /url: http://www.carloratti.com/project/digital-water-pavilion/ + - generic [ref=e959]: + - heading "Digital Water Pavilion" [level=4] [ref=e960] + - paragraph [ref=e961]: "2007" + - img [ref=e963] + - link "WikiCity Rome 2007" [ref=e964] [cursor=pointer]: + - /url: https://senseable.mit.edu/wikicity/rome/ + - generic [ref=e965]: + - heading "WikiCity Rome" [level=4] [ref=e966] + - paragraph [ref=e967]: "2007" + - img [ref=e969] + - link "Lochaber Live 2007" [ref=e970] [cursor=pointer]: + - /url: https://senseable.mit.edu/lochaberlive/ + - generic [ref=e971]: + - heading "Lochaber Live" [level=4] [ref=e972] + - paragraph [ref=e973]: "2007" + - img [ref=e975] + - link "WikiCity 2007" [ref=e976] [cursor=pointer]: + - /url: https://senseable.mit.edu/wikicity/ + - generic [ref=e977]: + - heading "WikiCity" [level=4] [ref=e978] + - paragraph [ref=e979]: "2007" + - img [ref=e981] + - 'link "NYTE: New York Talk Exchange 2007" [ref=e982] [cursor=pointer]': + - /url: https://senseable.mit.edu/nyte/ + - generic [ref=e983]: + - 'heading "NYTE: New York Talk Exchange" [level=4] [ref=e984]' + - paragraph [ref=e985]: "2007" + - img [ref=e987] + - link "Venice Biennale 2006" [ref=e988] [cursor=pointer]: + - /url: https://senseable.mit.edu/biennale/ + - generic [ref=e989]: + - heading "Venice Biennale" [level=4] [ref=e990] + - paragraph [ref=e991]: "2006" + - img [ref=e993] + - link "Real Time Rome 2006" [ref=e994] [cursor=pointer]: + - /url: https://senseable.mit.edu/realtimerome/ + - generic [ref=e995]: + - heading "Real Time Rome" [level=4] [ref=e996] + - paragraph [ref=e997]: "2006" + - img [ref=e999] + - link "Zaragoza Bus Stop 2006" [ref=e1000] [cursor=pointer]: + - /url: https://senseable.mit.edu/bus_stop/ + - generic [ref=e1001]: + - heading "Zaragoza Bus Stop" [level=4] [ref=e1002] + - paragraph [ref=e1003]: "2006" + - img [ref=e1005] + - link "Inside the Sponge 2006" [ref=e1006] [cursor=pointer]: + - /url: https://senseable.mit.edu/sponge/ + - generic [ref=e1007]: + - heading "Inside the Sponge" [level=4] [ref=e1008] + - paragraph [ref=e1009]: "2006" + - img [ref=e1011] + - link "Tsunami-Safe(r) Houses 2005" [ref=e1012] [cursor=pointer]: + - /url: https://senseable.mit.edu/tsunami-prajnopaya/ + - generic [ref=e1013]: + - heading "Tsunami-Safe(r) Houses" [level=4] [ref=e1014] + - paragraph [ref=e1015]: "2005" + - img [ref=e1017] + - link "Mobile Landscape Graz 2005" [ref=e1018] [cursor=pointer]: + - /url: https://senseable.mit.edu/graz/ + - generic [ref=e1019]: + - heading "Mobile Landscape Graz" [level=4] [ref=e1020] + - paragraph [ref=e1021]: "2005" + - img [ref=e1023] + - link "iSPOTS 2005" [ref=e1024] [cursor=pointer]: + - /url: https://senseable.mit.edu/ispots/ + - generic [ref=e1025]: + - heading "iSPOTS" [level=4] [ref=e1026] + - paragraph [ref=e1027]: "2005" + - img [ref=e1029] + - link "Simmons Hall Competition 2005" [ref=e1030] [cursor=pointer]: + - /url: https://senseable.mit.edu/competition/ + - generic [ref=e1031]: + - heading "Simmons Hall Competition" [level=4] [ref=e1032] + - paragraph [ref=e1033]: "2005" + - img [ref=e1035] + - link "History Unwired 2005" [ref=e1036] [cursor=pointer]: + - /url: http://web.mit.edu/frontiers/ + - generic [ref=e1037]: + - heading "History Unwired" [level=4] [ref=e1038] + - paragraph [ref=e1039]: "2005" + - img [ref=e1041] + - link "A.C. Milan 2004" [ref=e1042] [cursor=pointer]: + - /url: https://senseable.mit.edu/milan/ + - generic [ref=e1043]: + - heading "A.C. Milan" [level=4] [ref=e1044] + - paragraph [ref=e1045]: "2004" + - img [ref=e1047] + - link "Sandscape 2004" [ref=e1048] [cursor=pointer]: + - /url: https://senseable.mit.edu/sandscape/ + - generic [ref=e1049]: + - heading "Sandscape" [level=4] [ref=e1050] + - paragraph [ref=e1051]: "2004" + - img [ref=e1053] + - link "Illuminating Clay 2004" [ref=e1054] [cursor=pointer]: + - /url: https://senseable.mit.edu/clay/ + - generic [ref=e1055]: + - heading "Illuminating Clay" [level=4] [ref=e1056] + - paragraph [ref=e1057]: "2004" + - img [ref=e1059] + - link "Phoxelspace 2004" [ref=e1060] [cursor=pointer]: + - /url: https://senseable.mit.edu/phoxel/ + - generic [ref=e1061]: + - heading "Phoxelspace" [level=4] [ref=e1062] + - paragraph [ref=e1063]: "2004" + - img [ref=e1065] + - link "Programable Window 2004" [ref=e1066] [cursor=pointer]: + - /url: https://senseable.mit.edu/window/ + - generic [ref=e1067]: + - heading "Programable Window" [level=4] [ref=e1068] + - paragraph [ref=e1069]: "2004" + - img [ref=e1071] + - link "Raster Cities 2004" [ref=e1072] [cursor=pointer]: + - /url: https://senseable.mit.edu/raster/ + - generic [ref=e1073]: + - heading "Raster Cities" [level=4] [ref=e1074] + - paragraph [ref=e1075]: "2004" + - img [ref=e1077] + - link "Cannes Reloaded 2004" [ref=e1078] [cursor=pointer]: + - /url: https://senseable.mit.edu/cannes/ + - generic [ref=e1079]: + - heading "Cannes Reloaded" [level=4] [ref=e1080] + - paragraph [ref=e1081]: "2004" + - img [ref=e1083] + - generic [ref=e1084]: + - generic [ref=e1085]: + - generic [ref=e1086]: + - heading "Consortium" [level=2] [ref=e1087] + - generic [ref=e1088]: + - paragraph [ref=e1089]: + - text: More information on joining our research efforts, through the Senseable City Lab Consortium can be found + - link "here" [ref=e1090] [cursor=pointer]: + - /url: mailto:senseable-consortium@mit.edu + - text: ". Current and past members of the Consortium include:" + - generic [ref=e1091]: + - generic [ref=e1092]:  + - heading "Current Members" [level=3] [ref=e1093]: + - link "Current Members" [ref=e1094] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1097]: + - generic [ref=e1098]: + - heading "Companies" [level=3] [ref=e1099] + - paragraph [ref=e1100]: + - generic [ref=e1101]: FAE Technology, + - generic [ref=e1102]: Dubai Future Foundation, + - generic [ref=e1103]: Sondotécnica, + - generic [ref=e1104]: Seoul AI Foundation, + - generic [ref=e1105]: Arnold Ventures, + - generic [ref=e1106]: Sidara, + - generic [ref=e1107]: Woven by Toyota, + - generic [ref=e1108]: Abu Dhabi’s Department of Municipalities and Transport, + - generic [ref=e1109]: Sidara, + - generic [ref=e1110]: A2A, + - generic [ref=e1111]: UnipolTech, + - generic [ref=e1112]: Hospital Israelita Albert Einstein + - generic [ref=e1113]: + - heading "Research Partners" [level=3] [ref=e1114] + - paragraph [ref=e1115]: + - generic [ref=e1116]: KACST - King Abdulaziz City for Science and Technology, + - generic [ref=e1117]: SMART - Singapore-MIT Alliance for Research and Technology, + - generic [ref=e1118]: KAIST Center for Advanced Urban Systems, + - generic [ref=e1119]: Imperial College London, + - generic [ref=e1120]: AMS Institute + - generic [ref=e1121]: + - heading "Cities and Regions" [level=3] [ref=e1122] + - paragraph [ref=e1123]: + - generic [ref=e1124]: Rio de Janeiro, + - generic [ref=e1125]: Laval, + - generic [ref=e1126]: Amsterdam + - generic [ref=e1127]: + - generic [ref=e1128]:  + - heading "Past Members" [level=3] [ref=e1129]: + - link "Past Members" [ref=e1130] [cursor=pointer]: + - /url: javascript:void(0); + - heading "Social Media" [level=2] [ref=e1132] + - generic [ref=e1133]: + - link [ref=e1134] [cursor=pointer]: + - /url: https://instagram.com/senseable_city_lab + - img [ref=e1135] + - link [ref=e1140] [cursor=pointer]: + - /url: https://www.youtube.com/user/senseablecitylab + - img [ref=e1141] + - link [ref=e1144] [cursor=pointer]: + - /url: https://www.linkedin.com/company/mit-senseable-city-lab + - img [ref=e1145] + - generic [ref=e1147]: + - link "Publications" [ref=e1149] [cursor=pointer]: + - /url: ./papers + - heading "Publications" [level=2] [ref=e1150] + - generic [ref=e1151]: + - generic [ref=e1152]: + - generic [ref=e1153]: + - generic [ref=e1154]:  + - 'heading "Octopus: A low-cost, modular environmental sensing platform for makers" [level=3] [ref=e1155]': + - 'link "Octopus: A low-cost, modular environmental sensing platform for makers" [ref=e1156] [cursor=pointer]': + - /url: https://senseable.mit.edu/papers/pdf/20260321_Oynlola-etal_Octopus_HardwareX.pdf + - paragraph [ref=e1157]: Oyinlola, O., Håtveit, Å., Elalami, C., Mora, S., Dubey, R., Duarte, F., Biagioli, J., Gregis, M., Ratti, C. + - paragraph [ref=e1158]: HardwareX + - generic [ref=e1159]: + - generic [ref=e1160]:  + - heading "Unsupervised mapping of urban tree diversity using spatially-aware visual clustering" [level=3] [ref=e1161]: + - link "Unsupervised mapping of urban tree diversity using spatially-aware visual clustering" [ref=e1162] [cursor=pointer]: + - /url: https://senseable.mit.edu/papers/pdf/20260228_Abuhani-etal_UnsupervisedMapping_ScientificReports.pdf + - paragraph [ref=e1163]: Abuhani, D., Seccaroni, M., Mazzarello, M., Zualkernan, I., Duarte, F., Ratti, C. + - paragraph [ref=e1164]: Scientific Reports + - generic [ref=e1165]: + - generic [ref=e1166]:  + - heading "Global patterns of inequality in pedestrian shade provision" [level=3] [ref=e1167]: + - link "Global patterns of inequality in pedestrian shade provision" [ref=e1168] [cursor=pointer]: + - /url: https://senseable.mit.edu/papers/pdf/20260115_Gu-etal_Shady_inequalities_NatureCommunications.pdf + - paragraph [ref=e1169]: Gu, X., Beuster, L., L, X., van Leeuwen, E., Venverloo, T., Duarte, F. + - paragraph [ref=e1170]: Nature Communications + - link "Browse all publications" [ref=e1172] [cursor=pointer]: + - /url: ./papers + - generic [ref=e1173]: + - generic [ref=e1174]: + - heading "News Letter" [level=2] [ref=e1176] + - generic [ref=e1178]: + - generic [ref=e1179]:  + - link "2026" [ref=e1180] [cursor=pointer]: + - /url: javascript:void(0); + - list [ref=e1185]: + - listitem [ref=e1186]: + - link "March" [ref=e1187] [cursor=pointer]: + - /url: https://mitsenseablecitylab.cmail20.com/t/t-e-wyuhtty-tycliuukk-y/ + - listitem [ref=e1188]: + - link "January" [ref=e1189] [cursor=pointer]: + - /url: https://mitsenseablecitylab.cmail19.com/t/t-e-wluely-tycliuukk-y/ + - generic [ref=e1190]: + - generic [ref=e1191]:  + - link "2025" [ref=e1192] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1193]: + - generic [ref=e1194]:  + - link "2024" [ref=e1195] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1196]: + - generic [ref=e1197]:  + - link "2023" [ref=e1198] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1199]: + - generic [ref=e1200]:  + - link "2022" [ref=e1201] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1202]: + - generic [ref=e1203]:  + - link "2021" [ref=e1204] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1205]: + - generic [ref=e1206]:  + - link "2020" [ref=e1207] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1208]: + - generic [ref=e1209]:  + - link "2019" [ref=e1210] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1211]: + - generic [ref=e1212]:  + - link "2018" [ref=e1213] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1214]: + - generic [ref=e1215]:  + - link "2017" [ref=e1216] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1217]: + - generic [ref=e1218]:  + - link "2016" [ref=e1219] [cursor=pointer]: + - /url: javascript:void(0); + - link "Subscribe to our newsletter" [ref=e1221] [cursor=pointer]: + - /url: https://senseable.mit.edu/signup.html + - generic [ref=e1223]: + - heading "Positions" [level=2] [ref=e1224] + - generic [ref=e1225]: + - list [ref=e1226]: + - listitem [ref=e1227]: + - link "Apply Here" [ref=e1228] [cursor=pointer]: + - /url: https://podio.com/webforms/20990155/1447915 + - paragraph [ref=e1229]: We always seek outstanding candidates from a variety of backgrounds besides our specific position openings. We encourage applications from minorities and other under-represented groups. Apply today and join us in our mission of making cities more diverse and inclusive. + - list [ref=e1230]: + - listitem [ref=e1231]: + - link "Postdoc, Research Fellow, Research Assistant (RA)" [ref=e1232] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/030/original/SCL_EnvironmentalSensing.pdf?1691083212 + - paragraph [ref=e1233]: Sensing Technologies (air quality, thermal imagery, sound AI) + - listitem [ref=e1234]: + - link "Senseable City Dubai" [ref=e1235] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/034/original/Dubai_Open_Positions_20251107.pdf?1762543616 + - paragraph [ref=e1236]: Postdoc, Research Fellow, Visiting Researcher / Student + - listitem [ref=e1237]: + - link "Senseable City Rio de Janeiro" [ref=e1238] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/035/original/Rio_Open_Positions_20251107.pdf?1762543557 + - paragraph [ref=e1239]: Postdoc, Research Fellow, Visiting Researcher / Student + - listitem [ref=e1240]: + - link "Senseable City Amsterdam" [ref=e1241] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/036/original/Amsterdam_Open_Positions_20251215.pdf?1765827730 + - paragraph [ref=e1242]: Postdoc, Research Fellow, Visiting Researcher / Student + - listitem [ref=e1243]: + - link "Senseable City Seoul" [ref=e1244] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/037/original/Seoul_Open_Positions_20251107.pdf?1762543654 + - paragraph [ref=e1245]: Postdoc, Research Fellow, Visiting Researcher / Student + - listitem [ref=e1246]: + - link "Postdoc Fellow" [ref=e1247] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/020/original/SCL_Complexity_UrbanScience.pdf?1691080310 + - paragraph [ref=e1248]: Complexity and Urban Science + - listitem [ref=e1249]: + - link "Postdoc, Research Fellow, Research Assistant (RA)" [ref=e1250] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/032/original/SCL_General_fellow-assistant.pdf?1691083598 + - paragraph [ref=e1251]: General (design, computer science, environmental science) + - listitem [ref=e1252]: + - link "Postdoc, Research Fellow" [ref=e1253] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/038/original/Postdoc_AI_20260504.pdf?1777916836 + - paragraph [ref=e1254]: Artificial Intelligence for Urban Science + - listitem [ref=e1255]: + - link "Data Visualization and/or UX/UI Specialist" [ref=e1256] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/system/positions/pdfs/000/000/004/original/SCL_DataVisualization.pdf?1691080196 + - generic [ref=e1257]: + - heading "Team" [level=2] [ref=e1258] + - generic [ref=e1259]: + - generic [ref=e1260]: + - paragraph [ref=e1261]: + - link "Carlo Ratti Director, Professor of the Practice" [ref=e1262] [cursor=pointer]: + - /url: http://www.carloratti.com + - paragraph [ref=e1263]: Assaf Biderman Co-Founder + - paragraph [ref=e1264]: + - link "Irina Franklin Operations Director" [ref=e1265] [cursor=pointer]: + - /url: https://www.linkedin.com/in/i-franklin/ + - paragraph [ref=e1266]: + - link "Fábio Duarte Associate Director, Research & Design" [ref=e1267] [cursor=pointer]: + - /url: https://dusp.mit.edu/people/fabio-duarte + - paragraph [ref=e1268]: Umberto Fugiglando Head of Research Strategy & Partnerships + - paragraph [ref=e1269]: Martina Mazzarello Research Scientist + - paragraph [ref=e1270]: + - link "Simone Mora Research Scientist" [ref=e1271] [cursor=pointer]: + - /url: http://simonemora.com + - paragraph [ref=e1272]: + - link "Paolo Santi Principal Research Scientist" [ref=e1273] [cursor=pointer]: + - /url: http://www.iit.cnr.it/staff/paolo.santi/ + - paragraph [ref=e1274]: Paulina Sterpe HR & Communications + - generic [ref=e1275]: + - generic [ref=e1276]: + - generic [ref=e1277]:  + - heading "Affiliate Scholars" [level=3] [ref=e1278]: + - link "Affiliate Scholars" [ref=e1279] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1280]: + - generic [ref=e1281]:  + - heading "Current Researchers" [level=3] [ref=e1282]: + - link "Current Researchers" [ref=e1283] [cursor=pointer]: + - /url: javascript:void(0); + - paragraph [ref=e1286]: + - link "Diaa Abuhani," [ref=e1287] [cursor=pointer]: + - /url: http://www.linkedin.com/in/diaa-abuhani + - link "Alaa AlRadwan," [ref=e1288] [cursor=pointer]: + - /url: https://www.linkedin.com/in/aalradwan/ + - link "Mayar Ariss," [ref=e1289] [cursor=pointer]: + - /url: http://mayarariss.com/ + - link "Suzan Ayas," [ref=e1290] [cursor=pointer]: + - /url: https://www.linkedin.com/in/suzan-ayas/ + - link "Deniz Aydemir," [ref=e1291] [cursor=pointer]: + - /url: https://denizaydemir.org/ + - link "Cassiano Bastos Moroz," [ref=e1292] [cursor=pointer]: + - /url: https://www.linkedin.com/in/cassianomoroz/ + - link "Lukas Beuster," [ref=e1293] [cursor=pointer]: + - /url: https://www.linkedin.com/in/lukas-beuster/ + - link "Maria Boxwala," [ref=e1294] [cursor=pointer]: + - /url: https://www.linkedin.com/in/maria-boxwala-69958b286/ + - link "Chiara Cadoni," [ref=e1295] [cursor=pointer]: + - /url: https://www.linkedin.com/in/chiara-cadoni-293441195/?originalSubdomain=ch + - link "Susana Callehas Sandoval," [ref=e1296] [cursor=pointer]: + - /url: https://www.linkedin.com/in/scallejas/ + - link "Mingze Chen," [ref=e1297] [cursor=pointer]: + - /url: https://mingzechen.com/ + - link "Kyujin Choi," [ref=e1298] [cursor=pointer]: + - /url: www.linkedin.com/in/kyujin-choi-0161102a9 + - link "Luiz Coelho," [ref=e1299] [cursor=pointer]: + - /url: https://teixeiracoelho.com + - link "Stefania Dimitrov," [ref=e1300] [cursor=pointer]: + - /url: https://www.linkedin.com/in/stefaniadimitrov + - link "Yinan Dong," [ref=e1301] [cursor=pointer]: + - /url: https://www.linkedin.com/in/yinan-dong/ + - link "Ravish Dubey," [ref=e1302] [cursor=pointer]: + - /url: https://www.linkedin.com/in/ravish-dubey-a31750122/ + - link "Marc Duran Sala," [ref=e1303] [cursor=pointer]: + - /url: www.linkedin.com/in/marc-duran-sala + - generic [ref=e1304]: Chada Elalami, + - link "Habiba Elkholy," [ref=e1305] [cursor=pointer]: + - /url: https://www.linkedin.com/in/habiba-elkholy-1bab6b279/ + - link "Simone Erba," [ref=e1306] [cursor=pointer]: + - /url: http://www.linkedin.com/in/simone-erba-989266292 + - link "Francois Gu," [ref=e1307] [cursor=pointer]: + - /url: www.linkedin.com/in/francois-gu + - link "Hanmin Gu," [ref=e1308] [cursor=pointer]: + - /url: https://www.hanmingu.com/ + - link "Song Guo," [ref=e1309] [cursor=pointer]: + - /url: https://songguoarchitect.github.io/ + - link "Åse Haatveit," [ref=e1310] [cursor=pointer]: + - /url: https://www.linkedin.com/in/asehatveit/ + - link "Fadi G. Haddad," [ref=e1311] [cursor=pointer]: + - /url: https://www.linkedin.com/in/fadighaddad/ + - generic [ref=e1312]: Thea Harmouche, + - link "Theo Hermann," [ref=e1313] [cursor=pointer]: + - /url: https://github.com/theoh-io + - link "Eunah Jung," [ref=e1314] [cursor=pointer]: + - /url: https://www.linkedin.com/in/eunah-jung-920412223/ + - link "Miho Koda," [ref=e1315] [cursor=pointer]: + - /url: https://www.linkedin.com/in/mihokoda/ + - link "Charles Li," [ref=e1316] [cursor=pointer]: + - /url: https://charlesqcl.github.io/ + - link "Seung Jae Lieu," [ref=e1317] [cursor=pointer]: + - /url: https://www.linkedin.com/in/lsj97/ + - generic [ref=e1318]: Yingjie Liu, + - link "Chang Liu," [ref=e1319] [cursor=pointer]: + - /url: https://www.linkedin.com/in/chang-liu-247416115/ + - link "Peng Luo," [ref=e1320] [cursor=pointer]: + - /url: https://sites.google.com/view/pengluo/about + - link "Elizabeth McCaffrey," [ref=e1321] [cursor=pointer]: + - /url: https://www.worksofelizabethmccaffrey.com + - link "Ching Yau Mok," [ref=e1322] [cursor=pointer]: + - /url: www.fergus.mk + - link "Diego Morra," [ref=e1323] [cursor=pointer]: + - /url: http://diegomorra.github.io/ + - link "Leslie Norford," [ref=e1324] [cursor=pointer]: + - /url: https://architecture.mit.edu/people/les-norford + - link "Muhammed Noshin," [ref=e1325] [cursor=pointer]: + - /url: www.linkedin.com/in/muhammed-noshin + - link "Oluwatobi Oyinlola," [ref=e1326] [cursor=pointer]: + - /url: https://www.internetoftobi.com/ + - link "Stefano Patiti," [ref=e1327] [cursor=pointer]: + - /url: https://stefanopatiti.framer.website/ + - link "Matteo Postinghel," [ref=e1328] [cursor=pointer]: + - /url: https://matteopostinghel.com + - link "Irati Rodriguez," [ref=e1329] [cursor=pointer]: + - /url: http://linkedin.com/in/irati-lur-zabalbeitia-rodríguez-898a6388 + - link "Esther Saller," [ref=e1330] [cursor=pointer]: + - /url: www.linkedin.com/in/esther-saller-06b7471b9 + - link "Qiwei Song," [ref=e1331] [cursor=pointer]: + - /url: https://www.linkedin.com/in/qiwei-song-207144127/ + - link "Onur Tumturk," [ref=e1332] [cursor=pointer]: + - /url: www.linkedin.com/in/onur-tumturk + - link "Maximilian van der Hart," [ref=e1333] [cursor=pointer]: + - /url: https://www.linkedin.com/in/max-van-der-hart-6959b720b/ + - link "Michiel van Selm," [ref=e1334] [cursor=pointer]: + - /url: https://www.linkedin.com/in/michiel-van-selm-a870841bb/ + - link "Dara Varam," [ref=e1335] [cursor=pointer]: + - /url: https://daravaram.github.io/ + - link "Titus Venverloo," [ref=e1336] [cursor=pointer]: + - /url: https://www.linkedin.com/in/titusvenverloo/ + - link "Ruoxi Wang," [ref=e1337] [cursor=pointer]: + - /url: https://www.linkedin.com/in/ruoxi-wang-4167522b7/ + - link "Qi Wang," [ref=e1338] [cursor=pointer]: + - /url: https://sites.google.com/view/uirlab + - link "Nils Wolff," [ref=e1339] [cursor=pointer]: + - /url: www.linkedin.com/in/nils-wolff-9192b92aa + - link "Wenhan Wu," [ref=e1340] [cursor=pointer]: + - /url: https://wenhanwu1998.github.io/ + - link "Menghao Yuan," [ref=e1341] [cursor=pointer]: + - /url: www.linkedin.com/in/lyle-yuan-80177391 + - link "Kaihan Zhang," [ref=e1342] [cursor=pointer]: + - /url: https://www.linkedin.com/in/kaihan-zhang-152676210/ + - link "Aurora Zhang," [ref=e1343] [cursor=pointer]: + - /url: https://www.linkedin.com/in/aurora-zhang-5399a3b7/ + - link "Jingrong Zhang," [ref=e1344] [cursor=pointer]: + - /url: https://zhangjingrong.com + - link "Mingming Zhao," [ref=e1345] [cursor=pointer]: + - /url: mingmingzhao.com + - link "Pei Zhao," [ref=e1346] [cursor=pointer]: + - /url: https://www.linkedin.com/in/pei-zhao-a17128224/ + - link "Yu Zheng," [ref=e1347] [cursor=pointer]: + - /url: https://davymorgan.github.io/ + - link "Hui Zhong" [ref=e1348] [cursor=pointer]: + - /url: https://www.linkedin.com/in/hui-zhong-1215702a9/ + - generic [ref=e1349]: + - generic [ref=e1350]:  + - heading "Past Researchers" [level=3] [ref=e1351]: + - link "Past Researchers" [ref=e1352] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1353]: + - generic [ref=e1354]:  + - heading "Faculty Advisory Board" [level=3] [ref=e1355]: + - link "Faculty Advisory Board" [ref=e1356] [cursor=pointer]: + - /url: javascript:void(0); + - generic [ref=e1357]: + - generic [ref=e1358]:  + - heading "Visiting Committee" [level=3] [ref=e1359]: + - link "Visiting Committee" [ref=e1360] [cursor=pointer]: + - /url: javascript:void(0); + - link "Ongoing Projects" [ref=e1362] [cursor=pointer]: + - /url: https://senseabledb.mit.edu/labmap + - heading "Ongoing Projects" [level=2] [ref=e1363] + - link "Org Chart" [ref=e1364] [cursor=pointer]: + - /url: http://senseable.mit.edu/org_chart + - heading "Org Chart" [level=2] [ref=e1365] + - contentinfo [ref=e1366]: + - separator [ref=e1367] + - generic [ref=e1369]: + - link "School of Architecture + Planning" [ref=e1370] [cursor=pointer]: + - /url: http://sap.mit.edu + - img "School of Architecture + Planning" [ref=e1371] + - link "Department of Urban Studies and Planning" [ref=e1372] [cursor=pointer]: + - /url: http://dusp.mit.edu + - img "Department of Urban Studies and Planning" [ref=e1373] + - paragraph [ref=e1377]: + - text: For more information of the Senseable City Lab, Please visit + - link "Senseable Database" [ref=e1378] [cursor=pointer]: + - /url: https://senseabledb.mit.edu + - text: . + - generic [ref=e1380]: + - heading "Senseable City Laboratory" [level=4] [ref=e1381] + - paragraph [ref=e1382]: + - text: MIT 9-216 + - text: 77 Massachusetts Avenue + - text: Cambridge, MA 02139 USA + - paragraph [ref=e1385]: + - generic [ref=e1386]:  + - text: 1-617-324-4474 + - generic [ref=e1387]:  + - text: 1-617-258-8081 + - generic [ref=e1388]:  + - link "senseable.mit.edu" [ref=e1389] [cursor=pointer]: + - /url: / + - generic [ref=e1390]:  + - link "senseable-contacts@mit.edu" [ref=e1391] [cursor=pointer]: + - /url: mailto:senseable-contacts@mit.edu + - paragraph [ref=e1396]: + - link "Accessibility" [ref=e1397] [cursor=pointer]: + - /url: https://accessibility.mit.edu/ \ No newline at end of file diff --git a/web/next-env.d.ts b/web/next-env.d.ts new file mode 100644 index 0000000..830fb59 --- /dev/null +++ b/web/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/web/next.config.js b/web/next.config.js new file mode 100644 index 0000000..10c0e8d --- /dev/null +++ b/web/next.config.js @@ -0,0 +1,43 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + // 启用 standalone 输出模式(用于 Docker) + output: 'standalone', + experimental: { + turbo: { + rules: { + '*.svg': { + loaders: ['@svgr/webpack'], + as: '*.js', + }, + }, + }, + }, + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: '**', + }, + ], + }, + async rewrites() { + // 在容器环境中,前端和后端在同一容器内,可以直接访问 + const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; + return [ + { + source: '/api/:path*', + destination: `${backendUrl}/:path*`, + }, + { + source: '/generated_images/:path*', + destination: `${backendUrl}/generated_images/:path*`, + }, + ]; + }, + // 禁用静态生成,避免 SSR 时使用浏览器 API 的错误 + generateBuildId: async () => { + return 'build-' + Date.now(); + }, +}; + +export default nextConfig; diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..49e91a5 --- /dev/null +++ b/web/package.json @@ -0,0 +1,87 @@ +{ + "name": "course-agent-web", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "build": "next build", + "check": "next lint && tsc --noEmit", + "dev": "next dev --turbo --port 8001", + "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,mdx}\" --cache", + "format:write": "prettier --write \"**/*.{ts,tsx,js,jsx,mdx}\" --cache", + "lint": "next lint", + "lint:fix": "next lint --fix", + "preview": "next build && next start --port 8001", + "start": "next start --port 8001", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@hookform/resolvers": "^5.0.1", + "@radix-ui/react-accordion": "^1.2.8", + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.2.3", + "@radix-ui/react-collapsible": "^1.1.8", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-popover": "^1.1.11", + "@radix-ui/react-radio-group": "^1.3.8", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slider": "^1.3.6", + "@radix-ui/react-slot": "^1.2.0", + "@radix-ui/react-switch": "^1.2.2", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-tooltip": "^1.2.0", + "@t3-oss/env-nextjs": "^0.11.0", + "@tailwindcss/typography": "^0.5.16", + "autoprefixer": "^10.4.21", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "framer-motion": "^12.23.24", + "highlight.js": "^11.11.1", + "js-cookie": "^3.0.5", + "katex": "^0.16.21", + "lucide-react": "^0.487.0", + "next": "^15.4.7", + "next-auth": "^4.24.11", + "next-themes": "^0.4.6", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-force-graph-2d": "^1.29.0", + "react-hook-form": "^7.56.1", + "react-markdown": "^10.1.0", + "react-syntax-highlighter": "^15.6.1", + "rehype-katex": "^7.0.1", + "remark-gfm": "^4.0.1", + "remark-math": "^6.0.0", + "sonner": "^2.0.3", + "tailwind-merge": "^3.2.0", + "tw-animate-css": "^1.4.0", + "typescript": "^5.8.2", + "zod": "^3.24.3", + "zustand": "^5.0.3" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@tailwindcss/postcss": "^4.1.14", + "@types/hast": "^3.0.4", + "@types/js-cookie": "^3.0.6", + "@types/node": "^20.14.10", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@types/react-syntax-highlighter": "^15.5.13", + "eslint": "^9.23.0", + "eslint-config-next": "^15.2.3", + "postcss": "^8.5.3", + "prettier": "^3.5.3", + "prettier-plugin-tailwindcss": "^0.6.11", + "tailwindcss": "^4.0.15", + "typescript-eslint": "^8.27.0" + }, + "packageManager": "pnpm@10.6.5" +} diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml new file mode 100644 index 0000000..19d207f --- /dev/null +++ b/web/pnpm-lock.yaml @@ -0,0 +1,7110 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@hookform/resolvers': + specifier: ^5.0.1 + version: 5.2.2(react-hook-form@7.65.0(react@19.2.0)) + '@radix-ui/react-accordion': + specifier: ^1.2.8 + version: 1.2.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-avatar': + specifier: ^1.1.10 + version: 1.1.10(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-checkbox': + specifier: ^1.2.3 + version: 1.3.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-collapsible': + specifier: ^1.1.8 + version: 1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.16 + version: 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-icons': + specifier: ^1.3.2 + version: 1.3.2(react@19.2.0) + '@radix-ui/react-label': + specifier: ^2.1.7 + version: 2.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-popover': + specifier: ^1.1.11 + version: 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-radio-group': + specifier: ^1.3.8 + version: 1.3.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-scroll-area': + specifier: ^1.2.10 + version: 1.2.10(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-select': + specifier: ^2.2.6 + version: 2.2.6(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-separator': + specifier: ^1.1.7 + version: 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slider': + specifier: ^1.3.6 + version: 1.3.6(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': + specifier: ^1.2.0 + version: 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-switch': + specifier: ^1.2.2 + version: 1.2.6(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-tabs': + specifier: ^1.1.13 + version: 1.1.13(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-tooltip': + specifier: ^1.2.0 + version: 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@t3-oss/env-nextjs': + specifier: ^0.11.0 + version: 0.11.1(typescript@5.9.3)(zod@3.25.76) + '@tailwindcss/typography': + specifier: ^0.5.16 + version: 0.5.19(tailwindcss@4.1.14) + autoprefixer: + specifier: ^10.4.21 + version: 10.4.21(postcss@8.5.6) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + cmdk: + specifier: ^1.1.1 + version: 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + framer-motion: + specifier: ^12.23.24 + version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + highlight.js: + specifier: ^11.11.1 + version: 11.11.1 + js-cookie: + specifier: ^3.0.5 + version: 3.0.5 + katex: + specifier: ^0.16.21 + version: 0.16.25 + lucide-react: + specifier: ^0.487.0 + version: 0.487.0(react@19.2.0) + next: + specifier: ^15.4.7 + version: 15.5.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next-auth: + specifier: ^4.24.11 + version: 4.24.11(next@15.5.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: + specifier: ^19.0.0 + version: 19.2.0 + react-dom: + specifier: ^19.0.0 + version: 19.2.0(react@19.2.0) + react-force-graph-2d: + specifier: ^1.29.0 + version: 1.29.0(react@19.2.0) + react-hook-form: + specifier: ^7.56.1 + version: 7.65.0(react@19.2.0) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.2.2)(react@19.2.0) + react-syntax-highlighter: + specifier: ^15.6.1 + version: 15.6.6(react@19.2.0) + rehype-katex: + specifier: ^7.0.1 + version: 7.0.1 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + remark-math: + specifier: ^6.0.0 + version: 6.0.0 + sonner: + specifier: ^2.0.3 + version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + tailwind-merge: + specifier: ^3.2.0 + version: 3.3.1 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + typescript: + specifier: ^5.8.2 + version: 5.9.3 + zod: + specifier: ^3.24.3 + version: 3.25.76 + zustand: + specifier: ^5.0.3 + version: 5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) + devDependencies: + '@eslint/eslintrc': + specifier: ^3.3.1 + version: 3.3.1 + '@tailwindcss/postcss': + specifier: ^4.1.14 + version: 4.1.14 + '@types/hast': + specifier: ^3.0.4 + version: 3.0.4 + '@types/js-cookie': + specifier: ^3.0.6 + version: 3.0.6 + '@types/node': + specifier: ^20.14.10 + version: 20.19.21 + '@types/react': + specifier: ^19.0.0 + version: 19.2.2 + '@types/react-dom': + specifier: ^19.0.0 + version: 19.2.1(@types/react@19.2.2) + '@types/react-syntax-highlighter': + specifier: ^15.5.13 + version: 15.5.13 + eslint: + specifier: ^9.23.0 + version: 9.37.0(jiti@2.6.1) + eslint-config-next: + specifier: ^15.2.3 + version: 15.5.4(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + postcss: + specifier: ^8.5.3 + version: 8.5.6 + prettier: + specifier: ^3.5.3 + version: 3.6.2 + prettier-plugin-tailwindcss: + specifier: ^0.6.11 + version: 0.6.14(prettier@3.6.2) + tailwindcss: + specifier: ^4.0.15 + version: 4.1.14 + typescript-eslint: + specifier: ^8.27.0 + version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@emnapi/core@1.5.0': + resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} + + '@emnapi/runtime@1.5.0': + resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.0': + resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.16.0': + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.37.0': + resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.0': + resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@hookform/resolvers@5.2.2': + resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} + peerDependencies: + react-hook-form: ^7.55.0 + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.4': + resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.4': + resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.3': + resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.3': + resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.3': + resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.3': + resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.3': + resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.3': + resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.3': + resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': + resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.3': + resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.4': + resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.4': + resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.4': + resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.4': + resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.4': + resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.4': + resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.4': + resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.4': + resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.4': + resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.4': + resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.4': + resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@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==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@next/env@15.5.4': + resolution: {integrity: sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==} + + '@next/eslint-plugin-next@15.5.4': + resolution: {integrity: sha512-SR1vhXNNg16T4zffhJ4TS7Xn7eq4NfKfcOsRwea7RIAHrjRpI9ALYbamqIJqkAhowLlERffiwk0FMvTLNdnVtw==} + + '@next/swc-darwin-arm64@15.5.4': + resolution: {integrity: sha512-nopqz+Ov6uvorej8ndRX6HlxCYWCO3AHLfKK2TYvxoSB2scETOcfm/HSS3piPqc3A+MUgyHoqE6je4wnkjfrOA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.5.4': + resolution: {integrity: sha512-QOTCFq8b09ghfjRJKfb68kU9k2K+2wsC4A67psOiMn849K9ZXgCSRQr0oVHfmKnoqCbEmQWG1f2h1T2vtJJ9mA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.5.4': + resolution: {integrity: sha512-eRD5zkts6jS3VfE/J0Kt1VxdFqTnMc3QgO5lFE5GKN3KDI/uUpSyK3CjQHmfEkYR4wCOl0R0XrsjpxfWEA++XA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.5.4': + resolution: {integrity: sha512-TOK7iTxmXFc45UrtKqWdZ1shfxuL4tnVAOuuJK4S88rX3oyVV4ZkLjtMT85wQkfBrOOvU55aLty+MV8xmcJR8A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.5.4': + resolution: {integrity: sha512-7HKolaj+481FSW/5lL0BcTkA4Ueam9SPYWyN/ib/WGAFZf0DGAN8frNpNZYFHtM4ZstrHZS3LY3vrwlIQfsiMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.5.4': + resolution: {integrity: sha512-nlQQ6nfgN0nCO/KuyEUwwOdwQIGjOs4WNMjEUtpIQJPR2NUfmGpW2wkJln1d4nJ7oUzd1g4GivH5GoEPBgfsdw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.5.4': + resolution: {integrity: sha512-PcR2bN7FlM32XM6eumklmyWLLbu2vs+D7nJX8OAIoWy69Kef8mfiN4e8TUv2KohprwifdpFKPzIP1njuCjD0YA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.5.4': + resolution: {integrity: sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@panva/hkdf@1.2.1': + resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} + + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-accordion@1.2.12': + resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.10': + resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.3.3': + resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collapsible@1.1.12': + resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.16': + resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-icons@1.3.2': + resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} + peerDependencies: + react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.7': + resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popover@1.1.15': + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-radio-group@1.3.8': + resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.10': + resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.6': + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.7': + resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slider@1.3.6': + resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.2.6': + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.8': + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.0': + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@rushstack/eslint-patch@1.13.0': + resolution: {integrity: sha512-2ih5qGw5SZJ+2fLZxP6Lr6Na2NTIgPRL/7Kmyuw0uIyBQnuhQ8fi8fzUTd38eIQmqp+GYLC00cI6WgtqHxBwmw==} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@t3-oss/env-core@0.11.1': + resolution: {integrity: sha512-MaxOwEoG1ntCFoKJsS7nqwgcxLW1SJw238AJwfJeaz3P/8GtkxXZsPPolsz1AdYvUTbe3XvqZ/VCdfjt+3zmKw==} + peerDependencies: + typescript: '>=5.0.0' + zod: ^3.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@t3-oss/env-nextjs@0.11.1': + resolution: {integrity: sha512-rx2XL9+v6wtOqLNJbD5eD8OezKlQD1BtC0WvvtHwBgK66jnF5+wGqtgkKK4Ygie1LVmoDClths2T4tdFmRvGrQ==} + peerDependencies: + typescript: '>=5.0.0' + zod: ^3.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@tailwindcss/node@4.1.14': + resolution: {integrity: sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==} + + '@tailwindcss/oxide-android-arm64@4.1.14': + resolution: {integrity: sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.14': + resolution: {integrity: sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.14': + resolution: {integrity: sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.14': + resolution: {integrity: sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14': + resolution: {integrity: sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.14': + resolution: {integrity: sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.14': + resolution: {integrity: sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.14': + resolution: {integrity: sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.14': + resolution: {integrity: sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.14': + resolution: {integrity: sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==} + 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.14': + resolution: {integrity: sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.14': + resolution: {integrity: sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.14': + resolution: {integrity: sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.14': + resolution: {integrity: sha512-BdMjIxy7HUNThK87C7BC8I1rE8BVUsfNQSI5siQ4JK3iIa3w0XyVvVL9SXLWO//CtYTcp1v7zci0fYwJOjB+Zg==} + + '@tailwindcss/typography@0.5.19': + resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + + '@tweenjs/tween.js@25.0.0': + resolution: {integrity: sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@2.3.10': + resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/js-cookie@3.0.6': + resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/katex@0.16.7': + resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@20.19.21': + resolution: {integrity: sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==} + + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react-syntax-highlighter@15.5.13': + resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==} + + '@types/react@19.2.2': + resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@typescript-eslint/eslint-plugin@8.46.0': + resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.46.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.46.0': + resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.46.0': + resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.46.0': + resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.46.0': + resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.46.0': + resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.46.0': + resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.46.0': + resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.46.0': + resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.46.0': + resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + accessor-fn@1.5.3: + resolution: {integrity: sha512-rkAofCwe/FvYFUlMB0v0gWmhqtfAtV1IUkdPbfhTUyYniu5LrC0A0UJkTH0Jv3S8SvwkmfuAlY+mQIJATdocMA==} + engines: {node: '>=12'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + autoprefixer@10.4.21: + resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + baseline-browser-mapping@2.8.16: + resolution: {integrity: sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==} + hasBin: true + + bezier-js@6.1.4: + resolution: {integrity: sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.26.3: + resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001750: + resolution: {integrity: sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==} + + canvas-color-tracker@1.3.2: + resolution: {integrity: sha512-ryQkDX26yJ3CXzb3hxUVNlg1NKE4REc5crLBq661Nxzr8TNd236SaEf2ffYLXyI5tSABSeguHLqcVq4vf9L3Zg==} + engines: {node: '>=12'} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@1.1.4: + resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + cmdk@1.1.1: + resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + comma-separated-tokens@1.0.8: + resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-binarytree@1.0.2: + resolution: {integrity: sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-force-3d@3.0.6: + resolution: {integrity: sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-octree@1.1.0: + resolution: {integrity: sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.234: + resolution: {integrity: sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + eslint-config-next@15.5.4: + resolution: {integrity: sha512-BzgVVuT3kfJes8i2GHenC1SRJ+W3BTML11lAOYFOOPzrk2xp66jBOAGEFRw+3LkYCln5UzvFsLhojrshb5Zfaw==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.37.0: + resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fault@1.0.4: + resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + float-tooltip@1.7.5: + resolution: {integrity: sha512-/kXzuDnnBqyyWyhDMH7+PfP8J/oXiAavGzcRxASOMRHFuReDtofizLLJsf7nnDLAfEaMW4pVWaXrAjtnglpEkg==} + engines: {node: '>=12'} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + force-graph@1.51.0: + resolution: {integrity: sha512-aTnihCmiMA0ItLJLCbrQYS9mzriopW24goFPgUnKAAmAlPogTSmFWqoBPMXzIfPb7bs04Hur5zEI4WYgLW3Sig==} + engines: {node: '>=12'} + + format@0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} + engines: {node: '>=0.4.x'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + framer-motion@12.23.24: + resolution: {integrity: sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.12.0: + resolution: {integrity: sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-from-html-isomorphic@2.0.0: + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@2.2.5: + resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@6.0.0: + resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + + highlight.js@11.11.1: + resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} + engines: {node: '>=12.0.0'} + + highlightjs-vue@1.0.0: + resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==} + + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + index-array-by@1.4.2: + resolution: {integrity: sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw==} + engines: {node: '>=12'} + + inline-style-parser@0.2.4: + resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + is-alphabetical@1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-decimal@1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jerrypick@1.1.2: + resolution: {integrity: sha512-YKnxXEekXKzhpf7CLYA0A+oDP8V0OhICNCr5lv96FvSsDEmrb0GKM776JgQvHTMjr7DTTPEVv/1Ciaw0uEWzBA==} + engines: {node: '>=12'} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + jose@4.15.9: + resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + kapsule@1.16.3: + resolution: {integrity: sha512-4+5mNNf4vZDSwPhKprKwz3330iisPrb08JyMgbsdFrimBCKNHecua/WBwvVg3n7vwx0C1ARjfhwIpbrbd9n5wg==} + engines: {node: '>=12'} + + katex@0.16.25: + resolution: {integrity: sha512-woHRUZ/iF23GBP1dkDQMh1QBad9dmr8/PAwNA54VrSOVYgI12MAcE14TqnDdQOdzyEonGzMepYnqBMYdsoAr8Q==} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lowlight@1.20.0: + resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lucide-react@0.487.0: + resolution: {integrity: sha512-aKqhOQ+YmFnwq8dWgGjOuLc8V1R9/c/yOd+zDY4+ohsR2Jo05lSGc3WsstYPIzcTpeosN7LoCkLReUUITvaIvw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string@0.30.19: + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-math@3.0.0: + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + motion-dom@12.23.23: + resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==} + + motion-utils@12.23.6: + resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next-auth@4.24.11: + resolution: {integrity: sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==} + peerDependencies: + '@auth/core': 0.34.2 + next: ^12.2.5 || ^13 || ^14 || ^15 + nodemailer: ^6.6.5 + react: ^17.0.2 || ^18 || ^19 + react-dom: ^17.0.2 || ^18 || ^19 + peerDependenciesMeta: + '@auth/core': + optional: true + nodemailer: + optional: true + + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + next@15.5.4: + resolution: {integrity: sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-releases@2.0.23: + resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + oauth@0.9.15: + resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@2.2.0: + resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} + engines: {node: '>= 6'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + oidc-token-hash@5.1.1: + resolution: {integrity: sha512-D7EmwxJV6DsEB6vOFLrBM2OzsVgQzgPWyHlV2OOAVj772n+WTXpudC9e9u5BVKQnYwaD30Ivhi9b+4UeBcGu9g==} + engines: {node: ^10.13.0 || >=12.0.0} + + openid-client@5.7.1: + resolution: {integrity: sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + preact-render-to-string@5.2.6: + resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==} + peerDependencies: + preact: '>=10' + + preact@10.27.2: + resolution: {integrity: sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-plugin-tailwindcss@0.6.14: + resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==} + engines: {node: '>=14.21.3'} + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-hermes': '*' + '@prettier/plugin-oxc': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-import-sort: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-style-order: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-hermes': + optional: true + '@prettier/plugin-oxc': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-import-sort: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-style-order: + optional: true + prettier-plugin-svelte: + optional: true + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@3.8.0: + resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} + + prismjs@1.27.0: + resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} + engines: {node: '>=6'} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + property-information@5.6.0: + resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + peerDependencies: + react: ^19.2.0 + + react-force-graph-2d@1.29.0: + resolution: {integrity: sha512-Xv5IIk+hsZmB3F2ibja/t6j/b0/1T9dtFOQacTUoLpgzRHrO6wPu1GtQ2LfRqI/imgtaapnXUgQaE8g8enPo5w==} + engines: {node: '>=12'} + peerDependencies: + react: '*' + + react-hook-form@7.65.0: + resolution: {integrity: sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-kapsule@2.5.7: + resolution: {integrity: sha512-kifAF4ZPD77qZKc4CKLmozq6GY1sBzPEJTIJb0wWFK6HsePJatK3jXplZn2eeAt3x67CDozgi7/rO8fNQ/AL7A==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16.13.1' + + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-syntax-highlighter@15.6.6: + resolution: {integrity: sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw==} + peerDependencies: + react: '>= 0.14.0' + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + refractor@3.6.0: + resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + rehype-katex@7.0.1: + resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-math@6.0.0: + resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.34.4: + resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@1.1.5: + resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + style-to-js@1.1.18: + resolution: {integrity: sha512-JFPn62D4kJaPTnhFUI244MThx+FEGbi+9dw1b9yBBQ+1CZpV7QAT8kUtJ7b7EUNdHajjF/0x8fT+16oLJoojLg==} + + style-to-object@1.0.11: + resolution: {integrity: sha512-5A560JmXr7wDyGLK12Nq/EYS38VkGlglVzkis1JEdbGWSnbQIEhZzTJhzURXN5/8WwwFCs/f/VVcmkTppbXLow==} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwind-merge@3.3.1: + resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} + + tailwindcss@4.1.14: + resolution: {integrity: sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tar@7.5.1: + resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} + engines: {node: '>=18'} + + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.46.0: + resolution: {integrity: sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zustand@5.0.8: + resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/runtime@7.28.4': {} + + '@emnapi/core@1.5.0': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.5.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.37.0(jiti@2.6.1))': + dependencies: + eslint: 9.37.0(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.0': + dependencies: + '@eslint/core': 0.16.0 + + '@eslint/core@0.16.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.37.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.4.0': + dependencies: + '@eslint/core': 0.16.0 + levn: 0.4.1 + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@floating-ui/utils@0.2.10': {} + + '@hookform/resolvers@5.2.2(react-hook-form@7.65.0(react@19.2.0))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.65.0(react@19.2.0) + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.3 + optional: true + + '@img/sharp-darwin-x64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.3 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.3': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.3': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.3': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.3': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.3': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.3': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.3': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.3': + optional: true + + '@img/sharp-linux-arm64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.3 + optional: true + + '@img/sharp-linux-arm@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.3 + optional: true + + '@img/sharp-linux-ppc64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.3 + optional: true + + '@img/sharp-linux-s390x@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.3 + optional: true + + '@img/sharp-linux-x64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.3 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + optional: true + + '@img/sharp-wasm32@0.34.4': + dependencies: + '@emnapi/runtime': 1.5.0 + optional: true + + '@img/sharp-win32-arm64@0.34.4': + optional: true + + '@img/sharp-win32-ia32@0.34.4': + optional: true + + '@img/sharp-win32-x64@0.34.4': + optional: true + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@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 + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.5.0 + '@emnapi/runtime': 1.5.0 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@next/env@15.5.4': {} + + '@next/eslint-plugin-next@15.5.4': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@15.5.4': + optional: true + + '@next/swc-darwin-x64@15.5.4': + optional: true + + '@next/swc-linux-arm64-gnu@15.5.4': + optional: true + + '@next/swc-linux-arm64-musl@15.5.4': + optional: true + + '@next/swc-linux-x64-gnu@15.5.4': + optional: true + + '@next/swc-linux-x64-musl@15.5.4': + optional: true + + '@next/swc-win32-arm64-msvc@15.5.4': + optional: true + + '@next/swc-win32-x64-msvc@15.5.4': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@panva/hkdf@1.2.1': {} + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-context@1.1.2(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-direction@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-icons@1.3.2(react@19.2.0)': + dependencies: + react: 19.2.0 + + '@radix-ui/react-id@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.1(@types/react@19.2.2) + + '@radix-ui/rect@1.1.1': {} + + '@rtsao/scc@1.1.0': {} + + '@rushstack/eslint-patch@1.13.0': {} + + '@standard-schema/utils@0.3.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@t3-oss/env-core@0.11.1(typescript@5.9.3)(zod@3.25.76)': + dependencies: + zod: 3.25.76 + optionalDependencies: + typescript: 5.9.3 + + '@t3-oss/env-nextjs@0.11.1(typescript@5.9.3)(zod@3.25.76)': + dependencies: + '@t3-oss/env-core': 0.11.1(typescript@5.9.3)(zod@3.25.76) + zod: 3.25.76 + optionalDependencies: + typescript: 5.9.3 + + '@tailwindcss/node@4.1.14': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.1 + magic-string: 0.30.19 + source-map-js: 1.2.1 + tailwindcss: 4.1.14 + + '@tailwindcss/oxide-android-arm64@4.1.14': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.14': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.14': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.14': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.14': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.14': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.14': + optional: true + + '@tailwindcss/oxide@4.1.14': + dependencies: + detect-libc: 2.1.2 + tar: 7.5.1 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.14 + '@tailwindcss/oxide-darwin-arm64': 4.1.14 + '@tailwindcss/oxide-darwin-x64': 4.1.14 + '@tailwindcss/oxide-freebsd-x64': 4.1.14 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.14 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.14 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.14 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.14 + '@tailwindcss/oxide-linux-x64-musl': 4.1.14 + '@tailwindcss/oxide-wasm32-wasi': 4.1.14 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.14 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.14 + + '@tailwindcss/postcss@4.1.14': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.14 + '@tailwindcss/oxide': 4.1.14 + postcss: 8.5.6 + tailwindcss: 4.1.14 + + '@tailwindcss/typography@0.5.19(tailwindcss@4.1.14)': + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 4.1.14 + + '@tweenjs/tween.js@25.0.0': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/hast@2.3.10': + dependencies: + '@types/unist': 2.0.11 + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/js-cookie@3.0.6': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/katex@0.16.7': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@20.19.21': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.1(@types/react@19.2.2)': + dependencies: + '@types/react': 19.2.2 + + '@types/react-syntax-highlighter@15.5.13': + dependencies: + '@types/react': 19.2.2 + + '@types/react@19.2.2': + dependencies: + csstype: 3.1.3 + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.0 + eslint: 9.37.0(jiti@2.6.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.0 + debug: 4.4.3 + eslint: 9.37.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.46.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.46.0': + dependencies: + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 + + '@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.37.0(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.46.0': {} + + '@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + eslint: 9.37.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.46.0': + dependencies: + '@typescript-eslint/types': 8.46.0 + eslint-visitor-keys: 4.2.1 + + '@ungap/structured-clone@1.3.0': {} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + accessor-fn@1.5.3: {} + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + autoprefixer@10.4.21(postcss@8.5.6): + dependencies: + browserslist: 4.26.3 + caniuse-lite: 1.0.30001750 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.11.0: {} + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + baseline-browser-mapping@2.8.16: {} + + bezier-js@6.1.4: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.26.3: + dependencies: + baseline-browser-mapping: 2.8.16 + caniuse-lite: 1.0.30001750 + electron-to-chromium: 1.5.234 + node-releases: 2.0.23 + update-browserslist-db: 1.1.3(browserslist@4.26.3) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001750: {} + + canvas-color-tracker@1.3.2: + dependencies: + tinycolor2: 1.6.0 + + ccount@2.0.1: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + character-entities-html4@2.1.0: {} + + character-entities-legacy@1.1.4: {} + + character-entities-legacy@3.0.0: {} + + character-entities@1.2.4: {} + + character-entities@2.0.2: {} + + character-reference-invalid@1.1.4: {} + + character-reference-invalid@2.0.1: {} + + chownr@3.0.0: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + cmdk@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + comma-separated-tokens@1.0.8: {} + + comma-separated-tokens@2.0.3: {} + + commander@8.3.0: {} + + concat-map@0.0.1: {} + + cookie@0.7.2: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + csstype@3.1.3: {} + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-binarytree@1.0.2: {} + + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-ease@3.0.1: {} + + d3-force-3d@3.0.6: + dependencies: + d3-binarytree: 1.0.2 + d3-dispatch: 3.0.1 + d3-octree: 1.1.0 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-octree@1.1.0: {} + + d3-quadtree@3.0.1: {} + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + date-fns@4.1.0: {} + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + detect-node-es@1.1.0: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.234: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@6.0.1: {} + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-config-next@15.5.4(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@next/eslint-plugin-next': 15.5.4 + '@rushstack/eslint-patch': 1.13.0 + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.37.0(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.37.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.37.0(jiti@2.6.1)) + eslint-plugin-react: 7.37.5(eslint@9.37.0(jiti@2.6.1)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.37.0(jiti@2.6.1)) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.37.0(jiti@2.6.1)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.37.0(jiti@2.6.1) + get-tsconfig: 4.12.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.15 + unrs-resolver: 1.11.1 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.37.0(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.37.0(jiti@2.6.1)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.37.0(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.37.0(jiti@2.6.1)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.11.0 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.37.0(jiti@2.6.1) + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@5.2.0(eslint@9.37.0(jiti@2.6.1)): + dependencies: + eslint: 9.37.0(jiti@2.6.1) + + eslint-plugin-react@7.37.5(eslint@9.37.0(jiti@2.6.1)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.37.0(jiti@2.6.1) + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.37.0(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.4.0 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.0 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + esutils@2.0.3: {} + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fault@1.0.4: + dependencies: + format: 0.2.2 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + float-tooltip@1.7.5: + dependencies: + d3-selection: 3.0.0 + kapsule: 1.16.3 + preact: 10.27.2 + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + force-graph@1.51.0: + dependencies: + '@tweenjs/tween.js': 25.0.0 + accessor-fn: 1.5.3 + bezier-js: 6.1.4 + canvas-color-tracker: 1.3.2 + d3-array: 3.2.4 + d3-drag: 3.0.0 + d3-force-3d: 3.0.6 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + float-tooltip: 1.7.5 + index-array-by: 1.4.2 + kapsule: 1.16.3 + lodash-es: 4.17.21 + + format@0.2.2: {} + + fraction.js@4.3.7: {} + + framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + motion-dom: 12.23.23 + motion-utils: 12.23.6 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.12.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-from-html-isomorphic@2.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-dom: 5.0.1 + hast-util-from-html: 2.0.3 + unist-util-remove-position: 5.0.0 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@2.2.5: {} + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.18 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@6.0.0: + dependencies: + '@types/hast': 2.3.10 + comma-separated-tokens: 1.0.8 + hast-util-parse-selector: 2.2.5 + property-information: 5.6.0 + space-separated-tokens: 1.1.5 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + highlight.js@10.7.3: {} + + highlight.js@11.11.1: {} + + highlightjs-vue@1.0.0: {} + + html-url-attributes@3.0.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + index-array-by@1.4.2: {} + + inline-style-parser@0.2.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + internmap@2.0.3: {} + + is-alphabetical@1.0.4: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@1.0.4: + dependencies: + is-alphabetical: 1.0.4 + is-decimal: 1.0.4 + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.7.3 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-decimal@1.0.4: {} + + is-decimal@2.0.1: {} + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@1.0.4: {} + + is-hexadecimal@2.0.1: {} + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-plain-obj@4.1.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jerrypick@1.1.2: {} + + jiti@2.6.1: {} + + jose@4.15.9: {} + + js-cookie@3.0.5: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + kapsule@1.16.3: + dependencies: + lodash-es: 4.17.21 + + katex@0.16.25: + dependencies: + commander: 8.3.0 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash-es@4.17.21: {} + + lodash.merge@4.6.2: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lowlight@1.20.0: + dependencies: + fault: 1.0.4 + highlight.js: 10.7.3 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + lucide-react@0.487.0(react@19.2.0): + dependencies: + react: 19.2.0 + + magic-string@0.30.19: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + markdown-table@3.0.4: {} + + math-intrinsics@1.1.0: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-math@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + longest-streak: 3.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + unist-util-remove-position: 5.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.0 + + mdast-util-to-hast@13.2.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.7 + devlop: 1.1.0 + katex: 0.16.25 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.2 + + motion-dom@12.23.23: + dependencies: + motion-utils: 12.23.6 + + motion-utils@12.23.6: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + next-auth@4.24.11(next@15.5.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@babel/runtime': 7.28.4 + '@panva/hkdf': 1.2.1 + cookie: 0.7.2 + jose: 4.15.9 + next: 15.5.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + oauth: 0.9.15 + openid-client: 5.7.1 + preact: 10.27.2 + preact-render-to-string: 5.2.6(preact@10.27.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + uuid: 8.3.2 + + next-themes@0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + next@15.5.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@next/env': 15.5.4 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001750 + postcss: 8.4.31 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + styled-jsx: 5.1.6(react@19.2.0) + optionalDependencies: + '@next/swc-darwin-arm64': 15.5.4 + '@next/swc-darwin-x64': 15.5.4 + '@next/swc-linux-arm64-gnu': 15.5.4 + '@next/swc-linux-arm64-musl': 15.5.4 + '@next/swc-linux-x64-gnu': 15.5.4 + '@next/swc-linux-x64-musl': 15.5.4 + '@next/swc-win32-arm64-msvc': 15.5.4 + '@next/swc-win32-x64-msvc': 15.5.4 + sharp: 0.34.4 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-releases@2.0.23: {} + + normalize-range@0.1.2: {} + + oauth@0.9.15: {} + + object-assign@4.1.1: {} + + object-hash@2.2.0: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + oidc-token-hash@5.1.1: {} + + openid-client@5.7.1: + dependencies: + jose: 4.15.9 + lru-cache: 6.0.0 + object-hash: 2.2.0 + oidc-token-hash: 5.1.1 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@2.0.0: + dependencies: + character-entities: 1.2.4 + character-entities-legacy: 1.1.4 + character-reference-invalid: 1.1.4 + is-alphanumerical: 1.0.4 + is-decimal: 1.0.4 + is-hexadecimal: 1.0.4 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + possible-typed-array-names@1.1.0: {} + + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + preact-render-to-string@5.2.6(preact@10.27.2): + dependencies: + preact: 10.27.2 + pretty-format: 3.8.0 + + preact@10.27.2: {} + + prelude-ls@1.2.1: {} + + prettier-plugin-tailwindcss@0.6.14(prettier@3.6.2): + dependencies: + prettier: 3.6.2 + + prettier@3.6.2: {} + + pretty-format@3.8.0: {} + + prismjs@1.27.0: {} + + prismjs@1.30.0: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + property-information@5.6.0: + dependencies: + xtend: 4.0.2 + + property-information@7.1.0: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-dom@19.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + + react-force-graph-2d@1.29.0(react@19.2.0): + dependencies: + force-graph: 1.51.0 + prop-types: 15.8.1 + react: 19.2.0 + react-kapsule: 2.5.7(react@19.2.0) + + react-hook-form@7.65.0(react@19.2.0): + dependencies: + react: 19.2.0 + + react-is@16.13.1: {} + + react-kapsule@2.5.7(react@19.2.0): + dependencies: + jerrypick: 1.1.2 + react: 19.2.0 + + react-markdown@10.1.0(@types/react@19.2.2)(react@19.2.0): + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/react': 19.2.2 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.0 + react: 19.2.0 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + react-remove-scroll-bar@2.3.8(@types/react@19.2.2)(react@19.2.0): + dependencies: + react: 19.2.0 + react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.2.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.2 + + react-remove-scroll@2.7.1(@types/react@19.2.2)(react@19.2.0): + dependencies: + react: 19.2.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.2)(react@19.2.0) + react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.2.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.2)(react@19.2.0) + use-sidecar: 1.1.3(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + + react-style-singleton@2.2.3(@types/react@19.2.2)(react@19.2.0): + dependencies: + get-nonce: 1.0.1 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.2 + + react-syntax-highlighter@15.6.6(react@19.2.0): + dependencies: + '@babel/runtime': 7.28.4 + highlight.js: 10.7.3 + highlightjs-vue: 1.0.0 + lowlight: 1.20.0 + prismjs: 1.30.0 + react: 19.2.0 + refractor: 3.6.0 + + react@19.2.0: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + refractor@3.6.0: + dependencies: + hastscript: 6.0.0 + parse-entities: 2.0.0 + prismjs: 1.27.0 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + rehype-katex@7.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/katex': 0.16.7 + hast-util-from-html-isomorphic: 2.0.0 + hast-util-to-text: 4.0.2 + katex: 0.16.25 + unist-util-visit-parents: 6.0.1 + vfile: 6.0.3 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-math@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-math: 3.0.0 + micromark-extension-math: 3.1.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.0 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + sharp@0.34.4: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.4 + '@img/sharp-darwin-x64': 0.34.4 + '@img/sharp-libvips-darwin-arm64': 1.2.3 + '@img/sharp-libvips-darwin-x64': 1.2.3 + '@img/sharp-libvips-linux-arm': 1.2.3 + '@img/sharp-libvips-linux-arm64': 1.2.3 + '@img/sharp-libvips-linux-ppc64': 1.2.3 + '@img/sharp-libvips-linux-s390x': 1.2.3 + '@img/sharp-libvips-linux-x64': 1.2.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + '@img/sharp-linux-arm': 0.34.4 + '@img/sharp-linux-arm64': 0.34.4 + '@img/sharp-linux-ppc64': 0.34.4 + '@img/sharp-linux-s390x': 0.34.4 + '@img/sharp-linux-x64': 0.34.4 + '@img/sharp-linuxmusl-arm64': 0.34.4 + '@img/sharp-linuxmusl-x64': 0.34.4 + '@img/sharp-wasm32': 0.34.4 + '@img/sharp-win32-arm64': 0.34.4 + '@img/sharp-win32-ia32': 0.34.4 + '@img/sharp-win32-x64': 0.34.4 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sonner@2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + source-map-js@1.2.1: {} + + space-separated-tokens@1.1.5: {} + + space-separated-tokens@2.0.2: {} + + stable-hash@0.0.5: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + style-to-js@1.1.18: + dependencies: + style-to-object: 1.0.11 + + style-to-object@1.0.11: + dependencies: + inline-style-parser: 0.2.4 + + styled-jsx@5.1.6(react@19.2.0): + dependencies: + client-only: 0.0.1 + react: 19.2.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwind-merge@3.3.1: {} + + tailwindcss@4.1.14: {} + + tapable@2.3.0: {} + + tar@7.5.1: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 + + tinycolor2@1.6.0: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + tw-animate-css@1.4.0: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.37.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-is@6.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.0.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.1: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + update-browserslist-db@1.1.3(browserslist@4.26.3): + dependencies: + browserslist: 4.26.3 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@19.2.2)(react@19.2.0): + dependencies: + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.2 + + use-sidecar@1.1.3(@types/react@19.2.2)(react@19.2.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.2 + + use-sync-external-store@1.6.0(react@19.2.0): + dependencies: + react: 19.2.0 + + util-deprecate@1.0.2: {} + + uuid@8.3.2: {} + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + web-namespaces@2.0.1: {} + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + xtend@4.0.2: {} + + yallist@4.0.0: {} + + yallist@5.0.0: {} + + yocto-queue@0.1.0: {} + + zod@3.25.76: {} + + zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): + optionalDependencies: + '@types/react': 19.2.2 + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) + + zwitch@2.0.4: {} diff --git a/web/postcss.config.js b/web/postcss.config.js new file mode 100644 index 0000000..1c87846 --- /dev/null +++ b/web/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, +} diff --git a/web/public/heilongjiang-spatial-planning.png b/web/public/heilongjiang-spatial-planning.png new file mode 100644 index 0000000..730f26a Binary files /dev/null and b/web/public/heilongjiang-spatial-planning.png differ diff --git a/web/public/p5-city.html b/web/public/p5-city.html new file mode 100644 index 0000000..8687565 --- /dev/null +++ b/web/public/p5-city.html @@ -0,0 +1,394 @@ + + + + + + p5.js 城市数据可视化 + + + + +
移动鼠标查看区域数据 | 点击切换数据维度 | 按空格切换视图
+ + + diff --git a/web/public/p5-course.html b/web/public/p5-course.html new file mode 100644 index 0000000..b95fe7f --- /dev/null +++ b/web/public/p5-course.html @@ -0,0 +1,195 @@ + + + + + + 国土空间规划课程智能体 + + + + +
+
国土空间规划课程智能体
+
基于大模型的智能问答系统
+
哈尔滨工业大学建筑与设计学院
+
+
移动鼠标与知识网络互动
+ + + diff --git a/web/public/p5-demo.html b/web/public/p5-demo.html new file mode 100644 index 0000000..30469d1 --- /dev/null +++ b/web/public/p5-demo.html @@ -0,0 +1,128 @@ + + + + + + p5.js 互动图形 Demo + + + + +
移动鼠标生成图形 | 点击产生爆炸 | 按空格清空画布
+ + + diff --git a/web/senseable-full-page.png b/web/senseable-full-page.png new file mode 100644 index 0000000..baf47d1 Binary files /dev/null and b/web/senseable-full-page.png differ diff --git a/web/senseable-fullpage.png b/web/senseable-fullpage.png new file mode 100644 index 0000000..baf47d1 Binary files /dev/null and b/web/senseable-fullpage.png differ diff --git a/web/src/app/(auth)/login/page.tsx b/web/src/app/(auth)/login/page.tsx new file mode 100644 index 0000000..15bc98a --- /dev/null +++ b/web/src/app/(auth)/login/page.tsx @@ -0,0 +1,192 @@ +"use client"; + +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import Link from "next/link"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { useAuthStore } from "@/store/auth"; +import { BookOpen, Eye, EyeOff, Loader2 } from "lucide-react"; +import { FlickeringGrid } from "@/components/magicui/flickering-grid"; +import { ThemeToggle } from "@/components/ui/theme-toggle"; + +const loginSchema = z.object({ + username: z.string().min(1, "用户名不能为空"), + password: z.string().min(1, "密码不能为空"), +}); + +type LoginForm = z.infer; + +export default function LoginPage() { + const [showPassword, setShowPassword] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const router = useRouter(); + const { login, error, clearError } = useAuthStore(); + + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(loginSchema), + }); + + const onSubmit = async (data: LoginForm) => { + setIsLoading(true); + clearError(); + + const success = await login(data); + + if (success) { + // 登录成功后回到主页,让用户看到无缝过渡效果 + router.push("/"); + } + + setIsLoading(false); + }; + + return ( +
+ {/* 背景动画 */} + + + {/* 主题切换按钮 */} +
+ +
+ +
+
+ {/* Logo和标题 */} +
+ +
+ +
+ + 国土空间规划课程智能体 + + +

登录您的账户

+
+ + {/* 登录表单 */} + + + 登录 + + 输入您的用户名和密码以访问系统 + + + +
+ {/* 错误提示 */} + {error && ( + + {error} + + )} + + {/* 用户名输入 */} +
+ + + {errors.username && ( +

{errors.username.message}

+ )} +
+ + {/* 密码输入 */} +
+ +
+ + +
+ {errors.password && ( +

{errors.password.message}

+ )} +
+ + {/* 登录按钮 */} + +
+ + {/* 注册链接 */} +
+

+ 还没有账户?{" "} + + 立即注册 + +

+
+
+
+ + {/* 快速登录提示 */} +
+

+ 首次使用?请先注册账户 +

+
+
+
+
+ ); +} diff --git a/web/src/app/(auth)/register/page.tsx b/web/src/app/(auth)/register/page.tsx new file mode 100644 index 0000000..5830b9f --- /dev/null +++ b/web/src/app/(auth)/register/page.tsx @@ -0,0 +1,265 @@ +"use client"; + +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import Link from "next/link"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { useAuthStore } from "@/store/auth"; +import { BookOpen, Eye, EyeOff, Loader2, CheckCircle } from "lucide-react"; +import { FlickeringGrid } from "@/components/magicui/flickering-grid"; +import { ThemeToggle } from "@/components/ui/theme-toggle"; + +const registerSchema = z.object({ + username: z.string().min(3, "用户名至少3个字符").max(20, "用户名最多20个字符"), + email: z.string().email("请输入有效的邮箱地址"), + password: z.string().min(6, "密码至少6个字符"), + confirmPassword: z.string(), + full_name: z.string().optional(), +}).refine((data) => data.password === data.confirmPassword, { + message: "密码不匹配", + path: ["confirmPassword"], +}); + +type RegisterForm = z.infer; + +export default function RegisterPage() { + const [showPassword, setShowPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const router = useRouter(); + const { register: registerUser, error, clearError } = useAuthStore(); + + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(registerSchema), + }); + + const onSubmit = async (data: RegisterForm) => { + setIsLoading(true); + clearError(); + + const success = await registerUser({ + username: data.username, + email: data.email, + password: data.password, + full_name: data.full_name, + }); + + if (success) { + router.push("/chat"); + } + + setIsLoading(false); + }; + + return ( +
+ {/* 背景动画 */} + + + {/* 主题切换按钮 */} +
+ +
+ +
+
+ {/* Logo和标题 */} +
+ +
+ +
+ + 国土空间规划课程智能体 + + +

创建您的账户

+
+ + {/* 注册表单 */} + + + 注册 + + 填写以下信息创建您的账户 + + + +
+ {/* 错误提示 */} + {error && ( + + {error} + + )} + + {/* 用户名输入 */} +
+ + + {errors.username && ( +

{errors.username.message}

+ )} +
+ + {/* 邮箱输入 */} +
+ + + {errors.email && ( +

{errors.email.message}

+ )} +
+ + {/* 姓名输入 */} +
+ + + {errors.full_name && ( +

{errors.full_name.message}

+ )} +
+ + {/* 密码输入 */} +
+ +
+ + +
+ {errors.password && ( +

{errors.password.message}

+ )} +
+ + {/* 确认密码输入 */} +
+ +
+ + +
+ {errors.confirmPassword && ( +

{errors.confirmPassword.message}

+ )} +
+ + {/* 注册按钮 */} + +
+ + {/* 登录链接 */} +
+

+ 已有账户?{" "} + + 立即登录 + +

+
+
+
+ + {/* 注册提示 */} +
+

+ 注册即表示您同意我们的服务条款和隐私政策 +

+
+
+
+
+ ); +} diff --git a/web/src/app/(main)/analytics/page.tsx b/web/src/app/(main)/analytics/page.tsx new file mode 100644 index 0000000..fe9eebf --- /dev/null +++ b/web/src/app/(main)/analytics/page.tsx @@ -0,0 +1,419 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { useAuthStore } from "@/store/auth"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { + BarChart3, + TrendingUp, + BookOpen, + MessageSquare, + FileText, + Calendar, + Target, + Lightbulb, + Download, + Share2 +} from "lucide-react"; +import LoadingSpinner from "@/components/ui/loading-spinner"; +import { analyticsAPI } from "@/lib/api"; + +interface Statistics { + total_sessions: number; + total_messages: number; + total_documents: number; + active_days: number; + popular_questions: Array<{ + question: string; + count: number; + category: string; + }>; + knowledge_coverage: Array<{ + topic: string; + coverage: number; + questions: number; + }>; + learning_trends: Array<{ + date: string; + messages: number; + sessions: number; + }>; +} + +interface LearningReport { + user_id: number; + total_questions: number; + topics_covered: string[]; + learning_progress: number; + recommendations: string[]; + study_time: number; + knowledge_gaps: string[]; +} + +export default function AnalyticsPage() { + const router = useRouter(); + const { isAuthenticated, isLoading: authLoading } = useAuthStore(); + + const [statistics, setStatistics] = useState(null); + const [learningReport, setLearningReport] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [activeTab, setActiveTab] = useState("overview"); + + useEffect(() => { + if (!authLoading && !isAuthenticated) { + router.push("/login"); + return; + } + + if (isAuthenticated) { + loadAnalyticsData(); + } + }, [isAuthenticated, authLoading, router]); + + const loadAnalyticsData = async () => { + try { + setIsLoading(true); + + // 调用真实API获取完整分析数据 + const response = await analyticsAPI.getFullAnalytics(); + + if (response.success) { + const { statistics, learning_trends, popular_questions, knowledge_coverage, learning_report } = response.data; + + // 构建Statistics对象 + const statisticsData: Statistics = { + total_sessions: statistics.total_sessions, + total_messages: statistics.total_messages, + total_documents: statistics.total_documents, + active_days: statistics.active_days, + popular_questions: popular_questions, + knowledge_coverage: knowledge_coverage, + learning_trends: learning_trends + }; + + // 构建LearningReport对象 + const learningReportData: LearningReport = { + user_id: learning_report.user_id, + total_questions: learning_report.total_questions, + topics_covered: learning_report.topics_covered, + learning_progress: learning_report.learning_progress, + recommendations: learning_report.recommendations, + study_time: learning_report.study_time, + knowledge_gaps: learning_report.knowledge_gaps + }; + + setStatistics(statisticsData); + setLearningReport(learningReportData); + } else { + throw new Error("API返回失败"); + } + + } catch (err) { + console.error("加载分析数据失败:", err); + // 如果API调用失败,使用模拟数据作为后备 + const mockStatistics: Statistics = { + total_sessions: 0, + total_messages: 0, + total_documents: 0, + active_days: 0, + popular_questions: [], + knowledge_coverage: [], + learning_trends: [] + }; + + const mockLearningReport: LearningReport = { + user_id: 0, + total_questions: 0, + topics_covered: [], + learning_progress: 0, + recommendations: ["请先开始学习以获取分析数据"], + study_time: 0, + knowledge_gaps: [] + }; + + setStatistics(mockStatistics); + setLearningReport(mockLearningReport); + } finally { + setIsLoading(false); + } + }; + + const formatTime = (minutes: number) => { + const hours = Math.floor(minutes / 60); + const mins = minutes % 60; + return `${hours}小时${mins}分钟`; + }; + + if (authLoading || isLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated) { + return null; + } + + return ( +
+
+ {/* 页面头部 */} +
+

学习分析

+

了解您的学习进度和知识掌握情况

+
+ + {/* 标签页 */} +
+ {[ + { id: "overview", name: "总览", icon: BarChart3 }, + { id: "progress", name: "学习进度", icon: TrendingUp }, + { id: "knowledge", name: "知识图谱", icon: BookOpen } + ].map((tab) => ( + + ))} +
+ + {/* 总览标签页 */} + {activeTab === "overview" && statistics && ( +
+ {/* 关键指标 */} +
+ + +
+ +
+

对话会话

+

{statistics.total_sessions}

+
+
+
+
+ + + +
+ +
+

消息总数

+

{statistics.total_messages}

+
+
+
+
+ + + +
+ +
+

文档数量

+

{statistics.total_documents}

+
+
+
+
+ + + +
+ +
+

活跃天数

+

{statistics.active_days}

+
+
+
+
+
+ + {/* 知识覆盖度 */} + + + 知识覆盖度 + 各主题的学习覆盖情况 + + +
+ {statistics.knowledge_coverage.map((item, index) => ( +
+
+ {item.topic} + {item.coverage}% +
+
+
+
+
+ {item.questions} 个问题 + {item.coverage}% 掌握度 +
+
+ ))} +
+ + + + {/* 热门问题 */} + + + 热门问题 + 您最常问的问题 + + +
+ {statistics.popular_questions.map((item, index) => ( +
+
+

{item.question}

+

{item.category}

+
+
{item.count} 次
+
+ ))} +
+
+
+
+ )} + + {/* 学习进度标签页 */} + {activeTab === "progress" && learningReport && ( +
+ {/* 学习进度 */} + + + 学习进度 + 您的整体学习进度 + + +
+
+ 总体进度 + {learningReport.learning_progress}% +
+
+
+
+
+
+ 学习时间: + {formatTime(learningReport.study_time)} +
+
+ 问题总数: + {learningReport.total_questions} +
+
+
+ + + + {/* 学习建议 */} + + + + + 学习建议 + + 基于您的学习情况,我们为您提供以下建议 + + +
+ {learningReport.recommendations.map((recommendation, index) => ( +
+
+

{recommendation}

+
+ ))} +
+ + + + {/* 知识缺口 */} + + + + + 知识缺口 + + 需要重点关注的学习领域 + + +
+ {learningReport.knowledge_gaps.map((gap, index) => ( +
+
+

{gap}

+
+ ))} +
+ + +
+ )} + + {/* 知识图谱标签页 */} + {activeTab === "knowledge" && ( +
+ + + 知识图谱 + 您的知识结构可视化 + + +
+ +

知识图谱

+

+ 知识图谱功能正在开发中,将展示您的知识结构和学习路径 +

+ +
+
+
+
+ )} + + {/* 操作按钮 */} +
+ + +
+
+
+ ); +} + + + + + + diff --git a/web/src/app/(main)/chat/page.tsx b/web/src/app/(main)/chat/page.tsx new file mode 100644 index 0000000..bad0e80 --- /dev/null +++ b/web/src/app/(main)/chat/page.tsx @@ -0,0 +1,59 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; +import { useAuthStore } from "@/store/auth"; +import { useChatStore } from "@/store/chat"; +import ChatInterface from "@/components/chat/chat-interface"; +import Sidebar from "@/components/chat/sidebar"; +import MobileNav from "@/components/layout/mobile-nav"; +import LoadingSpinner from "@/components/ui/loading-spinner"; + +export default function ChatPage() { + const router = useRouter(); + const { isAuthenticated, user, isLoading: authLoading } = useAuthStore(); + const { loadSessions, isLoading: chatLoading } = useChatStore(); + const [isInitialized, setIsInitialized] = useState(false); + + useEffect(() => { + if (!authLoading && !isAuthenticated) { + router.push("/login"); + return; + } + + if (isAuthenticated && !isInitialized) { + // 加载聊天会话 + loadSessions(); + setIsInitialized(true); + } + }, [isAuthenticated, authLoading, isInitialized, router, loadSessions]); + + if (authLoading || chatLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated) { + return null; + } + + return ( +
+ {/* 侧边栏 */} +
+ +
+ + {/* 主聊天区域 */} +
+ +
+ + {/* 移动端导航 */} + +
+ ); +} diff --git a/web/src/app/(main)/course-content/page.tsx b/web/src/app/(main)/course-content/page.tsx new file mode 100644 index 0000000..38b4759 --- /dev/null +++ b/web/src/app/(main)/course-content/page.tsx @@ -0,0 +1,289 @@ +"use client"; + +import { useEffect, useState } from "react"; + +// 禁用静态生成 +export const dynamic = 'force-dynamic'; +import { useRouter } from "next/navigation"; +import { useAuthStore } from "@/store/auth"; +import MobileNav from "@/components/layout/mobile-nav"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { + Loader2, + BookOpen, + GraduationCap, + Lightbulb, + Target, + Network, + List +} from "lucide-react"; +import { courseContentAPI } from "@/lib/api"; +import { BookStructure } from "@/types"; +import dynamicImport from "next/dynamic"; +import NodeDetailDialog from "@/components/course-content/node-detail-dialog"; +import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Button } from "@/components/ui/button"; +import { FileText, ChevronRight } from "lucide-react"; + +// 动态导入 KnowledgeGraph 组件,禁用 SSR +const KnowledgeGraph = dynamicImport( + () => import("@/components/course-content/knowledge-graph"), + { ssr: false } +); + +export default function CourseContentPage() { + const router = useRouter(); + const { isAuthenticated, isLoading: authLoading } = useAuthStore(); + const [bookStructure, setBookStructure] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const [viewMode, setViewMode] = useState<'graph' | 'list'>('graph'); + const [selectedNode, setSelectedNode] = useState<{ + type: 'chapter' | 'section' | 'subsection'; + id: number; + title: string; + subsections?: Array<{ id: number; title: string }>; + } | null>(null); + const [isDialogOpen, setIsDialogOpen] = useState(false); + + useEffect(() => { + if (!authLoading && !isAuthenticated) { + router.push("/login"); + return; + } + + if (isAuthenticated) { + loadCourseContent(); + } + }, [isAuthenticated, authLoading, router]); + + const loadCourseContent = async () => { + try { + setIsLoading(true); + setError(null); + const structure = await courseContentAPI.getCourseContent(); + console.log("加载的书籍结构:", structure); + console.log("章节数量:", structure?.chapters?.length || 0); + if (structure?.chapters) { + structure.chapters.forEach((chapter, index) => { + console.log(`章节 ${index + 1}:`, chapter.title, "节数:", chapter.sections?.length || 0); + }); + } + setBookStructure(structure); + } catch (err) { + console.error("加载课程内容失败:", err); + setError("加载课程内容失败: " + (err instanceof Error ? err.message : String(err))); + } finally { + setIsLoading(false); + } + }; + + if (authLoading || isLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated) { + return null; + } + + return ( +
+
+ {/* 页面头部 */} +
+
+
+
+ +
+
+

课程内容

+

探索国土空间规划课程的核心知识点

+
+
+ {/* 视图切换 */} + setViewMode(v as 'graph' | 'list')}> + + + + 知识图谱 + + + + 列表视图 + + + +
+
+ + {/* 错误提示 */} + {error && ( + + {error} + + )} + + {/* 课程内容展示 */} + {!bookStructure ? ( + + + +

暂无课程内容

+

+ 课程内容正在准备中,请稍后再来查看 +

+
+
+ ) : ( + <> + {/* 知识图谱视图 */} + {viewMode === 'graph' && ( +
+ +
+ )} + + {/* 列表视图 */} + {viewMode === 'list' && ( +
+ {bookStructure.chapters.map((chapter) => ( + + +
+ + + 第{chapter.chapter_number}章 {chapter.title} + + +
+
+ + + {chapter.sections.map((section) => ( + +
+ + {section.title} + + +
+ +
+ {section.subsections.length === 0 ? ( +

暂无小节(知识点)

+ ) : ( + <> +

+ 小节(知识点) ({section.subsections.length} 个) +

+
    + {section.subsections.map((subsection) => ( +
  • +
    + + {subsection.title} +
    + +
  • + ))} +
+ + )} +
+
+
+ ))} +
+
+
+ ))} +
+ )} + + )} +
+ + {/* 节点详情对话框 */} + {selectedNode && ( + + )} + + {/* 移动端导航 */} + +
+ ); +} + diff --git a/web/src/app/(main)/forum/page.tsx b/web/src/app/(main)/forum/page.tsx new file mode 100644 index 0000000..b6522ba --- /dev/null +++ b/web/src/app/(main)/forum/page.tsx @@ -0,0 +1,124 @@ +"use client"; + +import { useEffect, useState } from "react"; +import Link from "next/link"; +import { MessageSquare, Loader2, MessageCircle } from "lucide-react"; + +import { forumAPI } from "@/lib/api"; +import type { ForumCategory, ForumPostSummary } from "@/types"; +import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription } from "@/components/ui/alert"; + +export default function ForumHomePage() { + const [categories, setCategories] = useState([]); + const [categoryPosts, setCategoryPosts] = useState>({}); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const loadCategories = async () => { + try { + setIsLoading(true); + const data = await forumAPI.getCategories(); + setCategories(data); + const postsEntries = await Promise.all( + data.map(async (category) => { + try { + const posts = await forumAPI.getPosts(category.id, 10); + return [category.id, posts] as const; + } catch (err) { + console.warn(`加载分类 ${category.name} 的帖子失败:`, err); + return [category.id, []] as const; + } + }) + ); + setCategoryPosts(Object.fromEntries(postsEntries)); + setError(null); + } catch (err) { + const message = err instanceof Error ? err.message : "加载论坛数据失败"; + setError(message); + } finally { + setIsLoading(false); + } + }; + + loadCategories(); + }, []); + + return ( +
+
+

+ + 课程社区 +

+

+ 分享课程学习心得,交流系统使用体验,欢迎参与讨论。 +

+
+ + {isLoading ? ( +
+ + 正在加载社区分类... +
+ ) : error ? ( + + {error} + + ) : ( +
+ {categories.map((category) => ( + + + {category.name} + {category.description && ( + {category.description} + )} + + +
+ {category.post_count} 条讨论 + +
+
+ {categoryPosts[category.id] && categoryPosts[category.id].length > 0 ? ( + categoryPosts[category.id].map((post) => ( + +
+
+ {post.title} +
+
+ {post.author_name} + · + {new Date(new Date(post.created_at).getTime() + 8 * 60 * 60 * 1000).toLocaleString()} + · + {post.reply_count} 条回复 +
+
+ + )) + ) : ( +
+ + 暂无讨论,成为第一个发帖的人吧! +
+ )} +
+
+
+ ))} +
+ )} +
+ ); +} + diff --git a/web/src/app/(main)/knowledge/[id]/page.tsx b/web/src/app/(main)/knowledge/[id]/page.tsx new file mode 100644 index 0000000..9bea8a8 --- /dev/null +++ b/web/src/app/(main)/knowledge/[id]/page.tsx @@ -0,0 +1,501 @@ +"use client"; + +import { useEffect, useState, useRef } from "react"; +import { useRouter, useParams } from "next/navigation"; +import { useAuthStore } from "@/store/auth"; +import { Button } from "@/components/ui/button"; +import MobileNav from "@/components/layout/mobile-nav"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { + Upload, + FileText, + Search, + Plus, + Trash2, + Eye, + CheckCircle, + Clock, + Loader2, + BookOpen, + ArrowLeft, + Settings +} from "lucide-react"; +import { formatFileSize, formatDate } from "@/lib/utils"; +import { knowledgeBaseAPI } from "@/lib/api"; +import { KnowledgeBaseDetail, Document } from "@/types"; + +export default function KnowledgeBaseDetailPage() { + const router = useRouter(); + const params = useParams(); + const { isAuthenticated, isLoading: authLoading } = useAuthStore(); + const [knowledgeBase, setKnowledgeBase] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [searchQuery, setSearchQuery] = useState(""); + const [error, setError] = useState(null); + + // 上传文档对话框状态 + const [isUploadDialogOpen, setIsUploadDialogOpen] = useState(false); + const [uploadFiles, setUploadFiles] = useState([]); + const [uploadTitle, setUploadTitle] = useState(""); + const [uploadDescription, setUploadDescription] = useState(""); + const [isUploading, setIsUploading] = useState(false); + const [uploadProgress, setUploadProgress] = useState<{[key: string]: number}>({}); + const [uploadErrors, setUploadErrors] = useState<{[key: string]: string}>({}); + + const fileInputRef = useRef(null); + const knowledgeBaseId = params.id as string; + + useEffect(() => { + if (!authLoading && !isAuthenticated) { + router.push("/login"); + return; + } + + if (isAuthenticated && knowledgeBaseId) { + loadKnowledgeBase(); + } + }, [isAuthenticated, authLoading, knowledgeBaseId, router]); + + const loadKnowledgeBase = async () => { + try { + setIsLoading(true); + setError(null); + const kb = await knowledgeBaseAPI.getKnowledgeBase(knowledgeBaseId); + setKnowledgeBase(kb); + } catch (err) { + console.error("加载知识库失败:", err); + setError("加载知识库失败"); + } finally { + setIsLoading(false); + } + }; + + const handleFileUpload = async () => { + if (!uploadFiles.length || !knowledgeBase) return; + + try { + setIsUploading(true); + setError(null); + setUploadProgress({}); + setUploadErrors({}); + + const uploadPromises = uploadFiles.map(async (file, index) => { + const fileId = `${file.name}-${index}`; + try { + setUploadProgress(prev => ({ ...prev, [fileId]: 0 })); + + await knowledgeBaseAPI.uploadDocument( + knowledgeBaseId, + file, + file.name.replace(/\.[^/.]+$/, ""), // Use filename as title + undefined // No description for batch uploads + ); + + setUploadProgress(prev => ({ ...prev, [fileId]: 100 })); + } catch (err) { + console.error(`上传文件 ${file.name} 失败:`, err); + setUploadErrors(prev => ({ + ...prev, + [fileId]: err instanceof Error ? err.message : "上传失败" + })); + } + }); + + await Promise.all(uploadPromises); + + // 重新加载知识库详情 + await loadKnowledgeBase(); + + // 重置表单并关闭对话框 + setUploadFiles([]); + setUploadTitle(""); + setUploadDescription(""); + setIsUploadDialogOpen(false); + + } catch (err) { + console.error("批量上传失败:", err); + setError("批量上传失败"); + } finally { + setIsUploading(false); + } + }; + + const handleFileSelect = (event: React.ChangeEvent) => { + const files = event.target.files; + if (files && files.length > 0) { + const fileArray = Array.from(files); + setUploadFiles(fileArray); + if (!uploadTitle && fileArray.length === 1) { + setUploadTitle(fileArray[0].name.replace(/\.[^/.]+$/, "")); + } + } + }; + + const handleDeleteDocument = async (documentId: number) => { + if (!confirm("确定要删除这个文档吗?")) return; + + try { + await knowledgeBaseAPI.deleteDocument(documentId.toString()); + await loadKnowledgeBase(); + } catch (err) { + console.error("删除文档失败:", err); + setError("删除文档失败"); + } + }; + + const handleViewDocument = (doc: Document) => { + // Use the file_path from the document to construct the download URL + // Since backend serves static files from /uploads, we can use the file_path directly + const fileUrl = `/api/uploads/${doc.filename}`; + window.open(fileUrl, '_blank'); + }; + + const filteredDocuments = knowledgeBase?.documents.filter(doc => + doc.title.toLowerCase().includes(searchQuery.toLowerCase()) || + doc.filename.toLowerCase().includes(searchQuery.toLowerCase()) + ) || []; + + if (authLoading || isLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated) { + return null; + } + + if (!knowledgeBase) { + return ( +
+
+

知识库不存在

+

该知识库可能已被删除或您没有访问权限

+ +
+
+ ); + } + + return ( +
+
+ {/* 页面头部 */} +
+
+ +
+ +
+

{knowledgeBase.name}

+

+ {knowledgeBase.description || "暂无描述"} +

+
+
+
+ +
+
+ + 创建时间:{formatDate(knowledgeBase.created_at)} +
+
+ + 共 {knowledgeBase.document_count} 个文档 +
+
+
+ + {/* 错误提示 */} + {error && ( + + {error} + + )} + + {/* 操作栏 */} +
+
+ {/* 上传文档按钮 */} + { + setIsUploadDialogOpen(open); + if (open) { + // Reset file input when dialog opens + if (fileInputRef.current) { + fileInputRef.current.value = ""; + } + } else { + // Reset states when dialog closes + setUploadFiles([]); + setUploadTitle(""); + setUploadDescription(""); + setUploadProgress({}); + setUploadErrors({}); + } + }} + > + + + + + + 上传文档到"{knowledgeBase.name}" + + 选择要上传到该知识库的文档 + + +
+
+ + +
+ + {/* 已选择的文件列表 */} + {uploadFiles.length > 0 && ( +
+ +
+ {uploadFiles.map((file, index) => { + const fileId = `${file.name}-${index}`; + const progress = uploadProgress[fileId] || 0; + const error = uploadErrors[fileId]; + + return ( +
+
+
+ + {file.name} + + ({(file.size / 1024 / 1024).toFixed(2)} MB) + +
+ {error && ( +
{error}
+ )} + {progress > 0 && progress < 100 && ( +
+
+
+ )} + {progress === 100 && !error && ( +
✓ 上传完成
+ )} +
+ +
+ ); + })} +
+
+ )} + + {/* 单文件上传时显示标题和描述字段 */} + {uploadFiles.length <= 1 && ( + <> +
+ + setUploadTitle(e.target.value)} + placeholder="请输入文档标题" + disabled={isUploading} + /> +
+
+ + setUploadDescription(e.target.value)} + placeholder="请输入文档描述" + disabled={isUploading} + /> +
+ + )} +
+ + + + + +
+
+ +
+
+ + setSearchQuery(e.target.value)} + className="pl-10 w-64" + /> +
+
+ 共 {filteredDocuments.length} 个文档 +
+
+
+ + {/* 文档列表 */} + {filteredDocuments.length === 0 ? ( + + + +

+ {searchQuery ? "没有找到匹配的文档" : "该知识库还没有文档"} +

+

+ {searchQuery ? "尝试使用其他关键词搜索" : "上传您的第一个文档到此知识库"} +

+ {!searchQuery && ( + + )} +
+
+ ) : ( + + + + + 状态 + 文档标题 + 描述 + 文件类型 + 文件大小 + 上传时间 + 操作 + + + + {filteredDocuments.map((doc) => ( + + + {doc.is_processed ? ( + + ) : ( + + )} + + +
+ + {doc.title} +
+
+ + {doc.description || "暂无描述"} + + {doc.file_type} + {formatFileSize(doc.file_size)} + {formatDate(doc.created_at)} + +
+ + +
+
+
+ ))} +
+
+
+ )} +
+ + {/* 移动端导航 */} + +
+ ); +} diff --git a/web/src/app/(main)/knowledge/page.tsx b/web/src/app/(main)/knowledge/page.tsx new file mode 100644 index 0000000..8e8a207 --- /dev/null +++ b/web/src/app/(main)/knowledge/page.tsx @@ -0,0 +1,318 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; +import { useAuthStore } from "@/store/auth"; +import { Button } from "@/components/ui/button"; +import MobileNav from "@/components/layout/mobile-nav"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; +import { + Upload, + FileText, + Search, + Plus, + Trash2, + Eye, + CheckCircle, + Clock, + Loader2, + BookOpen, + Settings, + FolderOpen +} from "lucide-react"; +import { formatFileSize, formatDate } from "@/lib/utils"; +import { knowledgeBaseAPI } from "@/lib/api"; +import { KnowledgeBase } from "@/types"; + +export default function KnowledgePage() { + const router = useRouter(); + const { isAuthenticated, isLoading: authLoading } = useAuthStore(); + const [knowledgeBases, setKnowledgeBases] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [searchQuery, setSearchQuery] = useState(""); + const [error, setError] = useState(null); + + // 创建知识库对话框状态 + const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); + const [createName, setCreateName] = useState(""); + const [createDescription, setCreateDescription] = useState(""); + const [isCreating, setIsCreating] = useState(false); + + useEffect(() => { + if (!authLoading && !isAuthenticated) { + router.push("/login"); + return; + } + + if (isAuthenticated) { + loadKnowledgeBases(); + } + }, [isAuthenticated, authLoading, router]); + + const loadKnowledgeBases = async () => { + try { + setIsLoading(true); + setError(null); + const bases = await knowledgeBaseAPI.getKnowledgeBases(); + // 过滤掉系统知识库,只显示用户创建的知识库 + const userBases = bases.filter(kb => !kb.is_system); + setKnowledgeBases(userBases); + } catch (err) { + console.error("加载知识库失败:", err); + setError("加载知识库失败"); + } finally { + setIsLoading(false); + } + }; + + const handleCreateKnowledgeBase = async () => { + if (!createName.trim()) return; + + try { + setIsCreating(true); + setError(null); + + await knowledgeBaseAPI.createKnowledgeBase({ + name: createName.trim(), + description: createDescription.trim() || undefined, + }); + + // 重新加载知识库列表 + await loadKnowledgeBases(); + + // 重置表单并关闭对话框 + setCreateName(""); + setCreateDescription(""); + setIsCreateDialogOpen(false); + + } catch (err) { + console.error("创建知识库失败:", err); + setError("创建知识库失败"); + } finally { + setIsCreating(false); + } + }; + + const handleDeleteKnowledgeBase = async (knowledgeBaseId: number) => { + if (!confirm("确定要删除这个知识库吗?这将删除其中的所有文档。")) return; + + try { + await knowledgeBaseAPI.deleteKnowledgeBase(knowledgeBaseId.toString()); + await loadKnowledgeBases(); + } catch (err) { + console.error("删除知识库失败:", err); + setError("删除知识库失败"); + } + }; + + const filteredKnowledgeBases = knowledgeBases.filter(kb => + kb.name.toLowerCase().includes(searchQuery.toLowerCase()) || + (kb.description && kb.description.toLowerCase().includes(searchQuery.toLowerCase())) + ); + + if (authLoading || isLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated) { + return null; + } + + return ( +
+
+ {/* 页面头部 */} +
+

知识库管理

+

创建和管理您的知识库,组织文档内容

+
+ + {/* 错误提示 */} + {error && ( + + {error} + + )} + + {/* 操作栏 */} +
+
+ {/* 创建知识库按钮 */} + + + + + + + 创建新知识库 + + 创建一个新的知识库来组织您的文档 + + +
+
+ + setCreateName(e.target.value)} + placeholder="请输入知识库名称" + disabled={isCreating} + /> +
+
+ + setCreateDescription(e.target.value)} + placeholder="请输入知识库描述" + disabled={isCreating} + /> +
+
+ + + + +
+
+
+ +
+
+ + setSearchQuery(e.target.value)} + className="pl-10 w-64" + /> +
+
+ 共 {filteredKnowledgeBases.length} 个知识库 +
+
+
+ + {/* 知识库列表 */} + {filteredKnowledgeBases.length === 0 ? ( + + + +

+ {searchQuery ? "没有找到匹配的知识库" : "还没有创建知识库"} +

+

+ {searchQuery ? "尝试使用其他关键词搜索" : "创建您的第一个知识库来组织文档"} +

+ {!searchQuery && ( + + )} +
+
+ ) : ( +
+ {filteredKnowledgeBases.map((kb) => ( + + +
+
+ +
+ {kb.name} + + {kb.description || "暂无描述"} + +
+
+
+ {kb.document_count > 0 ? ( + + ) : ( + + )} +
+
+
+ +
+
+ 文档数量 + {kb.document_count} 个文档 +
+
+ 创建时间 + {formatDate(kb.created_at)} +
+
+ 状态 + 0 ? "text-green-600" : "text-gray-500"}> + {kb.document_count > 0 ? "已就绪" : "空知识库"} + +
+
+ +
+ + +
+
+
+ ))} +
+ )} +
+ + {/* 移动端导航 */} + +
+ ); +} diff --git a/web/src/app/(main)/layout.tsx b/web/src/app/(main)/layout.tsx new file mode 100644 index 0000000..d8d32ad --- /dev/null +++ b/web/src/app/(main)/layout.tsx @@ -0,0 +1,21 @@ +"use client"; + +import { useAuthStore } from "@/store/auth"; +import Navbar from "@/components/home/navbar"; + +export default function MainLayout({ + children, +}: { + children: React.ReactNode; +}) { + const { isAuthenticated, user } = useAuthStore(); + + return ( +
+ +
+ {children} +
+
+ ); +} diff --git a/web/src/app/(main)/profile/page.tsx b/web/src/app/(main)/profile/page.tsx new file mode 100644 index 0000000..c121a3e --- /dev/null +++ b/web/src/app/(main)/profile/page.tsx @@ -0,0 +1,395 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { useAuthStore } from "@/store/auth"; +import MobileNav from "@/components/layout/mobile-nav"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { + Loader2, + User as UserIcon, + Mail, + Calendar, + CheckCircle, + Edit2, + Save, + X, + MessageSquare, + Database, + FileText +} from "lucide-react"; +import { authAPI, analyticsAPI } from "@/lib/api"; +import { formatDate } from "@/lib/utils"; + +const profileSchema = z.object({ + email: z.string().email("请输入有效的邮箱地址"), + full_name: z.string().optional(), +}); + +type ProfileForm = z.infer; + +export default function ProfilePage() { + const router = useRouter(); + const { isAuthenticated, isLoading: authLoading, user, setUser } = useAuthStore(); + const [isLoading, setIsLoading] = useState(true); + const [isEditing, setIsEditing] = useState(false); + const [isSaving, setIsSaving] = useState(false); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(null); + const [statistics, setStatistics] = useState<{ + total_sessions: number; + total_messages: number; + total_documents: number; + active_days: number; + } | null>(null); + + const { + register, + handleSubmit, + formState: { errors }, + reset, + setValue, + } = useForm({ + resolver: zodResolver(profileSchema), + defaultValues: { + email: user?.email || "", + full_name: user?.full_name || "", + }, + }); + + useEffect(() => { + if (!authLoading && !isAuthenticated) { + router.push("/login"); + return; + } + + if (isAuthenticated) { + loadUserData(); + } + }, [isAuthenticated, authLoading, router]); + + useEffect(() => { + if (user) { + setValue("email", user.email || ""); + setValue("full_name", user.full_name || ""); + } + }, [user, setValue]); + + const loadUserData = async () => { + try { + setIsLoading(true); + setError(null); + + // 加载用户信息 + const userData = await authAPI.getCurrentUser(); + setUser(userData); + + // 加载统计数据 + try { + const stats = await analyticsAPI.getStatistics(); + setStatistics({ + total_sessions: stats.total_sessions || 0, + total_messages: stats.total_messages || 0, + total_documents: stats.total_documents || 0, + active_days: stats.active_days || 0, + }); + } catch (err) { + console.warn("加载统计数据失败:", err); + // 统计数据加载失败不影响页面显示 + } + } catch (err) { + console.error("加载用户信息失败:", err); + setError("加载用户信息失败"); + } finally { + setIsLoading(false); + } + }; + + const onSubmit = async (data: ProfileForm) => { + try { + setIsSaving(true); + setError(null); + setSuccess(null); + + const updatedUser = await authAPI.updateUserInfo({ + email: data.email, + full_name: data.full_name || undefined, + }); + + setUser(updatedUser); + setIsEditing(false); + setSuccess("个人信息更新成功"); + + // 3秒后清除成功消息 + setTimeout(() => setSuccess(null), 3000); + } catch (err: any) { + console.error("更新用户信息失败:", err); + setError(err.message || "更新用户信息失败"); + } finally { + setIsSaving(false); + } + }; + + const handleCancel = () => { + reset({ + email: user?.email || "", + full_name: user?.full_name || "", + }); + setIsEditing(false); + setError(null); + setSuccess(null); + }; + + if (authLoading || isLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated || !user) { + return null; + } + + const initials = (user.full_name || user.username || "U").charAt(0).toUpperCase(); + + return ( +
+
+ {/* 页面头部 */} +
+

个人资料

+

管理您的个人信息和账户设置

+
+ + {/* 错误提示 */} + {error && ( + + {error} + + )} + + {/* 成功提示 */} + {success && ( + + + + {success} + + + )} + +
+ {/* 左侧:用户头像和基本信息 */} +
+ {/* 用户头像卡片 */} + + + 头像 + 您的账户头像 + + +
+
+ {initials} +
+
+

+ 当前使用用户名首字母作为头像 +

+

+ 未来版本将支持上传自定义头像 +

+
+
+
+
+ + {/* 基本信息卡片 */} + + +
+
+ 基本信息 + 您的账户基本信息 +
+ {!isEditing && ( + + )} +
+
+ +
+ {/* 用户名(只读) */} +
+ + +

+ 用户名创建后无法修改 +

+
+ + {/* 邮箱(可编辑) */} +
+ + + {errors.email && ( +

+ {errors.email.message} +

+ )} +
+ + {/* 真实姓名(可编辑) */} +
+ + +
+ + {/* 注册时间(只读) */} +
+ + +
+ + {/* 账户状态(只读) */} +
+ +
+ + {user.is_active && ( + + )} +
+
+ + {/* 编辑模式下的按钮 */} + {isEditing && ( +
+ + +
+ )} +
+
+
+
+ + {/* 右侧:学习统计 */} +
+ + + 学习统计 + 您的学习数据概览 + + + {statistics ? ( +
+
+
+ + 总对话数 +
+ {statistics.total_sessions} +
+
+
+ + 总消息数 +
+ {statistics.total_messages} +
+
+
+ + 知识库 +
+ - +
+
+
+ + 文档数 +
+ {statistics.total_documents} +
+
+ ) : ( +
+ +

加载统计数据中...

+
+ )} +
+
+
+
+
+ + {/* 移动端导航 */} + +
+ ); +} + diff --git a/web/src/app/(main)/settings/page.tsx b/web/src/app/(main)/settings/page.tsx new file mode 100644 index 0000000..364cc57 --- /dev/null +++ b/web/src/app/(main)/settings/page.tsx @@ -0,0 +1,357 @@ +"use client"; + +import { useState } from "react"; + +// 禁用静态生成 +export const dynamic = 'force-dynamic'; +import { useRouter } from "next/navigation"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { useAuthStore } from "@/store/auth"; +import MobileNav from "@/components/layout/mobile-nav"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { ThemeToggle } from "@/components/ui/theme-toggle"; +import { + Loader2, + Lock, + Eye, + EyeOff, + CheckCircle, + Shield, + Palette, + Key +} from "lucide-react"; +import { authAPI } from "@/lib/api"; + +const passwordSchema = z.object({ + old_password: z.string().min(1, "请输入当前密码"), + new_password: z.string().min(6, "密码至少6个字符"), + confirm_password: z.string().min(1, "请确认新密码"), +}).refine((data) => data.new_password === data.confirm_password, { + message: "新密码与确认密码不匹配", + path: ["confirm_password"], +}); + +type PasswordForm = z.infer; + +// 密码强度检查函数 +function getPasswordStrength(password: string): { + strength: "weak" | "medium" | "strong"; + label: string; + color: string; + score: number; +} { + if (!password) { + return { strength: "weak", label: "", color: "", score: 0 }; + } + + let score = 0; + if (password.length >= 6) score++; + if (password.length >= 8) score++; + if (/[a-z]/.test(password)) score++; + if (/[A-Z]/.test(password)) score++; + if (/[0-9]/.test(password)) score++; + if (/[^a-zA-Z0-9]/.test(password)) score++; + + if (score <= 2) { + return { strength: "weak", label: "弱", color: "text-red-600", score }; + } else if (score <= 4) { + return { strength: "medium", label: "中", color: "text-yellow-600", score }; + } else { + return { strength: "strong", label: "强", color: "text-green-600", score }; + } +} + +export default function SettingsPage() { + const router = useRouter(); + const { isAuthenticated, isLoading: authLoading } = useAuthStore(); + const [showOldPassword, setShowOldPassword] = useState(false); + const [showNewPassword, setShowNewPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(null); + + const { + register, + handleSubmit, + formState: { errors }, + watch, + reset, + } = useForm({ + resolver: zodResolver(passwordSchema), + }); + + const newPassword = watch("new_password"); + const passwordStrength = getPasswordStrength(newPassword || ""); + + const onSubmit = async (data: PasswordForm) => { + try { + setIsSubmitting(true); + setError(null); + setSuccess(null); + + await authAPI.changePassword({ + old_password: data.old_password, + new_password: data.new_password, + }); + + setSuccess("密码修改成功"); + reset(); + + // 3秒后清除成功消息 + setTimeout(() => setSuccess(null), 3000); + } catch (err: any) { + console.error("修改密码失败:", err); + setError(err.message || "修改密码失败,请检查当前密码是否正确"); + } finally { + setIsSubmitting(false); + } + }; + + if (authLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated) { + router.push("/login"); + return null; + } + + return ( +
+
+ {/* 页面头部 */} +
+

设置

+

管理您的账户设置和偏好

+
+ + {/* 错误提示 */} + {error && ( + + {error} + + )} + + {/* 成功提示 */} + {success && ( + + + + {success} + + + )} + +
+ {/* 账户安全 */} + + +
+ + 账户安全 +
+ 修改您的登录密码 +
+ +
+ {/* 当前密码 */} +
+ +
+ + +
+ {errors.old_password && ( +

+ {errors.old_password.message} +

+ )} +
+ + {/* 新密码 */} +
+ +
+ + +
+ {newPassword && ( +
+
+ 密码强度: + + {passwordStrength.label} + +
+
+
+
+
+ )} + {errors.new_password && ( +

+ {errors.new_password.message} +

+ )} +
+ + {/* 确认新密码 */} +
+ +
+ + +
+ {errors.confirm_password && ( +

+ {errors.confirm_password.message} +

+ )} +
+ + {/* 密码要求提示 */} +
+

密码要求:

+
    +
  • • 至少6个字符
  • +
  • • 建议包含大小写字母、数字和特殊字符
  • +
  • • 避免使用常用密码或个人信息
  • +
+
+ + {/* 提交按钮 */} +
+ +
+ + + + + {/* 偏好设置 */} + + +
+ + 偏好设置 +
+ 自定义您的使用偏好 +
+ +
+ {/* 主题设置 */} +
+
+
+ + +
+

+ 切换浅色/深色主题模式 +

+
+ +
+ + {/* 未来可添加其他偏好设置 */} +
+

+ 更多偏好设置功能即将推出 +

+
+
+
+
+
+
+ + {/* 移动端导航 */} + +
+ ); +} + diff --git a/web/src/app/(main)/spatial/image-to-image/page.tsx b/web/src/app/(main)/spatial/image-to-image/page.tsx new file mode 100644 index 0000000..84e76ab --- /dev/null +++ b/web/src/app/(main)/spatial/image-to-image/page.tsx @@ -0,0 +1,697 @@ +"use client"; + +import { useState, useEffect, useRef } from "react"; +import { motion } from "framer-motion"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Textarea } from "@/components/ui/textarea"; +import { Badge } from "@/components/ui/badge"; +import { Separator } from "@/components/ui/separator"; +import { Slider } from "@/components/ui/slider"; +import { Loader2, Download, Copy, Upload, Edit3, Wand2, Expand, Palette, Image as ImageIcon, X } from "lucide-react"; +import { imageAPI } from "@/lib/api"; +import { toast } from "sonner"; + +interface EditResult { + id: string; + url: string; + original_filename?: string; + edit_prompt: string; + mode: string; + metadata: any; +} + +interface VariationResult { + id: string; + url: string; + type: string; + metadata: any; +} + +interface ConfigOption { + id: string; + name: string; + description: string; +} + +export default function ImageToImagePage() { + const [selectedImage, setSelectedImage] = useState(null); + const [imagePreview, setImagePreview] = useState(""); + const [editMode, setEditMode] = useState("optimize"); + const [editPrompt, setEditPrompt] = useState(""); + const [strength, setStrength] = useState(0.8); + const [numVariations, setNumVariations] = useState(3); + const [isProcessing, setIsProcessing] = useState(false); + const [editResult, setEditResult] = useState(null); + const [variations, setVariations] = useState([]); + + // Canvas 相关状态 + const [isDrawing, setIsDrawing] = useState(false); + const [brushSize, setBrushSize] = useState(20); + const [maskData, setMaskData] = useState(""); + + // 配置选项 + const [editModes, setEditModes] = useState([]); + const [stylePresets, setStylePresets] = useState([]); + + const canvasRef = useRef(null); + const fileInputRef = useRef(null); + + // 加载配置选项 + useEffect(() => { + const loadConfigs = async () => { + try { + const [modesData, presetsData] = await Promise.all([ + imageAPI.getEditModes(), + imageAPI.getStylePresets(), + ]); + + setEditModes(modesData); + setStylePresets(presetsData); + } catch (error) { + console.error("加载配置失败:", error); + toast.error("加载配置失败"); + } + }; + + loadConfigs(); + }, []); + + // 处理图像上传 + const handleImageUpload = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (file) { + setSelectedImage(file); + const reader = new FileReader(); + reader.onload = (e) => { + setImagePreview(e.target?.result as string); + }; + reader.readAsDataURL(file); + } + }; + + // 处理拖拽上传 + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + const file = event.dataTransfer.files[0]; + if (file && file.type.startsWith("image/")) { + setSelectedImage(file); + const reader = new FileReader(); + reader.onload = (e) => { + setImagePreview(e.target?.result as string); + }; + reader.readAsDataURL(file); + } + }; + + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); + }; + + // Canvas 绘制蒙版 + const handleCanvasMouseDown = (event: React.MouseEvent) => { + setIsDrawing(true); + drawOnCanvas(event); + }; + + const handleCanvasMouseMove = (event: React.MouseEvent) => { + if (!isDrawing) return; + drawOnCanvas(event); + }; + + const handleCanvasMouseUp = () => { + setIsDrawing(false); + // 导出蒙版数据 + const canvas = canvasRef.current; + if (canvas) { + const dataURL = canvas.toDataURL(); + setMaskData(dataURL); + } + }; + + const drawOnCanvas = (event: React.MouseEvent) => { + const canvas = canvasRef.current; + if (!canvas) return; + + const rect = canvas.getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = event.clientY - rect.top; + + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + ctx.globalCompositeOperation = "source-over"; + ctx.fillStyle = "rgba(255, 0, 0, 0.5)"; + ctx.beginPath(); + ctx.arc(x, y, brushSize / 2, 0, Math.PI * 2); + ctx.fill(); + }; + + // 清除蒙版 + const clearMask = () => { + const canvas = canvasRef.current; + if (canvas) { + const ctx = canvas.getContext("2d"); + if (ctx) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + setMaskData(""); + } + } + }; + + // 图像编辑 + const handleImageEdit = async () => { + if (!selectedImage) { + toast.error("请先上传图像"); + return; + } + + if (!editPrompt.trim()) { + toast.error("请输入编辑描述"); + return; + } + + setIsProcessing(true); + try { + let maskFile: File | undefined; + if (editMode === "local_edit" && maskData) { + // 将蒙版数据转换为文件 + const response = await fetch(maskData); + const blob = await response.blob(); + maskFile = new File([blob], "mask.png", { type: "image/png" }); + } + + const result = await imageAPI.imageEdit( + selectedImage, + editPrompt, + editMode, + maskFile, + strength + ); + + setEditResult(result); + toast.success("图像编辑完成"); + } catch (error) { + console.error("图像编辑失败:", error); + toast.error("图像编辑失败,请重试"); + } finally { + setIsProcessing(false); + } + }; + + // 生成变体 + const handleGenerateVariations = async () => { + if (!selectedImage) { + toast.error("请先上传图像"); + return; + } + + setIsProcessing(true); + try { + const result = await imageAPI.imageVariations(selectedImage, numVariations); + setVariations(result.variations); + toast.success(`成功生成 ${result.total} 个变体`); + } catch (error) { + console.error("生成变体失败:", error); + toast.error("生成变体失败,请重试"); + } finally { + setIsProcessing(false); + } + }; + + // 风格转换 + const handleStyleTransfer = async () => { + if (!selectedImage) { + toast.error("请先上传图像"); + return; + } + + if (!editPrompt.trim()) { + toast.error("请输入风格描述"); + return; + } + + setIsProcessing(true); + try { + const result = await imageAPI.styleTransfer(selectedImage, editPrompt, strength); + setEditResult(result); + toast.success("风格转换完成"); + } catch (error) { + console.error("风格转换失败:", error); + toast.error("风格转换失败,请重试"); + } finally { + setIsProcessing(false); + } + }; + + // 图像优化 + const handleOptimizeImage = async () => { + if (!selectedImage) { + toast.error("请先上传图像"); + return; + } + + setIsProcessing(true); + try { + const result = await imageAPI.optimizeImage(selectedImage, editPrompt || "优化图像质量,增强细节,提高清晰度", strength); + setEditResult(result); + toast.success("图像优化完成"); + } catch (error) { + console.error("图像优化失败:", error); + toast.error("图像优化失败,请重试"); + } finally { + setIsProcessing(false); + } + }; + + // 图像扩展 + const handleOutpaintImage = async () => { + if (!selectedImage) { + toast.error("请先上传图像"); + return; + } + + if (!editPrompt.trim()) { + toast.error("请输入扩展描述"); + return; + } + + setIsProcessing(true); + try { + const result = await imageAPI.outpaintImage(selectedImage, editPrompt, strength); + setEditResult(result); + toast.success("图像扩展完成"); + } catch (error) { + console.error("图像扩展失败:", error); + toast.error("图像扩展失败,请重试"); + } finally { + setIsProcessing(false); + } + }; + + // 执行操作 + const handleExecute = () => { + switch (editMode) { + case "optimize": + handleOptimizeImage(); + break; + case "style_transfer": + handleStyleTransfer(); + break; + case "local_edit": + handleImageEdit(); + break; + case "outpaint": + handleOutpaintImage(); + break; + default: + handleImageEdit(); + } + }; + + const handleDownload = (imageUrl: string, imageId: string) => { + const link = document.createElement("a"); + link.href = imageUrl; + link.download = `edited-image-${imageId}.png`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + toast.success("图像下载成功"); + }; + + return ( +
+
+ {/* 页面标题 */} + +

+ 图生图 - Image to Image +

+

+ 基于已有图像进行编辑、优化、风格转换和局部修改 +

+
+ +
+ {/* 左侧:图像上传和编辑配置 */} + + {/* 图像上传 */} + + + + + 上传图像 + + + 上传您想要编辑的图像 + + + + {!selectedImage ? ( +
fileInputRef.current?.click()} + onDrop={handleDrop} + onDragOver={handleDragOver} + > + +

点击上传或拖拽图像到此处

+

支持 PNG, JPG, JPEG 格式

+ +
+ ) : ( +
+
+ Uploaded image + +
+
+ {selectedImage.name} + + {(selectedImage.size / 1024 / 1024).toFixed(2)} MB + +
+
+ )} +
+
+ + {/* 编辑配置 */} + + + + + 编辑配置 + + + 选择编辑模式和参数 + + + + {/* 编辑模式 */} +
+ + +
+ + {/* 编辑描述 */} +
+ +