diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000000000000000000000000000000000..8eb523c29743d7cedc146534ddab163236a45a13 --- /dev/null +++ b/.env.example @@ -0,0 +1,67 @@ +## -------------------- DATABASE CONFIGURATION -------------------- ## + +# Local, Postgresql +causalogy--pg--name = "" +causalogy--pg--user = "" +causalogy--pg--password = "" +causalogy--pg--host = "" +causalogy--pg--port = "" + +# Local Postgresql +ss--postgresql--url = "" + + +## -------------------- OBSERVABILITY -------------------- ## + +# Langfuse (dev) +ss--langfuse--secret-key = "" +ss--langfuse--public-key = "" +langfuse--host = "" + + +## -------------------- LLM CONFIGURATION -------------------- ## + +# GEMINI MODEL +GOOGLE_API_KEY= "" + +# GPT-4O-MINI +azureai--api-key--4omini = "" +azureai--endpoint--url--4omini = "" +azureai--deployment--name--4omini = "" +azureai--api--version--4omini = "" + +# GPT-5-MINI +azureai--api-key--5mini = "" +azureai--endpoint--url--5mini = "" +azureai--deployment--name--5mini = "" +azureai--api--version--5mini = "" + +# GPT-4O-2 +azureai--api-key--4o-2 = "" +azureai--endpoint--url--4o-2 = "" +azureai--deployment--name--4o-2 = "" +azureai--api--version--4o-2 = "" + +# Qdrant +ss--qdrant--api-key = "" +ss--qdrant--endpoint--url = "" +ss--qdrant--collection--name = "" + +# Embedding Model +azureai--embedmodel--endpoint = "" +azureai--embedmodel--api-key = "" +azureai--embedmodel--api--version = "" +azureai--embedmodel--name = "" + +# AZURE BLOB +azureai--search--sas = "" +azureai--container--endpoint = "" +azureai--container--name = "" +azureai--container--account--name = "" +azureai--max-file-size-mb = 5 + + +# JWT +ss--jwt--secret-key = "" +ss--jwt--algorithm = "" +ss--jwt--access-token-expire-minutes = 60 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..a6344aac8c09253b3b630fb776ae94478aa0275b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,35 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..22cf9c0596a835f3a1e758948ad8c933cc812d8e --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.venv/ +.env +__pycache__/ +*/__pycache__/ +example/ +software/ +*.xlsx \ No newline at end of file diff --git a/.python-version b/.python-version new file mode 100644 index 0000000000000000000000000000000000000000..24ee5b1be9961e38a503c8e764b7385dbb6ba124 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..2586f65513a70f3a108881d2a3a1fd2bc8b66421 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +FROM python:3.13-slim-bookworm + +# Install uv +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +WORKDIR /app + +# Environment +ENV PYTHONUNBUFFERED=1 \ + UV_COMPILE_BYTECODE=1 \ + UV_SYSTEM_PYTHON=1 + +# System deps (IMPORTANT for bcrypt, cryptography, asyncpg) +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + libpq-dev \ + gcc \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user +RUN addgroup --system app && adduser --system --group app + +# Dependency layer +COPY pyproject.toml uv.lock ./ +RUN uv sync --frozen + +# App code +COPY . . + +RUN chown -R app:app /app +USER app + +EXPOSE 8111 + +CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8111"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c96b19ae32ad7d6d2ad1e5e256a5f5ab94cc550c --- /dev/null +++ b/README.md @@ -0,0 +1,163 @@ +## Schemas +```plain +1. Build Schema + a. table: cv_users ✅ + - user_id + - username + - hashed_password + - email + - full_name + - role + - is_active + - tenant_id + - created_at + - date_modified + - notes + b. table: cv_tenant ✅ + - tenant_id + - tenant_name + - created_at + - date_modified + - notes + c. table: cv_file ✅ + - file_id + - file_type + - filename + - url + - is_extracted + - uploaded_at + - date_modified + d. table: cv_profile ✅ + - profile_id + - fullname + - gpa_edu_1 + - univ_edu_1 + - major_edu_1 + - gpa_edu_2 + - univ_edu_2 + - major_edu_2 + - gpa_edu_3 + - univ_edu_3 + - major_edu_3 + - domicile + - yoe + - hardskills + - softskills + - certifications + - business_domain + - filename + - file_id + - created_at + e. table: cv_filter + - criteria_id + - gpa_edu_1 + - gpa_edu_2 + - gpa_edu_3 + - univ_edu_1 + - univ_edu_2 + - univ_edu_3 + - major_edu_1 + - major_edu_2 + - major_edu_3 + - domicile + - yoe + - hardskills + - softskills + - certifications + - business_domain + - created_at + f. table: cv_weight ✅ + - weight_id + - gpa_edu_1 + - gpa_edu_2 + - gpa_edu_3 + - univ_edu_1 + - univ_edu_2 + - univ_edu_3 + - major_edu_1 + - major_edu_2 + - major_edu_3 + - domicile + - yoe + - hardskills + - softskills + - certifications + - business_domain + - created_at + g. table: cv_matching ✅ + - matching_id + - profile_id + - criteria_id + - gpa_edu_1 + - gpa_edu_2 + - gpa_edu_3 + - univ_edu_1 + - univ_edu_2 + - univ_edu_3 + - major_edu_1 + - major_edu_2 + - major_edu_3 + - domicile + - yoe + - hardskills + - softskills + - certifications + - business_domain + - created_at + g. table: profile_scores ✅ + - score_id + - matching_id + - score + - created_at +``` + + +## List API +### User +```plain +1. create user ✅ +2. get user by username ✅ +3. login #TODO +``` +### Tenant +```plain +1. create tenant ✅ +2. get tenant by tenant_name ✅ +``` + +## Create User Example +Input: +{ + "username": "harryyanto.ia@bukittechnology.com", + "password": "Test12345$!", + "email": "harryyanto.ia@bukittechnology.com", + "full_name": "Harryyanto Ishaq Agasi", + "role": "Admin", + "tenant_id": "03ce53dd-9fc8-43e0-b047-c927602304a9", + "notes": "admin" +} + +Output: +{ + "user_id": "eb3de1ed-2e3f-4c95-b29b-b31f85f01730", + "username": "harryyanto.ia@bukittechnology.com", + "email": "harryyanto.ia@bukittechnology.com", + "full_name": "Harryyanto Ishaq Agasi", + "role": "Admin", + "is_active": true, + "tenant_id": "03ce53dd-9fc8-43e0-b047-c927602304a9", + "created_at": "2026-02-19T15:42:05.726988Z" +} + + + +## How To +1. Init schema on DB +`uv run python -m externals.databases.pg_schema_up` + +2. Drop schema on DB +`uv run python -m externals.databases.pg_schema_down` + + +Compile pyproject.toml to requirements.txt +`uv pip compile pyproject.toml -o requirements.txt` \ No newline at end of file diff --git a/allfiles.txt b/allfiles.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7a56e528581c34f68c95098308182d55bee9bb9 --- /dev/null +++ b/allfiles.txt @@ -0,0 +1,945 @@ +0b13ebed794644b6a34ceeda60f416bfe32458dd +2b6e87a1ac862ea3f70e6ccb60796c7bf4d175bb +2fba27e30bb1f7eb5a2412f66751f4ea7015418b +3e6af0dd88dca2150fe0c5bf4d1c568c9c50e68f +43ff6b9dacc7f01238b1ae3ddfdec8061645622e +484a5afebccc4d1d8dc0b945505943c59b787280 +bfd625a4be135ad83eda97391d04eac1bf43ce2f +ce496bf803b49662a59783a281e477a147863614 +d605a31fef53ae925289707c925a3c47bcae7938 +ef6b5c4b4be954fe22fadd7f1c4612a42ef27572 +38c0e9574d2f03d64c8d3aba3f11682be2e96edc +51b93bf595ae9d3e96bc974c61f5f0231db28b65 +870a26407445889ebab964776f2860e28353bb72 +96605499f87c6f9440d3428fa9006b03e0ba2b0f +9a1f1da613f4f24eb3f51c59b9c96856c5239b0e +9c985a2ae79975f0390db9f7339d0b878578ca0e +b90d7f072ee2870f1ffa89b3bdfd643f4538e67e +ce22fcc2a739826b5ebda00d72b6b42900d66ccc +dab9f4b784f01767f238842ad7b0fd8430191ca9 +fadedf7e9d57688d58354ca6c7fee3a67fa5ad0e +8eb523c29743d7cedc146534ddab163236a45a13 .env.example +a6344aac8c09253b3b630fb776ae94478aa0275b .gitattributes +049f74a19fda63e951a83a68e6e18e255b3a0d9c .gitignore +d77e4f61bcaacc5e1a2d07b3516e70acc2c596b9 .gitignore +24ee5b1be9961e38a503c8e764b7385dbb6ba124 .python-version +0f75af977ead0f3a52ef2a2110a8d5844790389b app.py +67c39967e785d7c9c512151546ff6f3a7d704ab8 app.py +b0a5db4b8a41d9163366f9a4c35607e92ef22702 app.py +cd239d67357a8fbdf62c4e881dfc1b9e96f6a0a7 app.py +dd6d4a056271f924b6531e49c795b487b1f6bc3c app.py +31d368b92d4c6ac076edeeb0ebea816e67112c4d config +e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 config/__init__.py +901cd6b713ff67c60b4b70319d7bd7289c4b0067 config/config.yaml +5b6ae76d696bf5ff0788f6e349e2e84d32594fec config/constant.py +664a24f2f3d8082d96efba45f5c5dbfb87bf5bb4 config/env_constant.py +afada3a9707e9d4f5907bb1b571b7bb79a65c726 config/get_config.py +2586f65513a70f3a108881d2a3a1fd2bc8b66421 Dockerfile +e8bfe895ac2fb8738ca19d76676ee2d64ecdaaef Dockerfile +859ef4ea893bc64421676a3c5288a200293b61bd externals +c8a4a6d629445af12265f315e09e194ed125d3a9 externals/databases +ab4ee64dc2565b991d1fadcf725f71423e943616 externals/databases/_pg_tables.py +f2be3781ec9f136dabeda11d9458b7bd21f1791e externals/databases/_pgdb.py +8b54d8c1a80ccb5d1779c976aca9adf275bac32f externals/databases/database.py +9b32ea520069e6f3ff230174b2317d932edacb85 externals/databases/pg_crud.py +12b4af534976a7917b00ddfd6748cc7f63071d5b externals/databases/pg_models.py +d285f45a1e6fb88fba58df9477c6eef747c22010 externals/databases/pg_schema_down.py +7b3c7007cbde7d3aa71b46a3575ed2c75b7a7ee9 externals/databases/pg_schema_up.py +81067b349555c55fa34ec619e6094e447779dd6d externals/databases/schemas +69638f1f43ae2ddafc2116c7d773d35635f0e0d3 externals/databases/schemas/auth.py +77bac82d9d894290e2c518d0a9885280764b7349 externals/databases/schemas/knowledge.py +b5af23822d0a585ee7a6816580c8e2655f034235 externals/databases/schemas/tenant.py +ce994ebee65727d23353fd089ce1b77290659426 externals/databases/schemas/user.py +fe182aaf7fd60a82a6bfff5627e5b8888e4dabde externals/observability +f31c9224ccc815650c82d0156fd5281e696e84ce externals/observability/langfuse.py +37d7cc77360973beab613611549528390feedbd9 externals/storages +adb47084bcd9671340616eba5e10e38fb7c486a3 externals/storages/azure_blob.py +80d1aac571d98ab1b30ecc94bbdbccc5fb64a2a3 externals/storages/azure_generate_sas.py +8d37c37033d8ba9b2c7e642f8dcfd24f24e93268 interfaces +7d1a2f2a51f390458756e141a55d096bbc88f794 interfaces/api +d09a582dff8fd3b4439fda2c8c34e1acb02a29cb interfaces/api/agentic.py +4f78886f89a0c498b474369d7f9f1031e54f8801 interfaces/api/deps.py +4a8b4e2880bab2c3f9f36f3029721fad407a5d2d interfaces/api/file.py +e9ab3776b92be129f501c053e30e3223d36f9f2c interfaces/api/profile.py +7286a971935996ac887ff81a943e86c5f7906940 interfaces/api/tenant.py +0e83901366694cef25209bc989e91a7e6b4ecc66 interfaces/api/user.py +a72868dc2c8d3313c20c8e9e7c2f793cb23879a8 interfaces/auth +e566718a131034710b018a038d693eda842dbff1 interfaces/handlers +139597f9cb07c5d48bed18984ec4747f4b4f3438 interfaces/handlers/handlers.py +72c36a1fd2c34cffd1a0b7a0397772022371213c interfaces/middlewares +cf5ce287fbe0552ad50c8c1f664f50624ddc1c09 interfaces/middlewares/cors.py +405e3917b44482cd60dac565ec81c3b510de1616 main.py +a61416c52c2805ff02bfd19bb80f81e554496841 models +e913418d0cc0d7f9cc79152274e573a83a597ce3 models/security.py +660ee5ef1f122742d7b943164a700c0353c82fbb playground +24073a266b90be2d80d1b08f5eeb08dfa9462101 playground/playground.py +bdc91f11d02935c0a1fc74fc05be86dee28e0a55 pyproject.toml +1cfcee33a0fe57e36675d4233971eea4ad96fe0c README.md +66d34b0167f59dead73b18c15f42c3b002fb4f97 README.md +bb6a859a13317f2890b74c654273ac22049675b0 README.md +c96b19ae32ad7d6d2ad1e5e256a5f5ab94cc550c README.md +8e0578a0c2cb636e21d871d5ae4fdbb81887bee2 requirements.txt +c1eedc48871c549d796e7502fdaa1c04afcdd0e2 requirements.txt +f3d8b58be3e154106fc348596e7f8329a5be7a7b requirements.txt +ec75fb8e749e5761ba66f6420ba8f14adeb57da4 run.sh +84561ef37696a594debcd5a82033c6f9360f15e4 services +b01f66d80226b76b7a9e349753bd161db56d5891 services +f8c4f72d8e1276052eee2cc62f5601168c5f39f7 services/agentic +c2247deaa58d326f0357f2ee41ba337d8f227436 services/agentic/agentic_setup.py +3994811108414242ec6a132859447fc97a483fe7 services/agentic/filter.py +9d4c0c3a64c1b1a854dc2d61e5210e3e3ed4745c services/agentic/profile_scoring.py +62bd27fd4ec11c3abf76c51d0819704d1ae2eeb3 services/agentic/weight.py +1033bd0433f781c259c1f049a67c1e002f31009d services/agents +f0ee98a09e1c686fe93fe9d733b28de4dcea0a1b services/agents/__init__.py +c221ed8406139355b613c9165f8e170e3976b93f services/agents/AutograderAgent.py +39910c8af3512d41451083040d7050e2fc065331 services/agents/LearningRoadmapAgent.py +8c091645299c0d46b0df85100089a5ec57fc5f9b services/agents/LLMAgent.py +bef791298b086cd223eeca3abeb41643a84cb200 services/agents/ProfileMatchingAgent.py +6ae899ea18dda0183be5d4a5dadab8dc4cdf4477 services/base +95de5a43c24b112839d4f61f9cd303cbc97a2eb8 services/base/BaseGenerator.py +6615b6f93978c90867e5aea1037c5030213ce277 services/embed_model +ac1e1ada3de223cd46a9fe8154f8a718ceb12f8a services/embed_model/embed_model.py +b1182e7df744f0cd1a9c49fd068a54131809295b services/extractor +5c4945e32274cab45a08564eb474104d49a45a74 services/extractor/pdf.py +23c94e12d6e133fecec8f9b66e1f33152929f765 services/knowledge +fa139f0679d8159260db84f51df884cd1cefc075 services/knowledge/delete_file.py +fa6186940d0cf15e3e00d84ae1a7a9ae09ad0adc services/knowledge/extract_profile.py +c65ba06a2f718061c09dc9152758d1548d7f200e services/knowledge/get_profile.py +898ad2aad187bb789cae0c2dd9fafa20e4a207c1 services/knowledge/knowledge_setup.py +9732ee836c9f6da50766bff0099a98b0a6f8dea1 services/knowledge/upload_file.py +1af56c096e9dc3db49b93376b65299a039fc4949 services/knowledge_base +bc2899960440ddebc395363497df93ade123362a services/knowledge_base/CV_urls.xlsx +f77bc420e968354e5b1d11f14783e299a482e506 services/knowledge_base/PipelineKBIngestion.py +bb596798cae105dac250161ca645ad26e90aadc8 services/llms +45cd6281697eb88ea87bb02bfc1ad600e04b51bb services/llms/__init__.py +27bebd8de9c33a1022466e247a147ae4dfbc7bbc services/llms/LLM.py +b9cb9b8496a7b76ee86d6a66b486c9aff082198f services/models +182927603fb11f22a8db0a12b1a34985cc7a6915 services/models/data_model.py +8c5ea878a828e39aa0ab36cf6f5ed3a78067c38a services/pipelines +20c33c70d690f1bc9ff1fbcc59410719191de51f services/pipelines/PipelineKBIngestion.py +716b88ac23286401ade002c66dbe14dddac346cd services/pipelines/PipelineKBProfileExtraction.py +bd7d9be15e69c0726e63126b39fdf9df976ad1e0 services/pipelines/PipelineKBProfileNorm.py +270ab16d04f31a81d56061af1cd901963a03cc82 services/prompts +9ce7dee8ac17e27ef19128b925796acc60489008 services/prompts/AutograderPrompt.md +5c874db37fc457912917431994d465a468ee5e95 services/prompts/LearningRoadmapPrompt.md +7633443bf25c103842fbccb2b9727d6d32f4b331 services/prompts/profile_extraction.py +3b8573e80512f705f078cc636a8d4495c414fe43 services/prompts/profile_matching.py +278dd98491ae6b88f8e1a9cf103da96d4d13305a services/software +278f0b580f55521c0a67173359dca931545943db services/software/poppler-24.08.0 +b115a675f506bd2433d206bd448a298ba025c0da services/software/poppler-24.08.0/Library +0ca1c988cffa37470985a559747f64c81feef307 services/software/poppler-24.08.0/Library/bin +5c723df8c4b2632d1d507012f86e4b2d266fe27e services/software/poppler-24.08.0/Library/bin/cairo.dll +ec63daf29ef67960f812ce4b166dbdce9490f275 services/software/poppler-24.08.0/Library/bin/charset.dll +ac81863783b5d7c7d4ce74ce53921d865a8f11ff services/software/poppler-24.08.0/Library/bin/deflate.dll +963a8dbbeb31997df0317ca405a85120966fc442 services/software/poppler-24.08.0/Library/bin/expat.dll +8d821d2c836662b346470e0a47b79e3f7ed910a1 services/software/poppler-24.08.0/Library/bin/fontconfig-1.dll +10a54260d3045bfa6ee5ea2e282416c65c156c4c services/software/poppler-24.08.0/Library/bin/freetype.dll +99dd64c13d1de1f45666a30a3b227de3d805384f services/software/poppler-24.08.0/Library/bin/iconv.dll +13af15313b701c317135fdfbfdec91572a8781df services/software/poppler-24.08.0/Library/bin/jpeg8.dll +8ce2ff9f262455c4f11ab4d5154e601760e63dc6 services/software/poppler-24.08.0/Library/bin/lcms2.dll +564de764efd2bf60075bfc9bc1f5d6326f59036e services/software/poppler-24.08.0/Library/bin/Lerc.dll +9b27073df1d5c47ea8689d5cec78e0c53b8a8e0b services/software/poppler-24.08.0/Library/bin/libcrypto-3-x64.dll +2622385a31b81377f348d9fab4e8ea9a39df14bb services/software/poppler-24.08.0/Library/bin/libcurl.dll +b4a03710f450c95cbc80e9197714039bdfc8643b services/software/poppler-24.08.0/Library/bin/liblzma.dll +5b5966b9766edde5ec285ae3695e1f6e7b504fe1 services/software/poppler-24.08.0/Library/bin/libpng16.dll +6c98b7fad3c25598b6c6e3eccc7cb1fda934cc73 services/software/poppler-24.08.0/Library/bin/libssh2.dll +e54f84199732a81fcb3e446a657c639e2080908f services/software/poppler-24.08.0/Library/bin/libtiff.dll +fd7af57a7976aead501efb418f0a92fd19cec7a7 services/software/poppler-24.08.0/Library/bin/libzstd.dll +2030ee9824310beb727f7c7c658d0a37c21b9159 services/software/poppler-24.08.0/Library/bin/openjp2.dll +9cf25113fd9ada2bdf75caf5bbc6419fa265a9af services/software/poppler-24.08.0/Library/bin/pdfattach.exe +64e28c540365fb22dcbc328f1773dba97ea25d83 services/software/poppler-24.08.0/Library/bin/pdfdetach.exe +ce8098097ce72b234df94f59818c589d9ad5954c services/software/poppler-24.08.0/Library/bin/pdffonts.exe +18bd5e75ece9b6880355101cdaac9b21a90bd28c services/software/poppler-24.08.0/Library/bin/pdfimages.exe +a46425aba2453cf4c83aaca841d8c2136c7de209 services/software/poppler-24.08.0/Library/bin/pdfinfo.exe +ce5cf711bb919d6d3c991f1d19ccdc6a292dcfa3 services/software/poppler-24.08.0/Library/bin/pdfseparate.exe +f918644d7ed9afb242af2afce8146c8949519180 services/software/poppler-24.08.0/Library/bin/pdftocairo.exe +4eb4a95d56fa7bdb57a6567fc063ea13e188453d services/software/poppler-24.08.0/Library/bin/pdftohtml.exe +3078e3b3eaba60b2b7bc8a3206ac36895718aeac services/software/poppler-24.08.0/Library/bin/pdftoppm.exe +d65bbbf620268997c9a44cbc928e22bf5deb8bc5 services/software/poppler-24.08.0/Library/bin/pdftops.exe +403ceef3023d2563bb252055870f68fa34bbd2d0 services/software/poppler-24.08.0/Library/bin/pdftotext.exe +5d6e0344d2ed2bf8c543efa3e5daaccac0ccf66e services/software/poppler-24.08.0/Library/bin/pdfunite.exe +24f4925dcb5c6b627e9973c061ce10d51c6482bc services/software/poppler-24.08.0/Library/bin/pixman-1-0.dll +16eb098a67b5e741a6953355cd052042e94dc4c4 services/software/poppler-24.08.0/Library/bin/poppler.dll +266cab62fa6b7562bae80d4cf16c8f6eeaeb3d41 services/software/poppler-24.08.0/Library/bin/poppler-cpp.dll +5c68c4337652e0686c59f7792ee9786e2e82ec2f services/software/poppler-24.08.0/Library/bin/poppler-glib.dll +48f858a677ab750b58564e5301fb271b4b37d899 services/software/poppler-24.08.0/Library/bin/zlib.dll +7a427fbf4f88480a8056050d41ce2968fe0433ba services/software/poppler-24.08.0/Library/bin/zstd.exe +b7905bdc1e1201f6bda04ff0b483dabc913bee82 services/software/poppler-24.08.0/Library/include +07b79aad77e0d6f54244579a785f5b4d501ad0e4 services/software/poppler-24.08.0/Library/include/poppler +5d96e7532124a93311d0de827f3f936b36460737 services/software/poppler-24.08.0/Library/include/poppler/Annot.h +ebe6e9191570d1b97db1d9a35c480eb6fd3df310 services/software/poppler-24.08.0/Library/include/poppler/AnnotStampImageHelper.h +50bc9d0aff4a54d2654b57cbd1fbb84b9fa665fb services/software/poppler-24.08.0/Library/include/poppler/Array.h +e48122fd48edcb2bd5844594be618936884cca12 services/software/poppler-24.08.0/Library/include/poppler/BBoxOutputDev.h +854692ea764ce8150edec8c179d30647bdc3c364 services/software/poppler-24.08.0/Library/include/poppler/CachedFile.h +c97e0ea45d6b3235d89b9c740beb011952fdf7e1 services/software/poppler-24.08.0/Library/include/poppler/CairoFontEngine.h +349ec6199b0a9ec376ec19803828a4e1a0d1f500 services/software/poppler-24.08.0/Library/include/poppler/CairoOutputDev.h +2766d483bf33ce11375abb30d7e15fa04c2d882c services/software/poppler-24.08.0/Library/include/poppler/CairoRescaleBox.h +cb76ff8ac3c02ac7e2331cba5bac70f1cc47e6de services/software/poppler-24.08.0/Library/include/poppler/Catalog.h +d2dbc34f4020acbd8f46916ec229eb506e269dda services/software/poppler-24.08.0/Library/include/poppler/CertificateInfo.h +dc2fa84c40b8ce23e0ec739ecfb35f98e19864ca services/software/poppler-24.08.0/Library/include/poppler/CharCodeToUnicode.h +d0df630d0c937cc9af2cf09882cde242a7a8097f services/software/poppler-24.08.0/Library/include/poppler/CharTypes.h +9ef876e9ea0d36ded0ce83aa3591735e2dc643a1 services/software/poppler-24.08.0/Library/include/poppler/CMap.h +25e5ad0f166abca1edee6ef1b7e380e59d31cebd services/software/poppler-24.08.0/Library/include/poppler/cpp +90fec01d31a40e5c675665fd7d9005d5a8b98fdb services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler_cpp_export.h +6b0f920c249940ab3a7a22e4812b77fb7f62327f services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-destination.h +97fd9a878558843bf7bd4fdbfea072b879c8ddf7 services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-document.h +f39bd745489f70929443776e966732e58d6bab25 services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-embedded-file.h +b6bc48c50f2d7590373060cdd828a8ea399702cd services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-font.h +ba9c6e0db12e9ce43532794555dc242a1e1b8b7b services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-font-private.h +248a759962a3f02dd9742b0759b9ae0db09bd1d9 services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-global.h +2b98916c1ce3f81f6e1cf2b7e47b484a82a747e9 services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-image.h +6041402c8337e948321a6dc315a823a1dbf5eeef services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-page.h +166e5cdfe581f5bc8f0ddd7536a658420d5c35c6 services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-page-renderer.h +68447508678a4ebd975d45f9158b05238d3852f4 services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-page-transition.h +5657ec9a341d531cde5713044b12881d17688aca services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-rectangle.h +1e528a6e70ed6701a182633e63fb637b26d48131 services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-toc.h +58875ab79300f8538df1a8cf1dfdf6b91c031fc0 services/software/poppler-24.08.0/Library/include/poppler/cpp/poppler-version.h +752b7005b493a56a827542106f0b3c5d1969afee services/software/poppler-24.08.0/Library/include/poppler/CurlCachedFile.h +f1106b3513ef8ef3ec78900ca28a74941de9772c services/software/poppler-24.08.0/Library/include/poppler/CurlPDFDocBuilder.h +200536a087c98ce043d1170ae0eaf8ffb5772885 services/software/poppler-24.08.0/Library/include/poppler/DateInfo.h +4f0c6d288c154369f59a208001a3bba7d1ce00ed services/software/poppler-24.08.0/Library/include/poppler/Decrypt.h +621b76a2096e2c283786d85d2314731c26943e73 services/software/poppler-24.08.0/Library/include/poppler/Dict.h +b292afcf7419c6988ccf8ec05fd92e6a68ce3cb7 services/software/poppler-24.08.0/Library/include/poppler/Error.h +34fd86ab2dca81bec951c371d875315a1a41c1f5 services/software/poppler-24.08.0/Library/include/poppler/ErrorCodes.h +42c0ff6b2549222cc124fa0a2a2f704e42bffd3e services/software/poppler-24.08.0/Library/include/poppler/FDPDFDocBuilder.h +6662ebcf8bd6e501d5e470905c9ac4ea1d17a0da services/software/poppler-24.08.0/Library/include/poppler/FILECacheLoader.h +1650b89e792702bfa6eda152edbea10ebe46546f services/software/poppler-24.08.0/Library/include/poppler/FileSpec.h +87d6909e1b64915f4d5974b6b110378bd08fba5c services/software/poppler-24.08.0/Library/include/poppler/fofi +ca62e948d286fa7d4fa47d18c8aa9c1d14918c11 services/software/poppler-24.08.0/Library/include/poppler/fofi/FoFiBase.h +5a154405a448b3e0b947319a901aabac9b1b6798 services/software/poppler-24.08.0/Library/include/poppler/fofi/FoFiEncodings.h +f37ee3961218473bbec4c0dfd1f4374197eda99d services/software/poppler-24.08.0/Library/include/poppler/fofi/FoFiIdentifier.h +4c464b9dae0285b9284b95191a7f90ce98ad697a services/software/poppler-24.08.0/Library/include/poppler/fofi/FoFiTrueType.h +b3cc91e8b708c1b87581c8446af82d3ff5e5358f services/software/poppler-24.08.0/Library/include/poppler/fofi/FoFiType1.h +f3a9b731cf7b80b7b3ed0fa2c6ed563410eb0428 services/software/poppler-24.08.0/Library/include/poppler/fofi/FoFiType1C.h +a417b324e48087cbb6264cbe366a2c6bb1817c69 services/software/poppler-24.08.0/Library/include/poppler/FontEncodingTables.h +ba37a742a0664dbc47cf1c2b758931a2dc64c4a1 services/software/poppler-24.08.0/Library/include/poppler/FontInfo.h +51dae7420288443f09cdce4033301d9f3b0dace4 services/software/poppler-24.08.0/Library/include/poppler/Form.h +965280257e6a3dd8af49d02d32b1253c99234548 services/software/poppler-24.08.0/Library/include/poppler/Function.h +fee97a7228e5b62d2f3e5a486fd04c7d204cd8f9 services/software/poppler-24.08.0/Library/include/poppler/Gfx.h +c4dde6cb5ba30e38970460aa8602e638152a83c2 services/software/poppler-24.08.0/Library/include/poppler/GfxFont.h +9cf1afc193da5cc14fcc2aaf0f074a4a63f1cd17 services/software/poppler-24.08.0/Library/include/poppler/GfxState.h +9572f035b3282b80843f44196527e4f36abc5740 services/software/poppler-24.08.0/Library/include/poppler/GfxState_helpers.h +e68d17fcb2e6fb4671d022d4068fb025df799c70 services/software/poppler-24.08.0/Library/include/poppler/glib +70f2172a3e749b131a6ee0d13f4f4b570abf4e51 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler.h +b4ea01e59d854f441dfb205c80318f6673cea127 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-action.h +509ecdff00821ecdd9bbdfb0430409e864faee3f services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-annot.h +664a566e858cce8e6aedc13a862bae526274ba19 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-attachment.h +26b8a3f5cd2d1450c33eac967cb81312ba0e6308 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-date.h +a793e08bd4ed316a52dcf054369e3bbdc05eeca6 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-document.h +2fce5ceabefd3305e155897ada066793c766798c services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-enums.h +4de3d57d5b81ebe104f21490101e1c8d13fab464 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-features.h +6cdf22405b80b7419d14c8a7fd5d0ba13db5ff91 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-form-field.h +12dfd9a44b630cdb7f06b1688fbe051a0daf25e6 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-layer.h +fc491512b8e3b6acf9e9b3ec37f6a4ea9d95c31c services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-macros.h +72094b389b7f9fe5a59af51b10a99e3f59fe82ce services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-media.h +abd69ba9db83a5cb9d976560aec7016274369314 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-movie.h +2d037d8e6efb47d4c10f1066ae9cbe3a33a82559 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-page.h +05cef08e3a4cb76b7aabe96dd635af2927969f86 services/software/poppler-24.08.0/Library/include/poppler/glib/poppler-structure-element.h +e8f3c53444ec070e27d9c7bdf073013739870535 services/software/poppler-24.08.0/Library/include/poppler/GlobalParams.h +8c4d3365259576a9ea82636356ff75d21a40a696 services/software/poppler-24.08.0/Library/include/poppler/goo +760687919cda357b1ce98859cae504700543dee7 services/software/poppler-24.08.0/Library/include/poppler/goo/gdir.h +516c2fc289061a77cc978cfa2efd82e35a3fda82 services/software/poppler-24.08.0/Library/include/poppler/goo/gfile.h +100c9b36db133a1af78a63bf0ee43b78c905b2f6 services/software/poppler-24.08.0/Library/include/poppler/goo/gmem.h +0cb743372eb7b4e42d8a9597ffd5f3891b9e2e00 services/software/poppler-24.08.0/Library/include/poppler/goo/GooCheckedOps.h +76128a71f958b2a07f887aaa6f19f3d503edbc4b services/software/poppler-24.08.0/Library/include/poppler/goo/GooLikely.h +ea62b67bb4c40b50894505add8a0d1b4e7ee1766 services/software/poppler-24.08.0/Library/include/poppler/goo/GooString.h +00b85618fe929662773d9f583602651a53a1fc34 services/software/poppler-24.08.0/Library/include/poppler/goo/GooTimer.h +2d535ee7670ce239db284a0bc2afe46bb676712b services/software/poppler-24.08.0/Library/include/poppler/goo/grandom.h +fbf1872fb213fa3e56a63c0f6ff1602fbf1d2749 services/software/poppler-24.08.0/Library/include/poppler/goo/gstrtod.h +860b310f7899e8145ca099cf6331c0a5dfbaa431 services/software/poppler-24.08.0/Library/include/poppler/goo/ImgWriter.h +4b94c51ecab70d4eb523255886f14b6f6a801dda services/software/poppler-24.08.0/Library/include/poppler/goo/JpegWriter.h +cd0ce4b8a83de769879111dba3b8f8bc8c2421d4 services/software/poppler-24.08.0/Library/include/poppler/goo/PNGWriter.h +3691a6e2d5a608c656fcab592a1018628fbba9a2 services/software/poppler-24.08.0/Library/include/poppler/goo/TiffWriter.h +5253a76a8dc95d3bdfec3cb43dccf4b4add33d43 services/software/poppler-24.08.0/Library/include/poppler/HashAlgorithm.h +5104ca0efc7b3559959f2814fa1505767ff7f815 services/software/poppler-24.08.0/Library/include/poppler/Hints.h +ae31a99578862991c90a16f2baa74a77b6332f2a services/software/poppler-24.08.0/Library/include/poppler/JArithmeticDecoder.h +af63a6733776a1d8afb9b6f6434b3e6979ac5f18 services/software/poppler-24.08.0/Library/include/poppler/JBIG2Stream.h +fbaac8fc3bfd6a2ae3a9f3cd922029fa23af9d31 services/software/poppler-24.08.0/Library/include/poppler/JPEG2000Stream.h +cfd3a0d4d4f78d98f992b62914e47cb92bb1e2a4 services/software/poppler-24.08.0/Library/include/poppler/JSInfo.h +a117dbe020ac55bd51e039ccd3983b9994e5fb7f services/software/poppler-24.08.0/Library/include/poppler/Lexer.h +b5b366bfc34b3d951cf9fc446a13f727fd2ba489 services/software/poppler-24.08.0/Library/include/poppler/Linearization.h +6337d79388707b4914bbb610f3cec121c752a3b7 services/software/poppler-24.08.0/Library/include/poppler/Link.h +0595d1e620e5a2a3722f6d8dd30024c705372aac services/software/poppler-24.08.0/Library/include/poppler/LocalPDFDocBuilder.h +b025b158214f9df0541f31a8592a3c6f6987a6e8 services/software/poppler-24.08.0/Library/include/poppler/MarkedContentOutputDev.h +0c36510eaa32bd4baa45791f5b8893b4608928ed services/software/poppler-24.08.0/Library/include/poppler/Movie.h +53b8972e11ef6e34bca60e447dc22ac313f5f5ec services/software/poppler-24.08.0/Library/include/poppler/NameToCharCode.h +b4c29c461e188732133f84c835b0671ada1ee087 services/software/poppler-24.08.0/Library/include/poppler/NameToUnicodeTable.h +e70a97498639f7e5b88415e8100e97ed05e19b80 services/software/poppler-24.08.0/Library/include/poppler/Object.h +22b9409ec2909ff2292eef67a4b1cc2972d9485d services/software/poppler-24.08.0/Library/include/poppler/OptionalContent.h +877eaac4fd149a878bcb428267bd20a806587a1b services/software/poppler-24.08.0/Library/include/poppler/Outline.h +35ab9bc0f1fe01b10c9ad36228f31f5b2245c042 services/software/poppler-24.08.0/Library/include/poppler/OutputDev.h +331c8b61de7e7ecd0ae887aa67aad8c9d0f0e6c1 services/software/poppler-24.08.0/Library/include/poppler/Page.h +b8d51a9e8db22f51be22c3c9eadd61feed04d182 services/software/poppler-24.08.0/Library/include/poppler/PageTransition.h +b379b67d34ad9b7a6567a45dcc78bf609e892820 services/software/poppler-24.08.0/Library/include/poppler/Parser.h +61aae6184f0871195808b19a7f7a56a356ee460a services/software/poppler-24.08.0/Library/include/poppler/PDFDoc.h +d0bd1ea61c8501788d58ecb8ef7202807d5736fa services/software/poppler-24.08.0/Library/include/poppler/PDFDocBuilder.h +278a910d21815d24876e02e1139cf13536ffcfef services/software/poppler-24.08.0/Library/include/poppler/PDFDocEncoding.h +e84aca46bd14c699843e4f21f53b14c915b61592 services/software/poppler-24.08.0/Library/include/poppler/PDFDocFactory.h +eef49cf8d3a1777ff878bc08751cc160341715be services/software/poppler-24.08.0/Library/include/poppler/poppler_private_export.h +68db15382fe68c03dc91f07561e3f8c89440b078 services/software/poppler-24.08.0/Library/include/poppler/PopplerCache.h +d52b48e4935fe516e138e9b748170c2cf6e78758 services/software/poppler-24.08.0/Library/include/poppler/poppler-config.h +9b3234a42b7f4518e68b5e05a10b3147b14b1693 services/software/poppler-24.08.0/Library/include/poppler/PreScanOutputDev.h +b13cff7ffe289a9909b69c00e62589c3383498d4 services/software/poppler-24.08.0/Library/include/poppler/ProfileData.h +9e64598ff5924a4994ecf0d471631613235b8dc5 services/software/poppler-24.08.0/Library/include/poppler/PSOutputDev.h +dab684bddbff93a16a5938a05b3de62f418bd8f5 services/software/poppler-24.08.0/Library/include/poppler/PSTokenizer.h +9721abf86e8e77fdfe6e926652439ff90036e0b2 services/software/poppler-24.08.0/Library/include/poppler/Rendition.h +de10f23d3200d348dfa4ee53ae60e76771c9e218 services/software/poppler-24.08.0/Library/include/poppler/SecurityHandler.h +8e5ad37f85ed2de5cb01c9137f9e86ff947132a8 services/software/poppler-24.08.0/Library/include/poppler/SignatureInfo.h +aa080bfd4bd7750f91b3f0169da71047ceaaf852 services/software/poppler-24.08.0/Library/include/poppler/Sound.h +ef221f6b717b450da5ccc9802708ff6746d956e3 services/software/poppler-24.08.0/Library/include/poppler/splash +e13be54c625f1e624a2c62fb33af6b3b0cd5935e services/software/poppler-24.08.0/Library/include/poppler/splash/Splash.h +2d7cf413525e4ced4f90d222915ee493030f6792 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashBitmap.h +0b7dd14943a506eddfd16224b0bca6f266076a16 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashClip.h +10efd6db72f5c615fd5540664a35b13ab83945bf services/software/poppler-24.08.0/Library/include/poppler/splash/SplashErrorCodes.h +8c54b08f24947749b31e545127410b329dbe66c8 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashFont.h +3e5458c09374658a65ce99a0e58dd6e3749ba2d3 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashFontEngine.h +7f55fdf01ad21c2376b7dc71d13db65cdd398d27 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashFontFile.h +c127dd87f1d4a011c3a311518693ec292dea7dd4 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashFontFileID.h +ae656b9cc523f1c8be8ad99a18f8f8654d1b5579 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashFTFont.h +607b2a6ac4e9e2807e3cfbe5b5cf994092e22d82 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashFTFontEngine.h +3e52dd85fab69b148d1c7c955b7a8663b2e7dcb3 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashFTFontFile.h +a091941206f0b62d0a59948c93cca8975e3b6eb4 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashGlyphBitmap.h +5c076563327565fb43ab2b11a5b45215ffdb275e services/software/poppler-24.08.0/Library/include/poppler/splash/SplashMath.h +815e48a73e802db957d50fd3abc9503a434cea56 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashPath.h +2a50aa8249ce2f17ac2efe96175a24c1a2a0ccd4 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashPattern.h +d912ef02e24564ddab97ec732fa3fe7d4c8942f9 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashScreen.h +009c1f14c4eb9ea2d9e74b2ed587aab0f4ff75d8 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashState.h +30a98cd0f34195ff026a4c1039e67c5458a7aaae services/software/poppler-24.08.0/Library/include/poppler/splash/SplashTypes.h +e59649fa0abb11769633eebab056fec8431471dc services/software/poppler-24.08.0/Library/include/poppler/splash/SplashXPath.h +476e98c92a3513d0bb8c8c720e67718f494aad93 services/software/poppler-24.08.0/Library/include/poppler/splash/SplashXPathScanner.h +88b13b4238fabf53e1351863852c1d85d0fe8398 services/software/poppler-24.08.0/Library/include/poppler/SplashOutputDev.h +b1b8b492b5c8ccc8b8a001eaa8d9ea42b9feb7a0 services/software/poppler-24.08.0/Library/include/poppler/Stream.h +3029ed09edffb7699efd08507d25363397558b4f services/software/poppler-24.08.0/Library/include/poppler/Stream-CCITT.h +fbc0781fc76f0bcd79252146564c687236ed9481 services/software/poppler-24.08.0/Library/include/poppler/StructElement.h +8812a504bdae540dd69e4f82e0cd6f8d1d09d2f5 services/software/poppler-24.08.0/Library/include/poppler/StructTreeRoot.h +d598142176b5e6df5464165c51bdd52384546147 services/software/poppler-24.08.0/Library/include/poppler/TextOutputDev.h +88d119bce559aab97c578da93bd0b282ee4f117e services/software/poppler-24.08.0/Library/include/poppler/UnicodeCClassTables.h +f74ffcd00b86fbf570897f634ea38baae0a98bc6 services/software/poppler-24.08.0/Library/include/poppler/UnicodeCompTables.h +8cb793c0b95c58d3847a289e149a15c7c3fb8828 services/software/poppler-24.08.0/Library/include/poppler/UnicodeDecompTables.h +0d80c0254760a518f40f03de8afecc5d52ac9c49 services/software/poppler-24.08.0/Library/include/poppler/UnicodeMap.h +bace0a62da1e0556a82089bb7cd0e20ec12bb0b1 services/software/poppler-24.08.0/Library/include/poppler/UnicodeMapFuncs.h +7c89feb285716d8de73b7d35d357e3e29bec7f18 services/software/poppler-24.08.0/Library/include/poppler/UnicodeMapTables.h +85d88d62bc431050269851f43645c7e3dd0d23e5 services/software/poppler-24.08.0/Library/include/poppler/UnicodeTypeTable.h +bd57188df2bd804751272f580b4123cc12f69f07 services/software/poppler-24.08.0/Library/include/poppler/UTF.h +24a814ca2a4cfed1677ea9958367c1330d09456c services/software/poppler-24.08.0/Library/include/poppler/ViewerPreferences.h +739b87bb0ab6798e2710e4b02cbfbe70dcb899c9 services/software/poppler-24.08.0/Library/include/poppler/XRef.h +e577541dda324eaf74fd622e6c7e8f8850287b9e services/software/poppler-24.08.0/Library/lib +23c11bca60a554a2a2c2fa64ab5559fd43f5e056 services/software/poppler-24.08.0/Library/lib/pkgconfig +d2039943f70f89d2dd95b84b6cce5980aafa9d6b services/software/poppler-24.08.0/Library/lib/pkgconfig/poppler.pc +ad81a431c245429a867a68d6c6f70091abc59e64 services/software/poppler-24.08.0/Library/lib/pkgconfig/poppler-cpp.pc +6e21bd230539a7a09ca257fcd1206ad4b8fffc7a services/software/poppler-24.08.0/Library/lib/pkgconfig/poppler-glib.pc +fc89ac109fde63c5e14256068ad555267b75a7ba services/software/poppler-24.08.0/Library/lib/poppler.lib +c3af3051970dde6afe4fd42e5e1b972e13801bfa services/software/poppler-24.08.0/Library/lib/poppler-cpp.lib +fc2de108fcc7508c542e2b5c1d352438a4c0c879 services/software/poppler-24.08.0/Library/lib/poppler-glib.lib +6e55d667109010187de08f196378ab9702127c9b services/software/poppler-24.08.0/Library/share +4ddce75f708030dd1a0901fe5f8123e33afb5f61 services/software/poppler-24.08.0/Library/share/man +f7702066f299e1af809744b0ca38c8fd1e97cfe7 services/software/poppler-24.08.0/Library/share/man/man1 +c9589a783eb9b33bf65bc218a8625b846991b4d3 services/software/poppler-24.08.0/Library/share/man/man1/pdfattach.1 +0b8975dc620cbcb10bfdacc1dd33753f0145a5b8 services/software/poppler-24.08.0/Library/share/man/man1/pdfdetach.1 +1ec0db2722aa8bad093396c12148f8e4b2ce328e services/software/poppler-24.08.0/Library/share/man/man1/pdffonts.1 +1a5386a032d9173193ae60e750ca07f5df238e83 services/software/poppler-24.08.0/Library/share/man/man1/pdfimages.1 +2a17bbd50524eea38fdf68d77dfb0d3ae3231201 services/software/poppler-24.08.0/Library/share/man/man1/pdfinfo.1 +132511a12c87ad5c071dca31002c5db4bd8f15d2 services/software/poppler-24.08.0/Library/share/man/man1/pdfseparate.1 +782f81fdaa694e48ce36178c6572bd7eff324da1 services/software/poppler-24.08.0/Library/share/man/man1/pdftocairo.1 +e4e9da5c5b6dccd0ab55e4c78913150d83591311 services/software/poppler-24.08.0/Library/share/man/man1/pdftohtml.1 +ddbe4d70172cf8bb030965612dc8e4c7b2388da9 services/software/poppler-24.08.0/Library/share/man/man1/pdftoppm.1 +0ab17cbbae5c0a138ad5b63830b248bd4a25b83c services/software/poppler-24.08.0/Library/share/man/man1/pdftops.1 +c34c98a907f8f915e6decf09ca7fd6811f7728c7 services/software/poppler-24.08.0/Library/share/man/man1/pdftotext.1 +4a1b4ea89bc114bb4b6f0f69d4d47b553389ee71 services/software/poppler-24.08.0/Library/share/man/man1/pdfunite.1 +5610ba299033167f7a2908aa7f3eee49669ff16b services/software/poppler-24.08.0/share +f61637285918a71f84572dce0ff0dd2aab3c6d78 services/software/poppler-24.08.0/share/poppler +5fd8c09075d21693dcf9c029b345726e9a9e59f8 services/software/poppler-24.08.0/share/poppler/cidToUnicode +6969f321f9c598a5163355505a4ca3ee0a670a88 services/software/poppler-24.08.0/share/poppler/cidToUnicode/Adobe-CNS1 +5fec270461acf17e1ba67a1a0a8b36dedb21d957 services/software/poppler-24.08.0/share/poppler/cidToUnicode/Adobe-GB1 +0d729403ec3e19ccb23f8efaeeddd7a3f9f074fa services/software/poppler-24.08.0/share/poppler/cidToUnicode/Adobe-Japan1 +b0697040582c22b059193f6b07b12194926cbc35 services/software/poppler-24.08.0/share/poppler/cidToUnicode/Adobe-Korea1 +e1d64b1977e0f3cd086331d74d57451da5bc17c1 services/software/poppler-24.08.0/share/poppler/CMakeLists.txt +bc37d20bcfa2b49cce76bbbb60a7f07fd2c9ced0 services/software/poppler-24.08.0/share/poppler/cMap +be4f1991223c7fd1ff159e9faa3f51ad0c230388 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1 +9a037f85b8df021b333eb0501fe695e2e924ecbd services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-0 +24c193aac7aa0bc5aac12ebf2379e1e64e98f66c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-1 +544b73fc79d6db0fad73cfb392e0c4338bf4619c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-2 +f380656311673f79f95bf96aab5114e7f2258c39 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-3 +d9f2f65d14ef703aeca66fcc36c0802f0ca80cb2 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-4 +7aa30aabbbfcca044c4c0b671eca3d7b9f3ed616 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-5 +7529a97aacacd0c76ab0c3f429f8c794da29b585 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-6 +17cec369e448e234a11206c29aff265e7c76d8e4 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-7 +4cde2fb486f95ac49670aee849eb67d2b1aed78a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-B5pc +2ab5ffeb09d89c94e3dfb60428078a528f349523 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-ETen-B5 +4332835c658cc195f1264e7e9ed2d811b2df20c6 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-H-CID +2646dcce3a7af04e13fbf8d974eaa0d7b318cc48 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-H-Host +9cf7735d587195f3398890454795e63716f5f9e3 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-H-Mac +d8265ce72bad27dadbd8b3617b21f5577e766b8e services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/Adobe-CNS1-UCS2 +08f05cc372f1372b90ad9a43cca1a686bb975afd services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/B5-H +277ede77969762723ba531c698d5447724387a4f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/B5pc-H +08cca172468bb867962e490f0454e45737b296f2 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/B5pc-UCS2 +181ef364a082fb81583998b7aa2dc8b58f003b1c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/B5pc-UCS2C +70f89e7ab425e12f33b39f4ff089cef8731d0281 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/B5pc-V +2b0482d0387d5f6ec69a7922e40c31b63885acba services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/B5-V +eefb687598b2783ce9be1dd4c9b26cc0d591c2ee services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/CNS1-H +fec58cd1e36e85082594a1fbcbdfd3e1331180cc services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/CNS1-V +832b710a7bb75d25e2150b64b9d93b9d0b22aadc services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/CNS2-H +ee519fab4b293e19f013251e57b51a892c668de3 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/CNS2-V +8e8936bf14a4d485a72019d39379fff6d40611f7 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/CNS-EUC-H +62c458029881a185249af114c2c0a74e00a2e9a1 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/CNS-EUC-V +a25ea5ccbc2cf3ddf9dd0039a1cde5d6ffc2c747 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/ETen-B5-H +d71b62ad580d772ca9df1285d68ab729bd6339eb services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/ETen-B5-UCS2 +736fb4a403b94b9e6ce25f0a12675848c8dd5481 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/ETen-B5-V +6a3395011aaef3e921ab44c1e535223ea6679734 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/ETenms-B5-H +4a5c611fed53ddd6880f19b641233d89572f1c76 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/ETenms-B5-V +974945adf77484b3121687352d972fcbb6c54983 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/ETHK-B5-H +57d776389096381999a607dcceddb3c5e665710a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/ETHK-B5-V +199f52e58ebedf5da4c585994d89f13c72041721 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKdla-B5-H +cf1e5501d88934b7229736554cfd2bab70ee8d96 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKdla-B5-V +1721d6ea0bc07c0a4e1f5bf7615d82934d7a90cc services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKdlb-B5-H +a6960b22df4115caef5126be85d209d2ed21540d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKdlb-B5-V +d92536a2c1bf3f4b65f935524393e3378a912817 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKgccs-B5-H +298cb275c68458ee93ea969251553e1daca28b34 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKgccs-B5-V +cfc47917b53f57044460b4639c48543281d1919f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKm314-B5-H +0f47a62e9400732840d5f40c51068c10bd6c7f0a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKm314-B5-V +543de49adcb83b8585fc7ec8a98ca80d0eaecbb1 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKm471-B5-H +8782ca6b4ccbfd7a9e9ee23b21a5b4b186e72ee3 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKm471-B5-V +ea6e1c881ba1bb465b2b1d81bccefde9b602c977 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKscs-B5-H +da4f9bfe122fe49ab04878addf03f0ce95e57015 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/HKscs-B5-V +4a01a36646a60c894258c6117ea5828c91292aef services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UCS2-B5pc +783b1d8a85520c7a77caecfeebffea24e791bd1f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UCS2-ETen-B5 +73ca664a26ba7835d0c06a1ae13f1c8b5ed16812 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UniCNS-UCS2-H +9927ba9fb7cb7bcc46ade671f95a845ac39156d9 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UniCNS-UCS2-V +76c15677f9fc536e83d4263a3fb26b785db9eecf services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UniCNS-UTF16-H +37e13a5a9605070f98291b396806d04c6ddcfd09 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UniCNS-UTF16-V +beee8bb2efd85b85fb5457c1f048732bdde7d0a2 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UniCNS-UTF32-H +123ec46ca25b8649658b17cec29fab62cda29a8f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UniCNS-UTF32-V +1b5fb46b21b49d1d5b143a4abca2afa7c5c62ad3 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UniCNS-UTF8-H +ba1840bdb24e959384853adce5fba014ca4e308b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-CNS1/UniCNS-UTF8-V +662fbcb0b89dea7969aab1414b1ccbab47b4373d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1 +c96113ad786567fb9cf4e18bcf0d5b85b53b97ad services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-0 +8cde432ee3a6cffbe4f0125ad6662098bbb9e929 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-1 +ee205248148aa4dc85e6b7c2231bcd7e9b7afb7b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-2 +96fd45a6e3c3ae360804a2af46fed374ccf76b4a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-3 +ecb9212730c6e252bcd79f2b7185bc8d668a8adf services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-4 +8a9ee3ee1035dad2fcbd89863ed4fe9eeb5fec07 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-5 +a121ca7d9980eee4c0a41a57848fd601ec876b2a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-GBK-EUC +4e2af82f23b3013a1a800bac3e49da06c0dc4efa services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-GBpc-EUC +627822a07eebb2c5cd4562c50bd1501e3a1eee69 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-H-CID +a6b36a877afdd0e39b9db90394234ca1a31ab579 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-H-Host +6d2eb49c68499d01a25c52d8b9fbf0db3b700c5d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-H-Mac +72d9a1fe4d616b6c7c72acdc46b45fbed0731077 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/Adobe-GB1-UCS2 +f28d6f1135ea9294e02dc0d5ecb09205867d61d9 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GB-EUC-H +d6c9ba76d827a5d9ee58a47730d1fcb3d9471d5c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GB-EUC-V +0c84cff673a589d8e56c3edd4319aab6d088cc3e services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GB-H +fe15bc780a68c465bb2112e53edd5ddb83c8ff0a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBK2K-H +5ba0359d1360b984f9433d22a09b18e70d10202f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBK2K-V +ddb94e9f0457fe5560711a218556516103a56129 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBK-EUC-H +c5d17dd5a83de47eadcbab334e4523e8a28ecba7 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBK-EUC-UCS2 +7e5b586fb2eca868dce6dbfa2ce8bc1599f61792 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBK-EUC-V +15d15a49ded29b5995738a22d768bbf4af82798c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBKp-EUC-H +9bcb51d848506c2ea49fd1679964ee68d43c79bf services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBKp-EUC-V +84f0e64a7a566183828e8fb6e7479fef10c9ea75 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBpc-EUC-H +34f77f542b01de92b8a5272e357931adfb77324d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBpc-EUC-UCS2 +5a04809e0a3825427e69433d04fffe2c7a9d9075 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBpc-EUC-UCS2C +851888210989436ace1415082fcd484cb1cfda25 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBpc-EUC-V +e82b1ef0b5b4eab71f6f23e2f1cc5986b85da87d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBT-EUC-H +0b8c4b0bced6e9887d10387fb8ae3805e84a9f88 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBT-EUC-V +9aa834eb0623a38e3fac7288ca25d134d7fe463c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBT-H +a5be785960f371ead7dddb79dc6fe4176370cf37 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBTpc-EUC-H +bcc5f4713a914977860c668e9e6d7953992d9d8a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBTpc-EUC-V +c0bab3d590df40b841862dcc2eb84859610c3070 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GBT-V +c88725325f411b6caa8a09ccbef1d1ad5c6a93ec services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/GB-V +c5cc04933babdcc4c5b24f762b299f6385762916 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UCS2-GBK-EUC +7477d559160761f56c78f9b69ba17d6c1911590b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UCS2-GBpc-EUC +c7b40cda0527ed5d990bacceabc13164bf999fa2 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UniGB-UCS2-H +e0f0fb56ed168c035169be8e72fdcc361ef9186d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UniGB-UCS2-V +9575b1d7f276eb5e6af16878be82a575e8a61cf7 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UniGB-UTF16-H +0f302482564c3e90d9ed8d7959ae3273c2354fbc services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UniGB-UTF16-V +765869daab2df9015f4861d832c900d2de00d51e services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UniGB-UTF32-H +664a362ecd705e2e1ac506bb94eb6780358f1bd9 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UniGB-UTF32-V +8d2af6ba95c707c1d038ed6e68e9c46fbe49c685 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UniGB-UTF8-H +1c100efdeee5464beebcf24c1c1a7d2f249e8a90 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-GB1/UniGB-UTF8-V +b921f4c145e3d7613c18fbbb11d71ccba0da6c9f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1 +d30c5e8832eeb027cbc5715a0eedea6fe230b24a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/78-EUC-H +69fe9c26eb688d4651e5d5d939f0ca38d4072e28 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/78-EUC-V +1c7cc2d10bd847a2806a16677d46f741278ea843 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/78-H +ca78cae23fd2f0e7e33bf5e4b28f3b289b126683 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/78ms-RKSJ-H +03685c696791e40af7e369dea45fad938c035a79 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/78ms-RKSJ-V +d77d6308b1a3e4b3f65775dcf9f3274ad4b3df96 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/78-RKSJ-H +e68ca260312bd53965c407baf39b37a11b1ed49e services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/78-RKSJ-V +465b79f995a725aedceb1e606104f8badf312e05 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/78-V +d80b465fa79480caa1e9606fb89716fbc370d1ed services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/83pv-RKSJ-H +158f3f661cc7d0529d21adfbe92bcaaee5f8f756 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90msp-RKSJ-H +7081845f4fc2c965debd8906a557a6d772b5c87a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90msp-RKSJ-V +89c83394e93d6568ba031f349b46fd883e76f755 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90ms-RKSJ-H +726c4bfb3ac40e6f3d8ec32b428ac4eabec64d4d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90ms-RKSJ-UCS2 +eeb6a28a93d970d0d74c7000cc185a117aaaddf0 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90ms-RKSJ-V +0b68fba1392f9b6e5cff078f1642d29bc6a496e7 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90pv-RKSJ-H +dc16eb5f301f15220d73caaa204fe51b02ca3db6 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90pv-RKSJ-UCS2 +37759d6a9f0b804ace85840bcef26c419b2c0661 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90pv-RKSJ-UCS2C +32b993422ad421f7b22aaed08f19ccc22d2a3e98 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/90pv-RKSJ-V +a5889e51bebbc7188cc531c86fa1958e4ba73b0e services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Add-H +ff0b793bdb63feb6d09e01233cdd87b39f1660c0 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Add-RKSJ-H +db50cbcbf098a2e4603190d51f41fbc1c69f1008 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Add-RKSJ-V +053dbff78d0793e80e8dfda5d52a76b03c13b97e services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Add-V +7e172144da548b3dc9c706f9cd44c69f8c51f741 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-0 +f61f714cce4cd01615f95e67a7f4173fac2b2fb2 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-1 +d7767f65fcfd31c6f2a3551cf3b8942ef2d9ab72 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-2 +a5507b65ad1ed355e7c44f41f132b5d27844439c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-3 +f6a4cf813712748a7351bea4919222d300f5b2a6 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-4 +e7991319e3b7e7e34bdcd6d554d9501c23f758c4 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-5 +38e95eae7a7b595197357a17309bd96b0232deb9 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-6 +6f195ced13be18738b7dd7ef33d66fd6fab48d23 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-7 +9ac8341110e5b4a437fae3c57033caada449e740 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-90ms-RKSJ +7b7c6987eb2df73cdde7b5f3406df539764344c4 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-90pv-RKSJ +ea30bbc9b2529db1a406e21ede465d32008c1aa0 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-H-CID +833b3a817bd6db31eb4ec6ae719a765dbf2eb358 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-H-Host +46b64ee42a55a81e643131fa19837a6fb7094e02 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-H-Mac +c29524847c4d12dc59b5c6542098fe985cfb294f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-PS-H +c24698b4a8300ec49a583828395ffc9498e42527 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-PS-V +599d35a819e162aad1eb97ddff52aa35ec6fa517 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Adobe-Japan1-UCS2 +1167675bd41d5fa35bc35dbd02b7483070220b29 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/EUC-H +b3796b7443f306b81c0b857b6d9d472f3f1faa84 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/EUC-V +a67d3409ce7ec59d34ee7bd5aff3e703af5dce84 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Ext-H +fd6be155157daf82d09189b376fcca7b8facfeca services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Ext-RKSJ-H +06f2ce07c5ac084b25786fa7d8a4514c1f1e15b5 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Ext-RKSJ-V +dfe6d14face1eb9ad49b05f07403d8c60611eca1 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Ext-V +f8efc4ed68400d9de0ab017c977b9ff15597fdf1 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/H +24cfcca3ff60c00add8b12a0d1cf47d03bc0deb9 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Hankaku +f4983034846b44c8e6df204857ff37697a05dc64 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Hiragana +4d33c8dec14ff765d6a83147c596c1b2f672d604 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Hojo-EUC-H +223e544d2706c5d95751c55b1afe5420ca8d25ed services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Hojo-EUC-V +35490e0858b9a4f826d80ecab5b00a494cff8bab services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Hojo-H +0e3414499068f964bbc9f4e94040a30aa89b46dd services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Hojo-V +7dbaffb7d3293c534070fbcb31794f10bdf74eb1 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Katakana +4b8f7eb7d9b1765b18323be8c7aa1c7173b1f7cf services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/NWP-H +f44a34082bcf05655b4f4489a3a18b3089973c2c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/NWP-V +46fd6237fd77d10bdf6925654253e4ab3e4b3950 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/RKSJ-H +7740b49416eb6b590a275fd67a3b80a7cfc22a60 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/RKSJ-V +74eb81051b0a6af02c0585dcb2ddbf2b3f5fd234 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/Roman +b51c943b20a3af3db5375dadae1e115806c4d73d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UCS2-90ms-RKSJ +8e7da02a8b0f0c7f9a79d8eb8a96bb5ab5d0fc24 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UCS2-90pv-RKSJ +ca77057fb2e740885acd60c0b5176f3942e53aa4 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniHojo-UCS2-H +b82548d55002987bcf24feccc47f9b6865f1195d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniHojo-UCS2-V +87ff21bc045019fae7baec05378cb9e23f8902d8 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniHojo-UTF16-H +ba7d520d5165d0c1f834f603af9ae507ad0681cc services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniHojo-UTF16-V +9685b63258a6931a68bdb9931126f65c908401e8 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniHojo-UTF32-H +1b9959ec5afc61bcab07b5ba51b9f68bf6981ce7 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniHojo-UTF32-V +e92a0fc7ec3005993bd15260beae80c33c250f91 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniHojo-UTF8-H +1d31b182e6cd26afaaf1c4d14d6de945e5b5ac06 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniHojo-UTF8-V +296c2ab8d609a9a9b9025277c350f4763533734d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS2004-UTF16-H +441af72004ffaa37064c77ce254113a8f9bc4c2a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS2004-UTF16-V +723328206a8d9a875c39c24ace32bcc649b38ea0 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS2004-UTF32-H +ca945368992d110ed7d8637fd26ae3a4e3f5bcd0 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS2004-UTF32-V +0169f03647f0a81ec6e7cb44c971665d90f97158 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS2004-UTF8-H +c4f75c08a05edf94ceb73d917714ed29d61a1f93 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS2004-UTF8-V +bb4b1208814e9829481d1b33b1b179c80ee3c5d1 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJISPro-UCS2-HW-V +59d2d3d2fa01c0227b80989190490762a42bfe15 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJISPro-UCS2-V +654601bcfd62c5c007dbb386b75708cbcb211a06 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJISPro-UTF8-V +bf5331822801a655b922e0efaf786e1250b4216d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UCS2-H +ab516ed8a851126f4332608f19327bdc418fd8b8 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UCS2-HW-H +311d584a1c207bd63e0967a8068590f98b72e896 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UCS2-HW-V +7ade3d475e827114ca79d12640ada7bb48693a19 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UCS2-V +11b725a80d6bf0aef98378558d83bd74df30dd4c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UTF16-H +f18f11e82efd487e3115f92eb70da35da947d256 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UTF16-V +bdf61a04a29c82dec4c5e0945758ddbe0686dfa9 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UTF32-H +e9a3b9eed686719fd116ec626f1908c613484948 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UTF32-V +82ed8d1e664a2a3d974630533d206381e94f91f3 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UTF8-H +5e673f2303834f1b4e20891ecaff9c1fedc5b33b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJIS-UTF8-V +069d6991ea4171349d79f701a04c6e761304a79c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJISX02132004-UTF32-H +bf6f0a7caa8349372255eb9dbe7765a883d62dde services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJISX02132004-UTF32-V +ebe76f629d11bb0dcc0f0a6463d0d2e0cff6f611 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJISX0213-UTF32-H +a7b8d41a6a379f6ac528afc80d833642bc690376 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/UniJISX0213-UTF32-V +e508e19ecf70faf17b5da0bfeec5b49b6dd38cbf services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/V +a450c2ad0ee4ee935b6f11b7c5d3703094629d76 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan1/WP-Symbol +047dbf61188afa0073e4263c744379b9b89a0cb7 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan2 +b4abbe49ec37b2d446993a1be95671cbf2f7cf0b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Japan2/Adobe-Japan2-0 +ea9959b2f1d007b9a751e4c1cb21df8c01bb1307 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1 +903ef2fe13e5480fad45828130e08146b06b7025 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-0 +e6f3bba58f85de84ad05af9a64f3b598452f7d2f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-1 +26c8ff78e06ac23862fb841becef6d60c462a2b6 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-2 +e3a4ff547e5f3dd9b3fde4d120f12ed5fe18a77c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-H-CID +5aa6e313b5305237c191ef2907f784bc58f939ea services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-H-Host +d3ba9dee0bc90ff378fb1defb83db5657f688602 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-H-Mac +ab8c4f52bfa2fce31492c1caaedbcb8794e3e165 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-KSCms-UHC +8665a742a0b77729e16001815c578d1b0ebd13d5 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-KSCpc-EUC +4c0c00dbc80d49e0e5b69c960158a7fe5cf6dc6c services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/Adobe-Korea1-UCS2 +1b877a902a8d40c683c730102258a70ca548247d services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSC-EUC-H +46b28ed5d57068c733839c4a61fd07d835f0017f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSC-EUC-V +d7c42cddc29b8888d7e9e95685bc3b4aebd3b786 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSC-H +a08cc92b2288dbb715ae1d4da7253e099194b389 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSC-Johab-H +6245a72b819abfd1da1f2040fca1c17e93770e08 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSC-Johab-V +84dbbdc3cb433d9fb8ab0169c8bc8b08c05c49fe services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCms-UHC-H +6e89d5bd3672ec0104a14f98a653142e4decce07 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCms-UHC-HW-H +32f182f71dd824b9b00b93910ae7f4d536408cfb services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCms-UHC-HW-V +6d2297a4540c8a7f90c1509da6d8860b10d1730f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCms-UHC-UCS2 +8939350e036f64f861a50283c8db4afaedba6003 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCms-UHC-V +a5aae5a37a3359954e09d1effee1e9ccafd7d96b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCpc-EUC-H +fca17f924ab4f20d6763db19a3727d70aaec8ec0 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCpc-EUC-UCS2 +5ea87725ac0c6b73038090cbea26ca53ba3b17bd services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCpc-EUC-UCS2C +c9615a341e09bf193af8307f9cbbba2008d07972 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSCpc-EUC-V +b0ee2ba209d7123bed8ae9af68a4ff46257f90d0 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/KSC-V +dc16001b7f80a46ad96ffb0a07c33b9156dcb71b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UCS2-KSCms-UHC +ddd27455320ff8643d3c0e0d7805aa6211cf24cb services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UCS2-KSCpc-EUC +a7f64bd7c8e01039795a8d7eac11d90ad8500cf7 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UniKS-UCS2-H +4ecc9df8bec428f27eab46a7f0aa3a3b4101ff14 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UniKS-UCS2-V +61cab822075091ad36ed7abc975416bc8c408d3f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UniKS-UTF16-H +049fd21f02ab5eb253a3d3e594729eb4f396ebac services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UniKS-UTF16-V +4f6c419826124b8b950cb39304e0a56cebc7a1b0 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UniKS-UTF32-H +fe2fd2c28bce5892ce18330372be678f3588368e services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UniKS-UTF32-V +148162cdc5ae02edf172f5b25e744f507f0bbd48 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UniKS-UTF8-H +e06985999662b52e67b48601581e671b4c447153 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-Korea1/UniKS-UTF8-V +d8f79e67690a4ed8956dc1c57735d3a406685a0b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR +e87bc485e0587addee08b1ced23f5fc5465110a5 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-0 +210a09224ed51f9c172aaaf6614173b16190f79b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-1 +6d6ee62aed11e7bc607871b9f7b72434c576a831 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-2 +75503388388d9f4f48c2a475b98555ffffc0335b services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-3 +b16a34168049afe7b86f416c8ca826f77b790cf4 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-4 +abd3b546f7e815e0431eaeb7bca6f2c793cb0d38 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-5 +cde3707f562c88bfc3f4b6e07b1afa121fec5a71 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-6 +654c5443c861e1f9c9fa0966d6beedb993df8d1a services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-7 +8c80219e66deb00a3ccb445b99f59cfe40e19392 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-8 +7f1f9a499a737b32f21152c20205032093328739 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-9 +05698686f0ec900ffa67c89349548dca0dc63fa5 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/Adobe-KR-UCS2 +7f0904446ce2b16855e08f8bfe5752470923550e services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/UniAKR-UTF16-H +82b117b4f1846a88dc2cbb0364b8f5f643a53d4f services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/UniAKR-UTF32-H +0853d1182d2302b1b8a1f890ecff0a716de9df09 services/software/poppler-24.08.0/share/poppler/cMap/Adobe-KR/UniAKR-UTF8-H +5e53f88182fd288d28f43ba352d388587780e591 services/software/poppler-24.08.0/share/poppler/COPYING +d048f58bad011747136f76c9d8efb4e2492a9648 services/software/poppler-24.08.0/share/poppler/COPYING.adobe +d511905c1647a1e311e8b20d5930a37a9c2531cd services/software/poppler-24.08.0/share/poppler/COPYING.gpl2 +a8a0b6c93a80038473c72a2ee165e23c35739842 services/software/poppler-24.08.0/share/poppler/Makefile +b68e032fd83fa2eda948fb2f97d663e33f3ac3fc services/software/poppler-24.08.0/share/poppler/nameToUnicode +1f2229b2a90a2934a722a921acd056fff54ff770 services/software/poppler-24.08.0/share/poppler/nameToUnicode/Bulgarian +351d111ee5119f2c47e0782b0a3d48151cfd905b services/software/poppler-24.08.0/share/poppler/nameToUnicode/Greek +8fdc894b7ad86439d7b42968ed3a9811ea5613d1 services/software/poppler-24.08.0/share/poppler/nameToUnicode/Thai +d76795253ad4ddff800cb1c1792895e4a4f7b79e services/software/poppler-24.08.0/share/poppler/poppler-data.pc +b9741162db507c1b617d0bac0426e5610feb023b services/software/poppler-24.08.0/share/poppler/poppler-data.pc.in +787f6d7593170c2b629485b1d51f84126ccd2d02 services/software/poppler-24.08.0/share/poppler/README +716e5f0fadff577f91955484b46cca6d4791e762 services/software/poppler-24.08.0/share/poppler/unicodeMap +ec1dbc02a336defe017d881fe4d72c238a2b5493 services/software/poppler-24.08.0/share/poppler/unicodeMap/Big5 +cbcd04488ff33ba575ba90d8188a19e248b6ea98 services/software/poppler-24.08.0/share/poppler/unicodeMap/Big5ascii +7cc16e654cc03d73a7132df668a924361a18abf4 services/software/poppler-24.08.0/share/poppler/unicodeMap/EUC-CN +4ed2544bcca799f5c12bfe2088e5579ded6f1dda services/software/poppler-24.08.0/share/poppler/unicodeMap/EUC-JP +1d2a95fd36da219f91482dcc0d485557c41a102d services/software/poppler-24.08.0/share/poppler/unicodeMap/GBK +c41eb28a83907d1bba287c1c70a909e4e2c70d08 services/software/poppler-24.08.0/share/poppler/unicodeMap/ISO-2022-CN +1c6af6a400bfade812f5c33d95d40cc37365f4ef services/software/poppler-24.08.0/share/poppler/unicodeMap/ISO-2022-JP +7e37b4909260a96b5461e745cee1524c872bc7d4 services/software/poppler-24.08.0/share/poppler/unicodeMap/ISO-2022-KR +25bee9eb08e43af72fb20a1930ab45267426aefa services/software/poppler-24.08.0/share/poppler/unicodeMap/ISO-8859-6 +3a4768911667adbe157a0e2196f554956c1b140c services/software/poppler-24.08.0/share/poppler/unicodeMap/ISO-8859-7 +970a7cdf0aaacec2fc4ff0fbb76beaf35fea45a5 services/software/poppler-24.08.0/share/poppler/unicodeMap/ISO-8859-8 +6326ca669d36251f85cf80237cd240916eae298e services/software/poppler-24.08.0/share/poppler/unicodeMap/ISO-8859-9 +8869ede78ba20cbb8f820b583643177bd92202d5 services/software/poppler-24.08.0/share/poppler/unicodeMap/KOI8-R +993931e680ccd3f56b2505bd7966eea412e4eec7 services/software/poppler-24.08.0/share/poppler/unicodeMap/Latin2 +a55e584143533c881b3d7a932cb051319af87550 services/software/poppler-24.08.0/share/poppler/unicodeMap/Shift-JIS +b336e8782e4c6cc473f85c13f374019e2df6d016 services/software/poppler-24.08.0/share/poppler/unicodeMap/TIS-620 +f792be75b5fd724821506ea28676823947d4b80c services/software/poppler-24.08.0/share/poppler/unicodeMap/Windows-1255 +67b1b7ab5306bf1d14effe8d4cf7403b11262237 services/software/Tesseract-OCR +bc5cee639b404416e56f0659ab2e8b2fb67cdfa0 services/software/Tesseract-OCR/ambiguous_words.1.html +82becf9ec64ae44cf2045a27f2306965c1dd4d83 services/software/Tesseract-OCR/ambiguous_words.exe +7458133be8d759f7f5545b21bf91fe6d2fe134bd services/software/Tesseract-OCR/classifier_tester.1.html +65024a4f4f87f0c9d643f52e2654fec7b527b26f services/software/Tesseract-OCR/classifier_tester.exe +cd8d0ea404ff2c43b5731233a39b1960897227e6 services/software/Tesseract-OCR/cntraining.1.html +1ecc72ad141765ceb411184cc1370f62aba222ba services/software/Tesseract-OCR/cntraining.exe +0c1d58261ee6fd4fdec9f99f32122e861223753f services/software/Tesseract-OCR/combine_lang_model.1.html +16bb44dc152e05e93a379b0e3c1cbd519f331990 services/software/Tesseract-OCR/combine_lang_model.exe +e689c17e05681abefe26be2b9a281ad49b7fab13 services/software/Tesseract-OCR/combine_tessdata.1.html +7cfb65471a7c5d05bdb3fc99c8abf9865d460720 services/software/Tesseract-OCR/combine_tessdata.exe +4ae7b9283b1d2861d62515056bf8d21a0b6cfea2 services/software/Tesseract-OCR/dawg2wordlist.1.html +432f9763da44cc1a9e8a5f82ca28e207dcb4e8f7 services/software/Tesseract-OCR/dawg2wordlist.exe +3977bf96bea32e26844b9572d2964d74869bf633 services/software/Tesseract-OCR/doc +9d1e73c3083260ae9485e7d07f6ac1fa271737fb services/software/Tesseract-OCR/doc/AUTHORS +d645695673349e3947e8e5ae42332d0ac3164cd7 services/software/Tesseract-OCR/doc/LICENSE +99da6d275def3332f577e1554c0dca98c7ebda7a services/software/Tesseract-OCR/doc/README.md +9b64829aba22310ffafe685ded30b37a126b4962 services/software/Tesseract-OCR/libarchive-13.dll +1c1166a758d115949698f7ca4f48fb1287d37f4f services/software/Tesseract-OCR/libb2-1.dll +6e49a79e514c0758a4d0a845f70924c6c2170299 services/software/Tesseract-OCR/libbrotlicommon.dll +c67e14b5053dd81bd35747db1e90b2f7798de3ae services/software/Tesseract-OCR/libbrotlidec.dll +6f7db4827a41fef8a3aaa03efa31e72be3b7d366 services/software/Tesseract-OCR/libbz2-1.dll +3a35c115310eb54c031f603ca60fa31ace908df1 services/software/Tesseract-OCR/libcairo-2.dll +6fc26c9edd0220716d0313a7d14f3495297a2f10 services/software/Tesseract-OCR/libcrypto-3-x64.dll +b096c47d7c0022147e530c8009d9808e1569d743 services/software/Tesseract-OCR/libcurl-4.dll +672e29208adc991593fcef2efbafc2728157cbc3 services/software/Tesseract-OCR/libdatrie-1.dll +dd1505a81e7e89a815d4b3898ac6a2427ba45605 services/software/Tesseract-OCR/libdeflate.dll +78cd67b0890ca50cd311ca992a3a59644c9064ae services/software/Tesseract-OCR/libexpat-1.dll +77212def06935f83edb0e56be1ab550c46d680d9 services/software/Tesseract-OCR/libffi-8.dll +42edff502a584042bb6d6cf55e37e38af3d7e40e services/software/Tesseract-OCR/libfontconfig-1.dll +0b4250e04bb19668d9d5723f7d8bb11184904458 services/software/Tesseract-OCR/libfreetype-6.dll +19b30d590a03b49b091c48a4f619a8fd5d80a20e services/software/Tesseract-OCR/libfribidi-0.dll +cd1efb4b7af4abb238a543fdd2562e3ddf2a34a3 services/software/Tesseract-OCR/libgcc_s_seh-1.dll +5693bac25dbd497caa771b108b80ac6e799583dc services/software/Tesseract-OCR/libgif-7.dll +b8805159fcfb05846ce6979e8b313aaa617487c0 services/software/Tesseract-OCR/libgio-2.0-0.dll +884858efca1c2076618e1b98dbee6f578e7af398 services/software/Tesseract-OCR/libglib-2.0-0.dll +c95eb9947475b6fe9c5356623be8d0fe6432ebb0 services/software/Tesseract-OCR/libgmodule-2.0-0.dll +eec8d09494f28c3bc6e4b3338f8c93df61385b84 services/software/Tesseract-OCR/libgobject-2.0-0.dll +9b5178ac8ab3cc3656cad59e95d56f41f888310d services/software/Tesseract-OCR/libgraphite2.dll +d148bd8d34d454f3dae23dfddd8f234a49adc95b services/software/Tesseract-OCR/libharfbuzz-0.dll +34abf65eb7d43718fd74e3d954c617274216fb3e services/software/Tesseract-OCR/libiconv-2.dll +95ebd5abbda37376573b025d7db81870e0eb8f77 services/software/Tesseract-OCR/libicudt74.dll +627628997c7bb54e1f053877b7d778118d326fd4 services/software/Tesseract-OCR/libicuin74.dll +497222f9bab31232a7f78ea8a712eed5397f1997 services/software/Tesseract-OCR/libicuuc74.dll +37d62690f0d47e78067911251c4933965c7f08ab services/software/Tesseract-OCR/libidn2-0.dll +2aed7ad9c1b6b841f911269b6c17ddc2d56cfda6 services/software/Tesseract-OCR/libintl-8.dll +9bee42fd5a922d62660c5d71a53c2ad830c7c019 services/software/Tesseract-OCR/libjbig-0.dll +d45e627fdbe9d88fcebb20bb672b1aca68db803d services/software/Tesseract-OCR/libjpeg-8.dll +5f06383c1f9da5edd60d3c8ea1d0f65e6eb50ae4 services/software/Tesseract-OCR/libleptonica-6.dll +1c089e20ba3aa0a64a9af9fc49db564eab85a52d services/software/Tesseract-OCR/libLerc.dll +df85958c15533b23ab75ce58bd42c89ff26ce0e2 services/software/Tesseract-OCR/liblz4.dll +5ec3362724e3e84349599c42960281e32445830b services/software/Tesseract-OCR/liblzma-5.dll +74b3f134e4e91dcf61603f334fa688c30c1b3907 services/software/Tesseract-OCR/libopenjp2-7.dll +e86c4cfbabdb9b53d3c0eae620f154f9460a083c services/software/Tesseract-OCR/libpango-1.0-0.dll +cd072eb6f559c1981669330a4ffb598be8e02e2e services/software/Tesseract-OCR/libpangocairo-1.0-0.dll +8b17f7421be6c91a16e81f226814500efe579a2a services/software/Tesseract-OCR/libpangoft2-1.0-0.dll +a4fe8203f5aaf2ff328466dfec6b4c433ae1cc8e services/software/Tesseract-OCR/libpangowin32-1.0-0.dll +0349abf83154a6301d1e2b1b19c48ac703178360 services/software/Tesseract-OCR/libpcre2-8-0.dll +535ea7c78ba493f7187e984b47f901fc6c56bd9c services/software/Tesseract-OCR/libpixman-1-0.dll +4e7c3ac364ab521ea3580ab127c8f87c0ea0b30d services/software/Tesseract-OCR/libpng16-16.dll +74ed8044917fd71f100d3c75a4cc7295013ee61e services/software/Tesseract-OCR/libpsl-5.dll +22f3ee25ca999f021238a84fce073c2fb2b44945 services/software/Tesseract-OCR/libsharpyuv-0.dll +2860272c6336c51479779327a40e5014f35f5455 services/software/Tesseract-OCR/libssh2-1.dll +0ec8296d9e50a3225f88d4968161ed6348b2d8f6 services/software/Tesseract-OCR/libstdc++-6.dll +6ee07fc831d1cebed554b76cfdb75490bd8d48e2 services/software/Tesseract-OCR/libtesseract-5.dll +b931aad412604d3f4ae88b369212af7af8c3156a services/software/Tesseract-OCR/libthai-0.dll +ffbfe6d3cf9b17d9a41073943d3324f4719e665c services/software/Tesseract-OCR/libtiff-6.dll +95815c468603b80b47ad20ecca6b60d202fc5f58 services/software/Tesseract-OCR/libunistring-5.dll +2d457d71b47975d3bbb090069b0c570a993f3483 services/software/Tesseract-OCR/libwebp-7.dll +43ab09535c1f3909d24209a9c49b58bef7a00efc services/software/Tesseract-OCR/libwebpmux-3.dll +362cfc0f5752c8f49e5acd99b3982c485804afd3 services/software/Tesseract-OCR/libwinpthread-1.dll +d59a28d172b49f010c27d722ecf3f8fee101afaf services/software/Tesseract-OCR/libzstd.dll +d5ce355e39af2e4424d3aefca1ae392274bf1879 services/software/Tesseract-OCR/lstmeval.1.html +3658bcd2c9c07952d3f7b431a47c2a3d107d4e1f services/software/Tesseract-OCR/lstmeval.exe +85651c80465af6445c79ecc716c110b9df966717 services/software/Tesseract-OCR/lstmtraining.1.html +b0ccfd764eeca12871867d21728c9351846c3afc services/software/Tesseract-OCR/lstmtraining.exe +b321b768f5afa23fc4d335bab23193423032e14f services/software/Tesseract-OCR/merge_unicharsets.1.html +bd947e775a39033b591e116b4f6eee83f1897ac2 services/software/Tesseract-OCR/merge_unicharsets.exe +6ff757ba1a9173e475b84e5b25d5983263fb31e1 services/software/Tesseract-OCR/mftraining.1.html +fb1b10b73324930ccd63d5f0ccca873dd903b408 services/software/Tesseract-OCR/mftraining.exe +98088653dea9b78be6116d672a3391a09f2b1753 services/software/Tesseract-OCR/set_unicharset_properties.1.html +0bd70f8563a742391ebbdd7fd23bd74459a46e21 services/software/Tesseract-OCR/set_unicharset_properties.exe +8085791f02ae971abcc43bb3b4cdbbf1f9fe1091 services/software/Tesseract-OCR/shapeclustering.1.html +245d3d0bac84139d22f389192ee862c5673ce82e services/software/Tesseract-OCR/shapeclustering.exe +461f252fa0ba1e5917fe326ac78010932e78fedc services/software/Tesseract-OCR/tessdata +09e69cf5478cd6a0fb3ec5e7e7fa95a04f5cafb3 services/software/Tesseract-OCR/tessdata/afr.traineddata +7a302b2bf6306c34177f594e0824eafc48906965 services/software/Tesseract-OCR/tessdata/amh.traineddata +c8d129c67821c1592cac46836686b057ecc203dc services/software/Tesseract-OCR/tessdata/ara.traineddata +086035c6eacd5788c1f06d58c250023cee2aeb28 services/software/Tesseract-OCR/tessdata/asm.traineddata +27bc73edf08e5e5f0c3e43c315c5c6d965c2f075 services/software/Tesseract-OCR/tessdata/aze.traineddata +e2b1b953a5b8db9247c6ddfcb58f062dc0b3b574 services/software/Tesseract-OCR/tessdata/aze_cyrl.traineddata +65d83dad535f876de31847f5fa2ff1bdd57c7bab services/software/Tesseract-OCR/tessdata/bel.traineddata +7e9054d1de309714009a85555f5276168d41af9c services/software/Tesseract-OCR/tessdata/ben.traineddata +7bb5029466eaef46aad59fc23b96648df0e4f176 services/software/Tesseract-OCR/tessdata/bod.traineddata +95bed5c32e3759347db0471569303f06e3485f42 services/software/Tesseract-OCR/tessdata/bos.traineddata +c01691329561938fb7d491ea7611c591202952dd services/software/Tesseract-OCR/tessdata/bre.traineddata +1e65588d127d918ef3ba95b785b446f15827d60f services/software/Tesseract-OCR/tessdata/bul.traineddata +3fcd350dd2bb76503de90249111fff4e3c6aa0f0 services/software/Tesseract-OCR/tessdata/cat.traineddata +5a1b96928e54b175db96f00d2aa84b5878d301b9 services/software/Tesseract-OCR/tessdata/ceb.traineddata +dd6fc79a62f9fcd1c7c6da06b31bb4fdb10dc173 services/software/Tesseract-OCR/tessdata/ces.traineddata +388bac276d033d06e5ed5ba7a7ad14ae58f97dab services/software/Tesseract-OCR/tessdata/chi_sim.traineddata +f9898e91068a9d04bcacf6d2a244da40e9f30c0c services/software/Tesseract-OCR/tessdata/chi_sim_vert.traineddata +1955cd8b8d076b898616e9c2c1ace65b43105356 services/software/Tesseract-OCR/tessdata/chi_tra.traineddata +94bc5dbd7fa25dd89ac9c5bd18f3fc6d8409aa0e services/software/Tesseract-OCR/tessdata/chi_tra_vert.traineddata +e0799a2b888466e5bc2ca60f1f2fb4a7ff4c6990 services/software/Tesseract-OCR/tessdata/chr.traineddata +d089c65b686fee201a62f40f50b3383a3a971f04 services/software/Tesseract-OCR/tessdata/configs +0dd12a7a709c14e267fb7141cd9ef705102b8a3a services/software/Tesseract-OCR/tessdata/configs/alto +23035a1904cfb8a2e5ad143ac638447bc1b04b4c services/software/Tesseract-OCR/tessdata/configs/ambigs.train +5cd6ec0310213adbc59e5c48a49f858daf3cdc4f services/software/Tesseract-OCR/tessdata/configs/api_config +5d6c2d061f4a0bae8ab3b2270da8e6744a048d11 services/software/Tesseract-OCR/tessdata/configs/bigram +d39f2687ef8c50f090895ba1f26367e25613a685 services/software/Tesseract-OCR/tessdata/configs/box.train +82754e9cc90b7da072c9074e7ee1492beaa72db6 services/software/Tesseract-OCR/tessdata/configs/box.train.stderr +6a329f892910ae9dd7af1f9fe8f7a1d48378fd8b services/software/Tesseract-OCR/tessdata/configs/digits +7d00b613ffcbf7e4fa712d2c50a85c7643a027e3 services/software/Tesseract-OCR/tessdata/configs/get.images +5ab372eaf819b05bdd87ba419c874f6a1be4677b services/software/Tesseract-OCR/tessdata/configs/hocr +252f1a171a154f9ade798e210015a720af039d00 services/software/Tesseract-OCR/tessdata/configs/inter +c6ac105788137bc4e89821e94843ea86ed5b4564 services/software/Tesseract-OCR/tessdata/configs/kannada +bd9c114df65ddf13e640298075adb940225c5f96 services/software/Tesseract-OCR/tessdata/configs/linebox +a160f9be275a70fe3af1935fb8fe7af29efa8451 services/software/Tesseract-OCR/tessdata/configs/logfile +5ff37726211ab360ceead7c76a1b52613cc2f277 services/software/Tesseract-OCR/tessdata/configs/lstm.train +a6f2cedc504e9010eec3bfb0b1336b75ef0c28e5 services/software/Tesseract-OCR/tessdata/configs/lstmbox +3fa3dee71aafe30913c1863a5e67529872984743 services/software/Tesseract-OCR/tessdata/configs/lstmdebug +3d90ac26f9542c6beac1082b2d900859906af8e9 services/software/Tesseract-OCR/tessdata/configs/makebox +9928884cd0238d15533d30f1445df85695d814cc services/software/Tesseract-OCR/tessdata/configs/page +59645d71ce52a143d819f2057c8c4e9ce2d46e40 services/software/Tesseract-OCR/tessdata/configs/pdf +35b59a9d41dd462c6d13b2301d4b2c31219c582f services/software/Tesseract-OCR/tessdata/configs/quiet +f8342b4c2c7eb733e1d4078f32a0aa5aee677cc3 services/software/Tesseract-OCR/tessdata/configs/rebox +e95b59263daf6d43f1b20682a4fa79d386484536 services/software/Tesseract-OCR/tessdata/configs/strokewidth +dc52478177fd6fb7b1fe278e1374c2054f3e2442 services/software/Tesseract-OCR/tessdata/configs/tsv +a0cc952977f0f3562a5c94011c13044ace865519 services/software/Tesseract-OCR/tessdata/configs/txt +d2e22f5b93585032eef94f22966329144ba44d6f services/software/Tesseract-OCR/tessdata/configs/unlv +38cd41cd60f89ec7ab3bc5161e094b20f06a3361 services/software/Tesseract-OCR/tessdata/configs/wordstrbox +3105b7fb0cd6c26f4fb144ec5d594430e88927cb services/software/Tesseract-OCR/tessdata/cos.traineddata +900cf17f74514934f87e9a8df3b29cb16b5606fe services/software/Tesseract-OCR/tessdata/cym.traineddata +85501b582937493f9ae6a64ccd0a6bb0a2ea33d5 services/software/Tesseract-OCR/tessdata/dan.traineddata +97ed7b2b60f2771c07040660ef0f6daf596dc7bf services/software/Tesseract-OCR/tessdata/deu.traineddata +53b46df7d6ae94f75913d6377182867ea09d950b services/software/Tesseract-OCR/tessdata/div.traineddata +3c31175be56ab4db42af614f384ea52ce949082c services/software/Tesseract-OCR/tessdata/dzo.traineddata +ed98ae1a88d84414da316e6eeab3232f2c68639b services/software/Tesseract-OCR/tessdata/ell.traineddata +bbef4675053b5b468cdb477053e28b1c698ba08e services/software/Tesseract-OCR/tessdata/eng.traineddata +5daba44df897f1c6d67caeb6d0414f7b55625fa1 services/software/Tesseract-OCR/tessdata/eng.user-patterns +e0c5a630214ac69273e2b54107c62ed171fc50a0 services/software/Tesseract-OCR/tessdata/eng.user-words +e49b5b86da60f2e728ff2b7f4357692ac32b6a6d services/software/Tesseract-OCR/tessdata/enm.traineddata +235fc67adf52f43d34b409d44d426d560aefc8e3 services/software/Tesseract-OCR/tessdata/epo.traineddata +27b470378dc8718f1dc5a93931fefa3340336e4d services/software/Tesseract-OCR/tessdata/equ.traineddata +a2b52c3388358e6dfc4eb8d64d8fc6afbb3630ea services/software/Tesseract-OCR/tessdata/est.traineddata +6247f975443ec82c219c39e0b5ea76b4833c82fe services/software/Tesseract-OCR/tessdata/eus.traineddata +1b845e73759785908aef57161ae4c86a70cce622 services/software/Tesseract-OCR/tessdata/fao.traineddata +1a17ee02076107e73abd15d2038389150c8f824f services/software/Tesseract-OCR/tessdata/fas.traineddata +785f80decce6ddb6b50bd99f4840414359c806ff services/software/Tesseract-OCR/tessdata/fil.traineddata +73f92402f1891b9066e0e145f245145a2402105c services/software/Tesseract-OCR/tessdata/fin.traineddata +d9e2b2160be0d1ca3b8f1bf2730fae476ef3b4a6 services/software/Tesseract-OCR/tessdata/fra.traineddata +d473893bcabcef536ed36480f976fcce482bd87c services/software/Tesseract-OCR/tessdata/frk.traineddata +ed06039efef821b78f22c86abb6c5aea7f02461e services/software/Tesseract-OCR/tessdata/frm.traineddata +17199d2c33e201d6ad4003a6c86db5f8f273ddc1 services/software/Tesseract-OCR/tessdata/fry.traineddata +e8bae7f1863dd1872ab7d2b2e7f319874c480e60 services/software/Tesseract-OCR/tessdata/gla.traineddata +a7abc7be9aadc862b31ab7c7bc672051cd0245fb services/software/Tesseract-OCR/tessdata/gle.traineddata +7bc00b38f40f8de1575397f7d05387e5fbbacca4 services/software/Tesseract-OCR/tessdata/glg.traineddata +e94990006fc18e88ab120e7ca6681cc3b290269b services/software/Tesseract-OCR/tessdata/grc.traineddata +151b9aad2945e3103118e5d36eee288f631d985a services/software/Tesseract-OCR/tessdata/guj.traineddata +30d3baeaeef791781d782e58feb415b25921df3f services/software/Tesseract-OCR/tessdata/hat.traineddata +7356caf3cddc9c867fe6727e17726727b8284608 services/software/Tesseract-OCR/tessdata/heb.traineddata +a8f0aaec09378115b12a2c6287c57695d082aea2 services/software/Tesseract-OCR/tessdata/hin.traineddata +6dd4f8638a58eb0663e8f9a80a355c505dcf01a6 services/software/Tesseract-OCR/tessdata/hrv.traineddata +5d24fa8e922d6b57853dcb0cc490060c76643cab services/software/Tesseract-OCR/tessdata/hun.traineddata +ec2e2f3adea785e8964b9771871c44349a6e1b40 services/software/Tesseract-OCR/tessdata/hye.traineddata +6eab87ffe818b5f89baa869c458cb0a6dbed6b2d services/software/Tesseract-OCR/tessdata/iku.traineddata +3013f50cd2af9aceca00e865ed889144865f0848 services/software/Tesseract-OCR/tessdata/ind.traineddata +20d3bdf8cb8f2289a1f45aa9cdf4ddf2a22e7462 services/software/Tesseract-OCR/tessdata/isl.traineddata +edbffbe0e51892b240630b5eeabededa7e7c9c4f services/software/Tesseract-OCR/tessdata/ita.traineddata +c8a2c3c3d8c82a2d953b0fc64b949c1aa0918c09 services/software/Tesseract-OCR/tessdata/ita_old.traineddata +3155b8184d50af28dbf8dcbd972e26b388ab1581 services/software/Tesseract-OCR/tessdata/jav.traineddata +45658654712b88d45c9464286ffc2fcb07036bdf services/software/Tesseract-OCR/tessdata/jaxb-api-2.3.1.jar +c4178f89991bde90b7fdc647e3e1901868423bd0 services/software/Tesseract-OCR/tessdata/jpn.traineddata +43f38defe4b83588876d0d7a6dee928be1b73af0 services/software/Tesseract-OCR/tessdata/jpn_vert.traineddata +78252baeed24bcf327e62226c321c60242108a24 services/software/Tesseract-OCR/tessdata/kan.traineddata +1a3ae11fdd248891dd3fc74f156a0ce246ec1a15 services/software/Tesseract-OCR/tessdata/kat.traineddata +f4ae5ab4b3fe4bb3226639d9b23fa71513a40ec8 services/software/Tesseract-OCR/tessdata/kat_old.traineddata +f889e2b8ffd093d4f2dff8ffca2fa0b73296c028 services/software/Tesseract-OCR/tessdata/kaz.traineddata +d466dc2a7e35bf90cb7b54364985703728398687 services/software/Tesseract-OCR/tessdata/khm.traineddata +3e04f2954f33dd021b95de4befffb68904d9e142 services/software/Tesseract-OCR/tessdata/kir.traineddata +d1afefb7c5a67e273c6612aba77753021506b557 services/software/Tesseract-OCR/tessdata/kmr.traineddata +60986d44497689f3abace0b148199476d93292e1 services/software/Tesseract-OCR/tessdata/kor.traineddata +10bd41ae9352889f85a489eb3183eb0cbebc2516 services/software/Tesseract-OCR/tessdata/lao.traineddata +30dab6a24339f262d1eb21a3ee272d16c46aeba3 services/software/Tesseract-OCR/tessdata/lat.traineddata +71d925c8b6c73980157fd0128412b46e6e8396b5 services/software/Tesseract-OCR/tessdata/lav.traineddata +af9e2b3cd6a65650206b7d89f1b93b51683b9692 services/software/Tesseract-OCR/tessdata/lit.traineddata +c1ac5b922bbcad34b2654ba471c0a752c0397404 services/software/Tesseract-OCR/tessdata/ltz.traineddata +70e96f02cbc2f26630225112cd323a7f0b6ccdf3 services/software/Tesseract-OCR/tessdata/mal.traineddata +79138fadcdb256ec7b59e3bf9df18bd5fb492bee services/software/Tesseract-OCR/tessdata/mar.traineddata +fb0b245fb9ec61696e818887a70d8413b2914905 services/software/Tesseract-OCR/tessdata/mkd.traineddata +4242f9cd016987f16feb06973e988eced9604787 services/software/Tesseract-OCR/tessdata/mlt.traineddata +2ef212c519edc66ff2508f48dbe1bb836a4ea274 services/software/Tesseract-OCR/tessdata/mon.traineddata +eab6b1a98e4b6ed510d6443a5e3d14519da3b338 services/software/Tesseract-OCR/tessdata/mri.traineddata +f0e2b8bef0a681f09baac99a418529205ee80201 services/software/Tesseract-OCR/tessdata/msa.traineddata +cf28ddca604dc7f46bc34f2f4c6a193a0706c03b services/software/Tesseract-OCR/tessdata/mya.traineddata +948e365b55f9fe8179dde2ff0134feffb210496e services/software/Tesseract-OCR/tessdata/nep.traineddata +53ce95a9c2488a9a0228939944a184157373d0ae services/software/Tesseract-OCR/tessdata/nld.traineddata +9209df2c9904c127437c07e16c287cdefd024e7c services/software/Tesseract-OCR/tessdata/nor.traineddata +4017d4405b09333f22a3de2a4d30cf009bdb4a9b services/software/Tesseract-OCR/tessdata/oci.traineddata +ae0f9ed13d5c9ad4a4de57c7266c434b83a9f583 services/software/Tesseract-OCR/tessdata/ori.traineddata +527457ca8f8fe1fda7c2f88bce3c0e4be12be9d0 services/software/Tesseract-OCR/tessdata/osd.traineddata +d4f00533a6c76ce4045aa6ad40b39f47eeaa333f services/software/Tesseract-OCR/tessdata/pan.traineddata +d1472b20ef1aebbf5e11573867e9ac13873681b9 services/software/Tesseract-OCR/tessdata/pdf.ttf +df84ed5cc8059d640876d3be0ac4c11af0bf0853 services/software/Tesseract-OCR/tessdata/piccolo2d-core-3.0.1.jar +daf51c0ebbea07291c85cab9bc81b19ef0e99efc services/software/Tesseract-OCR/tessdata/piccolo2d-extras-3.0.1.jar +2382f568f0ce0c4c0a7f4380a291255514e5e97f services/software/Tesseract-OCR/tessdata/pol.traineddata +e9f373e95c66b4bf557c263721ef31f78e5bc301 services/software/Tesseract-OCR/tessdata/por.traineddata +220cdf92efdc76a227439c0b8734196af9743b98 services/software/Tesseract-OCR/tessdata/pus.traineddata +d80c1f308973b3129183843759f23fdcb1c5c2be services/software/Tesseract-OCR/tessdata/que.traineddata +04cd2bc7b471431354e9446e973f3472f442e189 services/software/Tesseract-OCR/tessdata/ron.traineddata +b146cb2263acbc6383f8e92ea0ce759537687bb8 services/software/Tesseract-OCR/tessdata/rus.traineddata +3df043f3247fd41a21ac47c3b199bc87643e984b services/software/Tesseract-OCR/tessdata/san.traineddata +7ef1100eecc1563f12f847a8c5580b80a2341c5b services/software/Tesseract-OCR/tessdata/script +4d4bac05b8be69aafb537d3a753efec6be473953 services/software/Tesseract-OCR/tessdata/script/Arabic.traineddata +7e4cf10f1fb571dbce0afea837db15cd11b44f39 services/software/Tesseract-OCR/tessdata/script/Armenian.traineddata +a1b888e492320fb9b941dbf0d7fe9d767e5f6a42 services/software/Tesseract-OCR/tessdata/script/Bengali.traineddata +9ba41b35b6b06892657a61dd33003bc8a0a9483a services/software/Tesseract-OCR/tessdata/script/Canadian_Aboriginal.traineddata +94834e6e395e97209c59846dc78320e830f67a12 services/software/Tesseract-OCR/tessdata/script/Cherokee.traineddata +1901a7483cccad6c43d1052bb40d754ae53694b4 services/software/Tesseract-OCR/tessdata/script/Cyrillic.traineddata +3c33bd676b0ae7a480ec1c1f5ebdd13513aa5433 services/software/Tesseract-OCR/tessdata/script/Devanagari.traineddata +e6c0944e630c580f4a9d6d4a8ebeaeaca3583164 services/software/Tesseract-OCR/tessdata/script/Ethiopic.traineddata +28262227524b894a1f283e8edd2245f11d9e3e9f services/software/Tesseract-OCR/tessdata/script/Fraktur.traineddata +77511502fa8dd8d1aec6700b697bdd3cc501a78d services/software/Tesseract-OCR/tessdata/script/Georgian.traineddata +0fdbf7f0eb07e1c4a72f580afba84cd85cafc177 services/software/Tesseract-OCR/tessdata/script/Greek.traineddata +9f203b6620b479149fe022553278a48032c87f21 services/software/Tesseract-OCR/tessdata/script/Gujarati.traineddata +36e1161b20dac2826f80c7e27f753670177116a2 services/software/Tesseract-OCR/tessdata/script/Gurmukhi.traineddata +977fd63d7430853e04f49c43400dc576144cfe0e services/software/Tesseract-OCR/tessdata/script/Hangul.traineddata +4e421ca8baa936ffad67b6bd78df848bbfb4fa03 services/software/Tesseract-OCR/tessdata/script/Hangul_vert.traineddata +41d7386cacc0faf19b381f9bba035cb3bcc7f8f9 services/software/Tesseract-OCR/tessdata/script/HanS.traineddata +a0464cb0478f089f00cbfa715a15ba5aba5d0e37 services/software/Tesseract-OCR/tessdata/script/HanS_vert.traineddata +ac8c8e97a2e75db8afd1a843527f350737973435 services/software/Tesseract-OCR/tessdata/script/HanT.traineddata +99757fde125138e5d889784d0d9f2edd659defac services/software/Tesseract-OCR/tessdata/script/HanT_vert.traineddata +590055a3db20484eb90e6bd1a9223f36b69ea907 services/software/Tesseract-OCR/tessdata/script/Hebrew.traineddata +89481f2c257019f1ea58c82b7daaac9688f7b172 services/software/Tesseract-OCR/tessdata/script/Japanese.traineddata +5c211c42046ada01847b1628a6f1766826c2a371 services/software/Tesseract-OCR/tessdata/script/Japanese_vert.traineddata +238f7a104e604a27b14ca956df2f346f7750099b services/software/Tesseract-OCR/tessdata/script/Kannada.traineddata +635b310e6a79c3aac2fe5aa12dd5bcb7718c2e15 services/software/Tesseract-OCR/tessdata/script/Khmer.traineddata +0bdf44f32650e6f15ef0491f88dee430994dca62 services/software/Tesseract-OCR/tessdata/script/Lao.traineddata +8b6e3a3ae06e6b623b587e9f87c988e169fa1c6b services/software/Tesseract-OCR/tessdata/script/Latin.traineddata +9e639ea78e5040c75bce36e1231755901448e4ef services/software/Tesseract-OCR/tessdata/script/Malayalam.traineddata +733ebd14f67a5a52211abfc6f66b485a23a8b955 services/software/Tesseract-OCR/tessdata/script/Myanmar.traineddata +d9ef97617c0914028360f703d810564013542421 services/software/Tesseract-OCR/tessdata/script/Oriya.traineddata +98d26bd5f71305d96f947e29d3fcb455ff26bc9f services/software/Tesseract-OCR/tessdata/script/Sinhala.traineddata +b97923946987070b6ee69ab41d4bc4c87b739001 services/software/Tesseract-OCR/tessdata/script/Syriac.traineddata +48fede126ba6e563a69ca10eae3604e42143039f services/software/Tesseract-OCR/tessdata/script/Tamil.traineddata +0468e5dc1eee3059191b4ac2d7109a9431ce42c1 services/software/Tesseract-OCR/tessdata/script/Telugu.traineddata +b13feb9f2af4762a80431e93de11e2e61ae40068 services/software/Tesseract-OCR/tessdata/script/Thaana.traineddata +62acc3de815e28c43f764dc7e10e5c8afdfefb20 services/software/Tesseract-OCR/tessdata/script/Thai.traineddata +223459ad4ee20b85075e423975aa44edbed190dd services/software/Tesseract-OCR/tessdata/script/Tibetan.traineddata +92c69d17eab37670c3ffc0efce3f7918ef1d9468 services/software/Tesseract-OCR/tessdata/script/Vietnamese.traineddata +fe7fafcfe7e57d1ccd679a0b8a9775e1a821f881 services/software/Tesseract-OCR/tessdata/ScrollView.jar +d0c8584e78c44666efcd7fbd47940a8a1121550d services/software/Tesseract-OCR/tessdata/sin.traineddata +ca99e3e82f69a0e16b48cdfec3c4e706758269f2 services/software/Tesseract-OCR/tessdata/slk.traineddata +835954e891897d3c8b63db48cb5c2712ef2e6b11 services/software/Tesseract-OCR/tessdata/slv.traineddata +1ef6548d22977dc1f236be879dce3a62ac6a47ed services/software/Tesseract-OCR/tessdata/snd.traineddata +72e901f13ca52cfe34cf239a368b9ed3c0ddaf26 services/software/Tesseract-OCR/tessdata/spa.traineddata +42b281f55736b2f714598accfc2a78f409db1f0c services/software/Tesseract-OCR/tessdata/spa_old.traineddata +9624fbf33452a95dd5a0a3a93fe9876108104895 services/software/Tesseract-OCR/tessdata/sqi.traineddata +530fb4b1cb27f369bbee7eb0add89bfd73d6f15c services/software/Tesseract-OCR/tessdata/srp.traineddata +5f81e591adad58a179a2d371aacccaf0801f93a2 services/software/Tesseract-OCR/tessdata/srp_latn.traineddata +894891425c1fe302ce1d8f115a3c00967c6c2832 services/software/Tesseract-OCR/tessdata/sun.traineddata +633d73b35869600452eec58dcd9036cc702c3e48 services/software/Tesseract-OCR/tessdata/swa.traineddata +684e1fa66e4a55b983febf5f9ed04f26ad946e59 services/software/Tesseract-OCR/tessdata/swe.traineddata +462aefc8a1485ae4c38db82f7f50fd105bf30195 services/software/Tesseract-OCR/tessdata/syr.traineddata +fa1793d68f9aba8bf191e8ff1036e2271d288e44 services/software/Tesseract-OCR/tessdata/tam.traineddata +9485ca27d48bb161a47584f8381420462ef6fa27 services/software/Tesseract-OCR/tessdata/tat.traineddata +ee8a33b0f658fc75b8cbfe8c10413eac4f41e6ad services/software/Tesseract-OCR/tessdata/tel.traineddata +51fe80ee88432b91fe829ac8d1f665e649722316 services/software/Tesseract-OCR/tessdata/tessconfigs +a681e4a443fa21ce6f32bbcf0334af3433888566 services/software/Tesseract-OCR/tessdata/tessconfigs/batch +ebaab9438e309b4dfdfd8428676170ab2b64a858 services/software/Tesseract-OCR/tessdata/tessconfigs/batch.nochop +c34567be7565d519806076b795fceff9fdad1477 services/software/Tesseract-OCR/tessdata/tessconfigs/matdemo +9c1184a0c84bde5f58ea74a1f316af9eb2574b52 services/software/Tesseract-OCR/tessdata/tessconfigs/msdemo +8b137891791fe96927ad78e64b0aad7bded08bdc services/software/Tesseract-OCR/tessdata/tessconfigs/nobatch +eaff69f54b9ed62d49987634a5fba2c79cccf3cf services/software/Tesseract-OCR/tessdata/tessconfigs/segdemo +044766728ce9cb2cc73976175b970a4cea9a870a services/software/Tesseract-OCR/tessdata/tgk.traineddata +ea28de3985668cac00d261c5b91f023ea66e19cd services/software/Tesseract-OCR/tessdata/tha.traineddata +55e62eb0297e07360db5e9dc5dd86aab8e0a1e9c services/software/Tesseract-OCR/tessdata/tir.traineddata +9eff0fd002798089f5f7d8307be968a36f1ce433 services/software/Tesseract-OCR/tessdata/ton.traineddata +1f0b331ef29f50ceb7c44da58e38c7ec42314d0a services/software/Tesseract-OCR/tessdata/tur.traineddata +36124d6b0ed1c2654a13551203c25b44b4013978 services/software/Tesseract-OCR/tessdata/uig.traineddata +d02cf90b2911a3da66dac6ae380bcefb18dd7663 services/software/Tesseract-OCR/tessdata/ukr.traineddata +715a159d4abea25294c82971be28be215b3d1c4a services/software/Tesseract-OCR/tessdata/urd.traineddata +109abc765273b2c9eabd55781f0a619320c80007 services/software/Tesseract-OCR/tessdata/uzb.traineddata +c2ff8b9c282a9712b5f24970927377bc18dea7cf services/software/Tesseract-OCR/tessdata/uzb_cyrl.traineddata +e54a5912fb634c581c4a45ae9f37cbc021ec7140 services/software/Tesseract-OCR/tessdata/vie.traineddata +6349588bbabf99f8a812e8231c98c015ea7b60c6 services/software/Tesseract-OCR/tessdata/yid.traineddata +3e0cd582f65f17844039173057dfc015bf19f61d services/software/Tesseract-OCR/tessdata/yor.traineddata +eb39a979891e62373073aa012d1e722eccf53679 services/software/Tesseract-OCR/tesseract.1.html +1b8266d099b65455e5d028794f27e0c97c56a410 services/software/Tesseract-OCR/tesseract.exe +f9a8aaca808fb84974a69db7058d39dfd6143940 services/software/Tesseract-OCR/tesseract-uninstall.exe +dabfda7747f42b0bf5a77f497f63cd9bcb24bac7 services/software/Tesseract-OCR/text2image.1.html +5dec420773690de9c9ec1b5ef749bb697aad107a services/software/Tesseract-OCR/text2image.exe +d939cf54b047a0089add0e711657282ee6a97ae4 services/software/Tesseract-OCR/unicharambigs.5.html +3f0f72aee992bbf1f8a364c9bc8607bbd66a2891 services/software/Tesseract-OCR/unicharset.5.html +efbeabdaf5aa4aedf38e5def2fff26789bb05f4f services/software/Tesseract-OCR/unicharset_extractor.1.html +22f28c9f4aec70a28b30276337eb5368c4939cb2 services/software/Tesseract-OCR/unicharset_extractor.exe +428e40e914e1fd615ecd931333cb2d192c060499 services/software/Tesseract-OCR/winpath.exe +7503ef471c8cb9e9fe9af50012737f035df4ea03 services/software/Tesseract-OCR/wordlist2dawg.1.html +5e9c230a56297f6f5d7834028f4f4af6d97c2a27 services/software/Tesseract-OCR/wordlist2dawg.exe +93c94c53ea14cc76fb6d313835ccef795c154209 services/software/Tesseract-OCR/zlib1.dll +74576a17b24af3b3461b3cf366bffc72b8af2247 services/tools +c060f8c47950ea007ef82d25341f6a236e690b1c services/tools/__init__.py +1ab5b944403cc0b3f268e9ce08dbcbd7fcb37883 services/tools/profile_scoring.py +3f523c2a536282d053c95a2f8149cb6f3d6d7fc7 services/uploader +e4cb1c1d046ce257dd41421a9529c2b5e972e5b7 services/uploader/azure_blob_service.py +3df5871d164cfdc5e82242c3c431196d889d1fb6 utils +a333c68fbc8680eb129aff6ae6a77b5fefc71b45 utils/__init__.py +d53923b95ed7e11ca362be122da89b3bc03d061d utils/decorator.py +9d0a562984f25046ddc3379aca73c1115d8fb528 utils/jwt.py +41d27a764c6b8a814c28f9e4812f669397450dd6 utils/logger.py +da25f0b2a8b1d7ad1d4b2334b673b20b378d5788 utils/security.py +a8682aeeeac3e667bd5150cbe6d18e069999f4f5 utils/utils.py +7ae84070d708061792beddf97a92f5daeaf97ea3 uv.lock diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..901cd6b713ff67c60b4b70319d7bd7289c4b0067 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,18 @@ +# Environment +stage: + active: dev # choose one of dev | uat | prd + +# Observability +langfuse: + is_active: false + +# Prefix blob folder +blob: + prefix: dev/cv + +llm: + default: "gpt-4o" + + +# "[dev|uat|prd]_[tenant_id]_[kb|caching|data_info]" +azure_search_index_name_template: "{stage}__{tenant_id}__{purpose}" \ No newline at end of file diff --git a/config/constant.py b/config/constant.py new file mode 100644 index 0000000000000000000000000000000000000000..5b6ae76d696bf5ff0788f6e349e2e84d32594fec --- /dev/null +++ b/config/constant.py @@ -0,0 +1,38 @@ +import os +from dataclasses import dataclass, field +from dotenv import load_dotenv +from typing import List +from config.env_constant import EnvFilepath +load_dotenv(EnvFilepath.ENVPATH) + + +@dataclass +class EnvPostgresConstants: + CONSTRING: str = os.environ.get("ss--postgresql--url") + +@dataclass(frozen=True) +class SecurityConstants: + BCRYPT_MAX_BYTES: int = 72 + JWT_SECRET_KEY: str = os.environ.get("ss--jwt--secret-key") + JWT_ALGORITHM: str = os.environ.get("ss--jwt--algorithm") + JWT_EXPIRE_MINUTES: int = int(os.environ.get("ss--jwt--access-token-expire-minutes", 60)) + +@dataclass(frozen=True) +class AzureBlobConstants: + BLOB_PREFIX: str = "dev" # DOCS: change accordingly + ENDPOINT: str = os.environ.get("azureai--container--endpoint") + CONTAINER_NAME: str = os.environ.get("azureai--container--name") + SAS_KEY: str = os.environ.get("azureai--search--sas") + MAX_FILE_SIZE_MB: int = int(os.getenv("azureai--max-file-size-mb", "5")) + CHUNK_SIZE: int = 4 * 1024 * 1024 + ACCOUNT_NAME: str = os.environ.get("azureai--container--account--name") + +@dataclass +class ProfileFieldTypes: + NUMERIC: List[str] = field(default_factory=lambda: ["gpa_edu_1", "gpa_edu_2", "gpa_edu_3", "yoe"]) + TEXT: List[str] = field(default_factory=lambda: ["univ_edu_1", "major_edu_1", + "univ_edu_2", "major_edu_2", + "univ_edu_3", "major_edu_3", + "domicile", + "hardskills", "softskills", "certifications", "business_domain"]) +ProfileFieldTypes = ProfileFieldTypes() diff --git a/config/env_constant.py b/config/env_constant.py new file mode 100644 index 0000000000000000000000000000000000000000..664a24f2f3d8082d96efba45f5c5dbfb87bf5bb4 --- /dev/null +++ b/config/env_constant.py @@ -0,0 +1,5 @@ +from dataclasses import dataclass + +@dataclass +class EnvFilepath: + ENVPATH: str = ".env" # DOCS: change in uat or prod environment! diff --git a/config/get_config.py b/config/get_config.py new file mode 100644 index 0000000000000000000000000000000000000000..afada3a9707e9d4f5907bb1b571b7bb79a65c726 --- /dev/null +++ b/config/get_config.py @@ -0,0 +1,19 @@ +import pytz +from sqlalchemy import func + + +class Config: + + @property + def tzinfo(self): + tzinfo = pytz.timezone('Asia/Jakarta') + return tzinfo + + + @property + def JAKARTA_NOW(self): + return func.timezone("Asia/Jakarta", func.now()) + + + +master_config = Config() \ No newline at end of file diff --git a/externals/__init__.py b/externals/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/externals/databases/__init__.py b/externals/databases/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/externals/databases/_pg_tables.py b/externals/databases/_pg_tables.py new file mode 100644 index 0000000000000000000000000000000000000000..ab4ee64dc2565b991d1fadcf725f71423e943616 --- /dev/null +++ b/externals/databases/_pg_tables.py @@ -0,0 +1,104 @@ +# CREATE TABLES +query_create_cv_raw = """ +CREATE TABLE cv_raw ( + filename TEXT NOT NULL UNIQUE, + profile_id SERIAL PRIMARY KEY, + file_content BYTEA NOT NULL, + is_extracted BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); +""" + +alter_table_cv_raw_add_is_extracted = """ +ALTER TABLE cv_raw +ADD COLUMN is_extracted BOOLEAN DEFAULT FALSE;""" + +query_create_cv_profile_extracted = """ +CREATE TABLE cv_profile_extracted ( + fullname VARCHAR(100) NOT NULL, + profile_id SERIAL PRIMARY KEY, + + gpa_edu_1 DECIMAL(4,2), + gpa_edu_2 DECIMAL(4,2), + gpa_edu_3 DECIMAL(4,2), + + univ_edu_1 varchar(100), + univ_edu_2 varchar(100), + univ_edu_3 varchar(100), + + major_edu_1 varchar(100), + major_edu_2 varchar(100), + major_edu_3 varchar(100), + + domicile TEXT, + yoe DECIMAL(3,1), + hardskills TEXT, + softskills TEXT, + certifications TEXT, + business_domain TEXT, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT fk_profile_extracted + FOREIGN KEY (profile_id) + REFERENCES cv_raw (profile_id) + ON DELETE CASCADE +); +""" + +query_create_cv_profile_norm = """ +CREATE TABLE cv_profile_norm ( + fullname VARCHAR(100) NOT NULL, + profile_id SERIAL PRIMARY KEY, + + gpa_edu_1 DECIMAL(4,2), + gpa_edu_2 DECIMAL(4,2), + gpa_edu_3 DECIMAL(4,2), + + univ_edu_1 varchar(100), + univ_edu_2 varchar(100), + univ_edu_3 varchar(100), + + major_edu_1 varchar(100), + major_edu_2 varchar(100), + major_edu_3 varchar(100), + + domicile TEXT, + yoe DECIMAL(3,1), + hardskills TEXT, + softskills TEXT, + certifications TEXT, + business_domain TEXT, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT fk_profile_norm + FOREIGN KEY (profile_id) + REFERENCES cv_profile_extracted (profile_id) + ON DELETE CASCADE +); +""" + +# DROP TABLES +query_drop_cv_raw = "drop table cv_raw cascade" +query_drop_cv_profile_extracted = "drop table cv_profile_extracted cascade" +query_drop_cv_profile_norm = "drop table cv_profile_norm cascade" + + +# OPERATIONS +q_creates = [query_create_cv_raw, query_create_cv_profile_extracted, query_create_cv_profile_norm] +q_drops = [ + # query_drop_cv_raw, + query_drop_cv_profile_extracted, query_drop_cv_profile_norm] + +from externals.databases._pgdb import execute_query + +async def get_create_queries(): + for q in q_creates: + await execute_query(q) + +async def get_drop_queries(): + for q in q_drops: + await execute_query(q) + + +if __name__ == "__main__": + import asyncio + # asyncio.run(get_drop_queries()) + asyncio.run(get_create_queries()) \ No newline at end of file diff --git a/externals/databases/_pgdb.py b/externals/databases/_pgdb.py new file mode 100644 index 0000000000000000000000000000000000000000..f2be3781ec9f136dabeda11d9458b7bd21f1791e --- /dev/null +++ b/externals/databases/_pgdb.py @@ -0,0 +1,56 @@ +# import os +# import dotenv +# dotenv.load_dotenv() +# import asyncpg +# # from datetime import datetime + +# async def fetch_data(query:str): +# try: +# conn = await asyncpg.connect(user=os.environ.get("causalogy--pg--user"), +# password=os.environ.get("causalogy--pg--password"), +# database=os.environ.get("causalogy--pg--name"), +# host=os.environ.get("causalogy--pg--host"), +# port=os.environ.get("causalogy--pg--port")) +# values = await conn.fetch(query) +# print(f"""✅ Fetching data succeeded!""") +# return values +# except Exception as E: +# print(f"""❌ Error when Fetching data, {E}""") +# finally: +# await conn.close() + + +# async def execute_query(query:str): +# try: +# conn = await asyncpg.connect(user=os.environ.get("causalogy--pg--user"), +# password=os.environ.get("causalogy--pg--password"), +# database=os.environ.get("causalogy--pg--name"), +# host=os.environ.get("causalogy--pg--host"), +# port=os.environ.get("causalogy--pg--port")) +# values = await conn.execute(query) +# print(f"""✅ Executing query succeeded!""") +# return True +# except Exception as E: +# print(f"""❌ Error when Executing query, {E}""") +# return False +# finally: +# await conn.close() + + +# async def execute_insert_binary(filename: str, file_content: bytes, query:str="""INSERT INTO cv_raw (filename, file_content) VALUES ($1, $2);"""): +# conn = None +# try: +# conn = await asyncpg.connect( +# user=os.environ.get("causalogy--pg--user"), +# password=os.environ.get("causalogy--pg--password"), +# database=os.environ.get("causalogy--pg--name"), +# host=os.environ.get("causalogy--pg--host"), +# port=os.environ.get("causalogy--pg--port") +# ) +# await conn.execute(query, filename, file_content) +# print(f"✅ Successfully inserted {filename} into cv_raw") +# except Exception as E: +# print(f"❌ Error when executing insert: {E}") +# finally: +# if conn: +# await conn.close() \ No newline at end of file diff --git a/externals/databases/database.py b/externals/databases/database.py new file mode 100644 index 0000000000000000000000000000000000000000..8b54d8c1a80ccb5d1779c976aca9adf275bac32f --- /dev/null +++ b/externals/databases/database.py @@ -0,0 +1,57 @@ +import os +import dotenv + +from config.constant import EnvPostgresConstants, EnvFilepath +dotenv.load_dotenv(EnvFilepath.ENVPATH) + +from contextlib import asynccontextmanager +from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession +from sqlalchemy.orm import declarative_base + +DATABASE_URL = EnvPostgresConstants.CONSTRING.\ + replace("postgresql+psycopg2", "postgresql+asyncpg") + +engine = create_async_engine( + DATABASE_URL, + echo=False, + future=True +) + +AsyncSessionLocal = async_sessionmaker( + engine, + expire_on_commit=False, + class_=AsyncSession +) + +Base = declarative_base() + +# async def get_db(): +# async with AsyncSessionLocal() as session: +# try: +# return session +# finally: +# await session.close() + +async def get_db(): + async with AsyncSessionLocal() as session: + try: + yield session + finally: + await session.close() + +# async def get_db_session(): +# session = AsyncSessionLocal() +# try: +# return session +# except: +# await session.close() +# raise + + +@asynccontextmanager +async def db_session(): + async with AsyncSessionLocal() as session: + try: + yield session + finally: + await session.close() \ No newline at end of file diff --git a/externals/databases/pg_crud.py b/externals/databases/pg_crud.py new file mode 100644 index 0000000000000000000000000000000000000000..9b32ea520069e6f3ff230174b2317d932edacb85 --- /dev/null +++ b/externals/databases/pg_crud.py @@ -0,0 +1,473 @@ +from typing import Optional, List +from uuid import UUID + +from sqlalchemy import select, and_, update, delete +from sqlalchemy.ext.asyncio import AsyncSession +from externals.databases.pg_models import ( + CVUser, + CVTenant, + CVFile, + CVProfile, + CVFilter, + CVWeight, + CVMatching, + CVScore, +) + +# ========================= +# USER +# ========================= +from externals.databases.schemas.user import UserCreate, UserResponse +from utils.security import hash_password + +async def get_user_by_username( + db: AsyncSession, + username: str, +) -> CVUser | None: + result = await db.execute( + select(CVUser).where(CVUser.username == username) + ) + return result.scalar_one_or_none() + + +async def create_user( + db: AsyncSession, + user_in: UserCreate, +) -> CVUser: + # ✅ CONVERT Pydantic → ORM + user = CVUser( + username=user_in.username, + hashed_password=hash_password(user_in.password), + email=user_in.email, + full_name=user_in.full_name, + role=user_in.role, + is_active=True, + tenant_id=user_in.tenant_id, + notes=user_in.notes, + ) + + db.add(user) # ✅ ORM + await db.commit() + await db.refresh(user) + + return user + +async def deactivate_user( + db: AsyncSession, + username: str, +) -> CVUser | None: + result = await db.execute( + select(CVUser).where(CVUser.username == username) + ) + user = result.scalar_one_or_none() + + if not user: + return None + + user.is_active = False + await db.commit() + await db.refresh(user) + + return user + + +async def get_user_by_email(db, email: str): + result = await db.execute( + select(CVUser).where(CVUser.email == email) + ) + return result.scalar_one_or_none() + + +async def get_user_by_id(db, user_id: str): + result = await db.execute( + select(CVUser).where(CVUser.user_id == user_id) + ) + return result.scalar_one_or_none() + + +# ========================= +# TENANT +# ========================= +from externals.databases.schemas.tenant import TenantCreate + +async def get_tenant_by_name( + db: AsyncSession, + tenant_name: str, +) -> CVTenant | None: + result = await db.execute( + select(CVTenant).where(CVTenant.tenant_name == tenant_name) + ) + return result.scalar_one_or_none() + + +async def create_tenant( + db: AsyncSession, + tenant_in: TenantCreate, +) -> CVTenant: + # ✅ CONVERT Pydantic → ORM + tenant = CVTenant( + tenant_name=tenant_in.tenant_name, + notes=tenant_in.notes, + ) + + db.add(tenant) # ✅ ORM + await db.commit() + await db.refresh(tenant) + + return tenant + + +# ========================= +# FILE +# ========================= + +# async def get_file_by_filename( +# db: AsyncSession, +# filename: str, +# ) -> Optional[CVFile]: +# stmt = select(CVFile).where(CVFile.filename == filename) +# result = await db.execute(stmt) +# return result.scalar_one_or_none() + + +async def mark_file_extracted( + db: AsyncSession, + file_id: UUID, +) -> None: + stmt = ( + update(CVFile) + .where(CVFile.file_id == file_id) + .values(is_extracted=True) + ) + await db.execute(stmt) + await db.commit() + + +async def create_cv_file( + db: AsyncSession, + *, + user_id: str, + filename: str, + file_type: str, + url: str, +): + cv_file = CVFile( + filename=filename, + file_type=file_type, + url=url, + is_extracted=False, + user_id=user_id, + ) + + db.add(cv_file) + await db.commit() + await db.refresh(cv_file) + + return cv_file + + +async def delete_file_by_filename( + db: AsyncSession, + filename: str, +) -> bool: + stmt = delete(CVFile).where(CVFile.filename == filename) + result = await db.execute(stmt) + await db.commit() + return result.rowcount > 0 + +async def get_file_by_user_id( + db: AsyncSession, + user_id: str, +) -> CVFile | None: + result = await db.execute( + select(CVFile).where(CVFile.user_id == user_id) + ) + return result.scalars().all() + +async def get_file_by_filename( + db: AsyncSession, + filename: str, + user_id: UUID, +) -> CVFile | None: + + result = await db.execute( + select(CVFile) + .where( + CVFile.filename == filename, + CVFile.user_id == user_id, + ) + ) + return result.scalar_one_or_none() + + +async def mark_file_extracted(db: AsyncSession, file_id: UUID): + await db.execute( + update(CVFile) + .where(CVFile.file_id == file_id) + .values(is_extracted=True) + ) + +# ========================= +# PROFILE +# ========================= + +# async def create_profile( +# db: AsyncSession, +# profile: CVProfile, +# ) -> CVProfile: +# db.add(profile) +# await db.commit() +# await db.refresh(profile) +# return profile + +from services.models.data_model import AIProfile + +async def create_profile( + db: AsyncSession, + filename: str, + file_id: str, + profile: AIProfile, +) -> CVProfile: + + profile = CVProfile( + fullname=profile.get("fullname"), + gpa_edu_1=profile.get("gpa_edu_1", None), + univ_edu_1=profile.get("univ_edu_1", None), + major_edu_1=profile.get("major_edu_1", None), + + gpa_edu_2=profile.get("gpa_edu_2", None), + univ_edu_2=profile.get("univ_edu_2", None), + major_edu_2=profile.get("major_edu_2", None), + gpa_edu_3=profile.get("gpa_edu_3", None), + univ_edu_3=profile.get("univ_edu_3", None), + major_edu_3=profile.get("major_edu_3", None), + + domicile=profile.get("domicile", None), + yoe=profile.get("yoe", None), + + hardskills=profile.get("hardskills", []), + softskills=profile.get("softskills", []), + certifications=profile.get("certifications", []), + business_domain=profile.get("business_domain", []), + + filename=filename, + file_id=file_id, + ) + + db.add(profile) + await db.flush() + return profile + + +async def get_profile_by_filename( + db: AsyncSession, + filename: str, +) -> Optional[CVProfile]: + stmt = select(CVProfile).where(CVProfile.filename == filename) + result = await db.execute(stmt) + return result.scalar_one_or_none() + + +async def get_profile_by_id( + db: AsyncSession, + profile_id: str, +) -> Optional[CVProfile]: + stmt = select(CVProfile).where(CVProfile.profile_id == profile_id) + result = await db.execute(stmt) + return result.scalar_one_or_none() + + +async def list_profiles( + db: AsyncSession, + limit: int = 50, + offset: int = 0, +) -> List[CVProfile]: + stmt = select(CVProfile).limit(limit).offset(offset) + result = await db.execute(stmt) + return result.scalars().all() + + +# ========================= +# FILTER & WEIGHT +# ========================= +from sqlalchemy import select, and_ +from sqlalchemy.ext.asyncio import AsyncSession + +async def get_filter( + db: AsyncSession, + filter: CVFilter, +): + conditions = [] + + # --- GPA --- + if filter.gpa_edu_1 is not None: + conditions.append(CVFilter.gpa_edu_1 >= filter.gpa_edu_1) + if filter.gpa_edu_2 is not None: + conditions.append(CVFilter.gpa_edu_2 >= filter.gpa_edu_2) + if filter.gpa_edu_3 is not None: + conditions.append(CVFilter.gpa_edu_3 >= filter.gpa_edu_3) + + # --- University --- + if filter.univ_edu_1: + conditions.append(CVFilter.univ_edu_1 == filter.univ_edu_1) + if filter.univ_edu_2: + conditions.append(CVFilter.univ_edu_2 == filter.univ_edu_2) + if filter.univ_edu_3: + conditions.append(CVFilter.univ_edu_3 == filter.univ_edu_3) + + # --- Major --- + if filter.major_edu_1: + conditions.append(CVFilter.major_edu_1 == filter.major_edu_1) + if filter.major_edu_2: + conditions.append(CVFilter.major_edu_2 == filter.major_edu_2) + if filter.major_edu_3: + conditions.append(CVFilter.major_edu_3 == filter.major_edu_3) + + # --- Others --- + if filter.domicile: + conditions.append(CVFilter.domicile == filter.domicile) + + if filter.yoe is not None: + conditions.append(CVFilter.yoe >= filter.yoe) + + # --- ARRAY fields (exact match) --- + if filter.hardskills: + conditions.append(CVFilter.hardskills == filter.hardskills) + + if filter.softskills: + conditions.append(CVFilter.softskills == filter.softskills) + + if filter.certifications: + conditions.append(CVFilter.certifications == filter.certifications) + + if filter.business_domain: + conditions.append(CVFilter.business_domain == filter.business_domain) + + # ⛔ Prevent full table scan + if not conditions: + return None + + stmt = select(CVFilter).where(and_(*conditions)) + result = await db.execute(stmt) + + return result.scalar_one_or_none() + + +async def get_filter_by_id( + db: AsyncSession, + criteria_id: str, +) -> Optional[CVFilter]: + stmt = select(CVFilter).where(CVFilter.criteria_id == criteria_id) + result = await db.execute(stmt) + return result.scalar_one_or_none() + + + +async def create_filter( + db: AsyncSession, + filter: CVFilter, +): + db.add(filter) + await db.commit() + return filter + + +async def get_filter_and_weight( + db: AsyncSession, + criteria_id: str, +): + stmt = ( + select(CVFilter, CVWeight) + .join(CVWeight, CVFilter.criteria_id == CVWeight.criteria_id) + .where(CVFilter.criteria_id == criteria_id) + ) + result = await db.execute(stmt) + return result.first() + + +async def get_weight_by_id( + db: AsyncSession, + weight_id: str, +): + stmt = ( + select(CVWeight) + .where(CVFilter.weight_id == weight_id) + ) + result = await db.execute(stmt) + return result.first() + + +async def create_filter_and_weight( + db: AsyncSession, + cv_filter: CVFilter, + cv_weight: CVWeight, +): + db.add_all([cv_filter, cv_weight]) + await db.commit() + +async def create_weight( + db: AsyncSession, + cv_weight: CVWeight, +): + db.add(cv_weight) + await db.commit() + + +# ========================= +# MATCHING +# ========================= + +async def create_matching( + db: AsyncSession, + matching: CVMatching, +) -> CVMatching: + db.add(matching) + await db.commit() + await db.refresh(matching) + return matching + + +async def get_matching_by_profile_and_criteria( + db: AsyncSession, + profile_id: str, + criteria_id: str, +) -> Optional[CVMatching]: + stmt = ( + select(CVMatching) + .where( + and_( + CVMatching.profile_id == profile_id, + CVMatching.criteria_id == criteria_id, + ) + ) + ) + result = await db.execute(stmt) + return result.scalar_one_or_none() + + +# ========================= +# SCORE +# ========================= + +async def create_score( + db: AsyncSession, + score: CVScore, +) -> CVScore: + db.add(score) + await db.commit() + await db.refresh(score) + return score + + +async def get_scores_by_criteria( + db: AsyncSession, + criteria_id: str, +) -> List[CVScore]: + stmt = ( + select(CVScore) + .join(CVMatching, CVScore.matching_id == CVMatching.matching_id) + .where(CVMatching.criteria_id == criteria_id) + .order_by(CVScore.score.desc()) + ) + result = await db.execute(stmt) + return result.scalars().all() \ No newline at end of file diff --git a/externals/databases/pg_models.py b/externals/databases/pg_models.py new file mode 100644 index 0000000000000000000000000000000000000000..12b4af534976a7917b00ddfd6748cc7f63071d5b --- /dev/null +++ b/externals/databases/pg_models.py @@ -0,0 +1,169 @@ +from config.get_config import master_config +from sqlalchemy import Column, String, Integer, TIMESTAMP, func +from sqlalchemy.dialects.postgresql import UUID, ARRAY, DOUBLE_PRECISION, BOOLEAN +from sqlalchemy.orm import declarative_base + + +Base = declarative_base() + +class CVUser(Base): + __tablename__ = "cv_user" + + user_id = Column(UUID(as_uuid=True), primary_key=True, server_default=func.uuid_generate_v4()) + username = Column(String, nullable=False, unique=True) + hashed_password = Column(String, nullable=False) + email = Column(String, nullable=False, unique=True) + full_name = Column(String, nullable=False) + role = Column(String, nullable=False) + is_active = Column(BOOLEAN, nullable=False) + tenant_id = Column(UUID(as_uuid=True), primary_key=False) + created_at = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + date_modified = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + notes = Column(String) + +class CVTenant(Base): + __tablename__ = "cv_tenant" + + tenant_id = Column(UUID(as_uuid=True), primary_key=True, server_default=func.uuid_generate_v4()) + tenant_name = Column(String, nullable=False, unique=True) + created_at = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + date_modified = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + notes = Column(String) + +class CVFile(Base): + __tablename__ = "cv_file" + file_id = Column(UUID(as_uuid=True), primary_key=True, server_default=func.uuid_generate_v4()) + user_id = Column(UUID(as_uuid=True), nullable=False) + file_type = Column(String, nullable=False) + filename = Column(String, nullable=False) + url = Column(String, nullable=False) + is_extracted = Column(BOOLEAN, nullable=False) + uploaded_at = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + date_modified = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + +class CVProfile(Base): + __tablename__ = "cv_profile" + + profile_id = Column(UUID(as_uuid=True), primary_key=True, server_default=func.uuid_generate_v4()) + fullname = Column(String, nullable=False) + + gpa_edu_1 = Column(DOUBLE_PRECISION) + univ_edu_1 = Column(String) + major_edu_1 = Column(String) + + gpa_edu_2 = Column(DOUBLE_PRECISION) + univ_edu_2 = Column(String) + major_edu_2 = Column(String) + + gpa_edu_3 = Column(DOUBLE_PRECISION) + univ_edu_3 = Column(String) + major_edu_3 = Column(String) + + domicile = Column(String) + yoe = Column(Integer) + + hardskills = Column(ARRAY(String)) + softskills = Column(ARRAY(String)) + certifications = Column(ARRAY(String)) + business_domain = Column(ARRAY(String)) + + filename = Column(String, nullable=False, unique=True) + file_id = Column(UUID(as_uuid=True), primary_key=False) + created_at = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + + +class CVFilter(Base): + __tablename__ = "cv_filter" + + criteria_id = Column(UUID(as_uuid=True), primary_key=True, server_default=func.uuid_generate_v4()) + + gpa_edu_1 = Column(DOUBLE_PRECISION) + gpa_edu_2 = Column(DOUBLE_PRECISION) + gpa_edu_3 = Column(DOUBLE_PRECISION) + + univ_edu_1 = Column(String) + univ_edu_2 = Column(String) + univ_edu_3 = Column(String) + + major_edu_1 = Column(String) + major_edu_2 = Column(String) + major_edu_3 = Column(String) + + domicile = Column(String) + yoe = Column(Integer) + + hardskills = Column(ARRAY(String)) + softskills = Column(ARRAY(String)) + certifications = Column(ARRAY(String)) + business_domain = Column(ARRAY(String)) + + created_at = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + + +class CVWeight(Base): + __tablename__ = "cv_weight" + + weight_id = Column(UUID(as_uuid=True), primary_key=True, server_default=func.uuid_generate_v4()) + criteria_id = Column(UUID(as_uuid=True), primary_key=True) + + gpa_edu_1 = Column(DOUBLE_PRECISION) + gpa_edu_2 = Column(DOUBLE_PRECISION) + gpa_edu_3 = Column(DOUBLE_PRECISION) + + univ_edu_1 = Column(DOUBLE_PRECISION) + univ_edu_2 = Column(DOUBLE_PRECISION) + univ_edu_3 = Column(DOUBLE_PRECISION) + + major_edu_1 = Column(DOUBLE_PRECISION) + major_edu_2 = Column(DOUBLE_PRECISION) + major_edu_3 = Column(DOUBLE_PRECISION) + + domicile = Column(DOUBLE_PRECISION) + yoe = Column(DOUBLE_PRECISION) + + hardskills = Column(DOUBLE_PRECISION) + softskills = Column(DOUBLE_PRECISION) + certifications = Column(DOUBLE_PRECISION) + business_domain = Column(DOUBLE_PRECISION) + + created_at = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + + +class CVMatching(Base): + __tablename__ = "cv_matching" + + matching_id = Column(UUID(as_uuid=True), primary_key=True, server_default=func.uuid_generate_v4()) + profile_id = Column(UUID(as_uuid=True)) + criteria_id = Column(UUID(as_uuid=True)) + + gpa_edu_1 = Column(BOOLEAN) + gpa_edu_2 = Column(BOOLEAN) + gpa_edu_3 = Column(BOOLEAN) + + univ_edu_1 = Column(BOOLEAN) + univ_edu_2 = Column(BOOLEAN) + univ_edu_3 = Column(BOOLEAN) + + major_edu_1 = Column(BOOLEAN) + major_edu_2 = Column(BOOLEAN) + major_edu_3 = Column(BOOLEAN) + + domicile = Column(BOOLEAN) + yoe = Column(BOOLEAN) + + hardskills = Column(BOOLEAN) + softskills = Column(BOOLEAN) + certifications = Column(BOOLEAN) + business_domain = Column(BOOLEAN) + + created_at = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) + + +class CVScore(Base): + __tablename__ = "cv_score" + + scoring_id = Column(UUID(as_uuid=True), primary_key=True, server_default=func.uuid_generate_v4()) + matching_id = Column(UUID(as_uuid=True)) + score = Column(Integer) + + created_at = Column(TIMESTAMP(timezone=True), server_default=master_config.JAKARTA_NOW) diff --git a/externals/databases/pg_schema_down.py b/externals/databases/pg_schema_down.py new file mode 100644 index 0000000000000000000000000000000000000000..d285f45a1e6fb88fba58df9477c6eef747c22010 --- /dev/null +++ b/externals/databases/pg_schema_down.py @@ -0,0 +1,33 @@ +import os +import dotenv +from config.constant import EnvPostgresConstants, EnvFilepath +dotenv.load_dotenv(EnvFilepath.ENVPATH) + +from sqlalchemy import create_engine, text +from externals.databases.pg_models import Base +from utils.logger import get_logger + + + +logger = get_logger("init schema") + +def drop_tables(): + try: + DATABASE_URL = EnvPostgresConstants.CONSTRING + engine = create_engine(DATABASE_URL) + + # Create extension + with engine.connect() as conn: + conn.execute(text('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";')) + conn.commit() + + # Create tables + Base.metadata.drop_all(engine) + logger.info("✅ drop schema success") + except Exception as E: + logger.error(f"❌ drop schema failed, {E}") + + + +if __name__ == "__main__": + drop_tables() \ No newline at end of file diff --git a/externals/databases/pg_schema_up.py b/externals/databases/pg_schema_up.py new file mode 100644 index 0000000000000000000000000000000000000000..7b3c7007cbde7d3aa71b46a3575ed2c75b7a7ee9 --- /dev/null +++ b/externals/databases/pg_schema_up.py @@ -0,0 +1,32 @@ +import os +import dotenv + +from config.constant import EnvPostgresConstants, EnvFilepath +dotenv.load_dotenv(EnvFilepath.ENVPATH) + +from externals.databases.pg_models import Base +from sqlalchemy import create_engine, text +from utils.logger import get_logger + +logger = get_logger("init schema") + + +def create_tables(): + try: + DATABASE_URL = EnvPostgresConstants.CONSTRING + engine = create_engine(DATABASE_URL) + + # Create extension + with engine.connect() as conn: + conn.execute(text('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";')) + conn.commit() + + # Create tables + Base.metadata.create_all(engine) + logger.info("✅ init schema success") + except Exception as E: + logger.error(f"❌ init schema failed, {E}") + + +if __name__ == "__main__": + create_tables() \ No newline at end of file diff --git a/externals/databases/schemas/__init__.py b/externals/databases/schemas/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/externals/databases/schemas/auth.py b/externals/databases/schemas/auth.py new file mode 100644 index 0000000000000000000000000000000000000000..69638f1f43ae2ddafc2116c7d773d35635f0e0d3 --- /dev/null +++ b/externals/databases/schemas/auth.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel, EmailStr + +class LoginRequest(BaseModel): + email: EmailStr + password: str + + +class TokenResponse(BaseModel): + access_token: str + token_type: str = "bearer" diff --git a/externals/databases/schemas/knowledge.py b/externals/databases/schemas/knowledge.py new file mode 100644 index 0000000000000000000000000000000000000000..77bac82d9d894290e2c518d0a9885280764b7349 --- /dev/null +++ b/externals/databases/schemas/knowledge.py @@ -0,0 +1,7 @@ +from pydantic import BaseModel +from typing import Any + +class ResponseGetProfile(BaseModel): + status: str + message: str + data: Any \ No newline at end of file diff --git a/externals/databases/schemas/tenant.py b/externals/databases/schemas/tenant.py new file mode 100644 index 0000000000000000000000000000000000000000..b5af23822d0a585ee7a6816580c8e2655f034235 --- /dev/null +++ b/externals/databases/schemas/tenant.py @@ -0,0 +1,29 @@ +from uuid import UUID +from typing import Optional +from datetime import datetime + +from pydantic import BaseModel, Field + + +# ---------- REQUEST ---------- +class TenantCreate(BaseModel): + tenant_name: str = Field(..., min_length=3, max_length=100) + notes: Optional[str] = None + + +# ---------- UPDATE (OPTIONAL) ---------- +class TenantUpdate(BaseModel): + tenant_name: Optional[str] = Field(None, min_length=3, max_length=100) + notes: Optional[str] = None + + +# ---------- RESPONSE ---------- +class TenantResponse(BaseModel): + tenant_id: UUID + tenant_name: str + created_at: datetime + date_modified: datetime + notes: Optional[str] = None + + class Config: + from_attributes = True # Pydantic v2 (ORM support) diff --git a/externals/databases/schemas/user.py b/externals/databases/schemas/user.py new file mode 100644 index 0000000000000000000000000000000000000000..ce994ebee65727d23353fd089ce1b77290659426 --- /dev/null +++ b/externals/databases/schemas/user.py @@ -0,0 +1,30 @@ +from uuid import UUID +from typing import Optional +from datetime import datetime +from pydantic import BaseModel, EmailStr + + +# ---------- REQUEST ---------- +class UserCreate(BaseModel): + username: str + password: str + email: EmailStr + full_name: str + role: str + tenant_id: Optional[UUID] = None + notes: Optional[str] = None + + +# ---------- RESPONSE ---------- +class UserResponse(BaseModel): + user_id: UUID + username: str + email: EmailStr + full_name: str + role: str + is_active: bool + tenant_id: Optional[UUID] + created_at: datetime + + class Config: + from_attributes = True # ⬅️ WAJIB (SQLAlchemy → Pydantic) diff --git a/externals/observability/__init__.py b/externals/observability/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/externals/observability/langfuse.py b/externals/observability/langfuse.py new file mode 100644 index 0000000000000000000000000000000000000000..f31c9224ccc815650c82d0156fd5281e696e84ce --- /dev/null +++ b/externals/observability/langfuse.py @@ -0,0 +1,16 @@ +import os +import dotenv +from config.constant import EnvFilepath +dotenv.load_dotenv(EnvFilepath.ENVPATH) +from langfuse import Langfuse +from langchain_core.callbacks.base import BaseCallbackHandler + + +langfuse = Langfuse( + secret_key=os.environ.get('ss--langfuse--secret-key'), + public_key=os.environ.get('ss--langfuse--public-key'), + host=os.environ.get('langfuse--host'), +) + + +langfuse_handler = BaseCallbackHandler() diff --git a/externals/storages/azure_blob.py b/externals/storages/azure_blob.py new file mode 100644 index 0000000000000000000000000000000000000000..adb47084bcd9671340616eba5e10e38fb7c486a3 --- /dev/null +++ b/externals/storages/azure_blob.py @@ -0,0 +1,183 @@ +import os +import uuid +from typing import List, Dict, Any + +from azure.identity.aio import DefaultAzureCredential +from azure.storage.blob.aio import BlobServiceClient, ContainerClient +from fastapi import UploadFile, HTTPException, status + +from config.constant import AzureBlobConstants +from utils.logger import get_logger + +logger = get_logger("azure-blob") + +# ---------- SINGLETONS ---------- +_blob_service_client: BlobServiceClient | None = None +_credential: DefaultAzureCredential | None = None + + +async def get_blob_service_client() -> BlobServiceClient: + global _blob_service_client, _credential + + if _blob_service_client is None: + _credential = DefaultAzureCredential() + _blob_service_client = BlobServiceClient( + account_url=AzureBlobConstants.ENDPOINT, + credential=_credential, + ) + logger.info("✅ Azure BlobServiceClient initialized") + + return _blob_service_client + + +async def get_container_client() -> ContainerClient: + service = await get_blob_service_client() + container = service.get_container_client( + AzureBlobConstants.CONTAINER_NAME + ) + + try: + await container.create_container() + logger.info("✅ Blob container created") + except Exception: + pass # already exists + + return container + + +# ---------- HELPERS ---------- +def build_blob_path(filename: str) -> str: + return f"{AzureBlobConstants.BLOB_PREFIX}/{filename}" + + +# ---------- UPLOAD ---------- +# async def upload_pdf( +# file: UploadFile, +# ) -> Dict[str, Any]: + +# if file.content_type != "application/pdf": +# raise HTTPException( +# status_code=status.HTTP_400_BAD_REQUEST, +# detail="Only PDF files are allowed", +# ) + +# container = await get_container_client() + +# blob_name = f"{uuid.uuid4()}.pdf" +# blob_path = build_blob_path(blob_name) + +# blob_client = container.get_blob_client(blob_path) + +# size = 0 +# chunks = [] + +# async for chunk in file.stream(): +# size += len(chunk) +# if size > AzureBlobConstants.MAX_FILE_SIZE_MB * 1024 * 1024: +# raise HTTPException( +# status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, +# detail="File too large", +# ) +# chunks.append(chunk) + +# await blob_client.upload_blob( +# b"".join(chunks), +# overwrite=False, +# content_type="application/pdf", +# ) + +# logger.info(f"✅ Uploaded PDF: {blob_path}") + +# return { +# "blob_name": blob_name, +# "path": blob_path, +# "url": blob_client.url, +# "size_bytes": size, +# } +def helper_path_maker( + tenant_id: str, + user_id: str, + filename: str, + in_folder: str = AzureBlobConstants.BLOB_PREFIX, +): + return f"{in_folder}/{tenant_id}/{user_id}/{filename}" + + +from azure.storage.blob import ContentSettings + +async def upload_pdf(file: UploadFile, tenant_id: str, user_id: str) -> dict: + container_client = await get_container_client() + blob_name = helper_path_maker(tenant_id, user_id, file.filename) + + blob_client = container_client.get_blob_client(blob_name) + + await file.seek(0) + + await blob_client.upload_blob( + data=_file_chunk_generator(file), + overwrite=True, + content_settings=ContentSettings( + content_type=file.content_type or "application/pdf" + ), + ) + + return { + "filename": file.filename, + "uploaded": True, + "url": blob_client.url, + } + + +async def _file_chunk_generator(file: UploadFile): + while True: + chunk = await file.read(AzureBlobConstants.CHUNK_SIZE) + if not chunk: + break + yield chunk + + +async def delete_blob_by_filename(filename: str, tenant_id: str, user_id: str) -> bool: + container = await get_container_client() + blob_path = helper_path_maker(tenant_id=tenant_id, + user_id=user_id, + filename=filename) + + blob_client = container.get_blob_client(blob_path) + + try: + await blob_client.delete_blob() + logger.info( + "azure.blob.delete.success", + extra={"cv_filename": filename}, + ) + return True + except Exception as e: + logger.error( + "azure.blob.delete.failed", + extra={ + "cv_filename": filename, + "error": str(e), + }, + ) + return False + + + +async def download_blob_by_filename(filename: str, tenant_id: str, user_id: str) -> bytes: + """ + Download file from Azure Blob Storage by filename + Return raw bytes + """ + try: + container_client = await get_container_client() + blob_name = helper_path_maker(tenant_id, user_id, filename) + + blob_client = container_client.get_blob_client(blob_name) + + downloader = await blob_client.download_blob() + file_bytes:bytes = await downloader.readall() + + return file_bytes + + except Exception as e: + raise RuntimeError(f"Failed to download blob '{filename}': {str(e)}") \ No newline at end of file diff --git a/externals/storages/azure_generate_sas.py b/externals/storages/azure_generate_sas.py new file mode 100644 index 0000000000000000000000000000000000000000..80d1aac571d98ab1b30ecc94bbdbccc5fb64a2a3 --- /dev/null +++ b/externals/storages/azure_generate_sas.py @@ -0,0 +1,52 @@ +from azure.identity import AzureCliCredential +from azure.storage.blob import ( + BlobServiceClient, + generate_blob_sas, + BlobSasPermissions, +) +from config.constant import AzureBlobConstants +from config.get_config import master_config +from datetime import datetime, timedelta +from urllib.parse import quote +from urllib.parse import urlparse + + +async def get_blob_sas_url(blob_name:str, + account_name:str=AzureBlobConstants.ACCOUNT_NAME, + container_name:str=AzureBlobConstants.CONTAINER_NAME): + + try: + blob_name = blob_name.replace('%20', ' ') + blob_name = urlparse(blob_name).path + + permissions = BlobSasPermissions(read=True) + + expiry = datetime.now(master_config.tzinfo) + timedelta(hours=1) + + credential = AzureCliCredential() + + account_url = f"https://{account_name}.blob.core.windows.net" + service_client = BlobServiceClient(account_url=account_url, credential=credential) + + start_time = datetime.now(master_config.tzinfo) - timedelta(minutes=5) + udk = service_client.get_user_delegation_key(key_start_time=start_time, key_expiry_time=expiry) + + sas_token = generate_blob_sas( + account_name=account_name, + container_name=container_name, + blob_name=blob_name, + permission=permissions, + start=start_time, + expiry=expiry, + user_delegation_key=udk, + protocol="https", + ) + + # Build a URL-safe path (encode reserved characters) + encoded_blob_name = quote(blob_name, safe="/") # keep '/' but encode spaces, etc. + blob_url_with_sas = f"{account_url}/{container_name}/{encoded_blob_name}?{sas_token}" + + return blob_url_with_sas + except Exception as E: + print("Error generating SAS URL:", str(E)) + return None \ No newline at end of file diff --git a/interfaces/__init__.py b/interfaces/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/interfaces/api/agentic.py b/interfaces/api/agentic.py new file mode 100644 index 0000000000000000000000000000000000000000..d09a582dff8fd3b4439fda2c8c34e1acb02a29cb --- /dev/null +++ b/interfaces/api/agentic.py @@ -0,0 +1,247 @@ +import time +from fastapi import APIRouter +from uuid import uuid4 +# from externals.databases.pg_crud import get_all_cv_profiles, get_cv_profile_with_scores +from externals.databases.database import get_db +from services.agentic.agentic_setup import AgenticService +from services.knowledge.knowledge_setup import KnowledgeService +from services.models.data_model import (Criteria, + CriteriaWeight, + PayloadMatchOne, + ResponseMatchOne, + DataResponseMatchOne, + PayloadMatchBulk, + ResponseMatchBulk, + DataResponseMatchBulk) +from interfaces.api.deps import get_current_user +from fastapi import APIRouter, UploadFile, File, Depends, status, HTTPException +from externals.databases.pg_models import CVUser, CVFilter, CVWeight + +from utils.logger import get_logger + +logger = get_logger("agentic service") +router = APIRouter( + prefix="/agentic", + tags=["Agentic"], +) + + +@router.post("/create_filter") +async def create_filter( + filter: Criteria, + db=Depends(get_db), + current_user: CVUser = Depends(get_current_user), +): + try: + agentic_service = AgenticService(db=db, + user=current_user) + + cv_filter = CVFilter( + criteria_id=uuid4(), + + gpa_edu_1=filter.get("gpa_edu_1"), + gpa_edu_2=filter.get("gpa_edu_2"), + gpa_edu_3=filter.get("gpa_edu_3"), + + univ_edu_1=filter.get("univ_edu_1"), + univ_edu_2=filter.get("univ_edu_2"), + univ_edu_3=filter.get("univ_edu_3"), + + major_edu_1=filter.get("major_edu_1"), + major_edu_2=filter.get("major_edu_2"), + major_edu_3=filter.get("major_edu_3"), + + domicile=filter.get("domicile"), + yoe=filter.get("yoe"), + + hardskills=filter.get("hardskills"), + softskills=filter.get("softskills"), + certifications=filter.get("certifications"), + business_domain=filter.get("business_domain") + ) + + logger.info(f"cv_filter: {cv_filter}") + + data = await agentic_service.filter.create_filter(filter=cv_filter) + return { + "status": "success", + "message": "Filter created successfully", + "criteria_id": data + } + except Exception as E: + logger.error(f"create filter error: {E}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"create filter error: {E}" + ) + + +@router.get("/filter/{criteria_id}") +async def get_filter_by_id( + criteria_id: str, + db=Depends(get_db), + current_user: CVUser = Depends(get_current_user), +): + agentic_service = AgenticService(db=db, + user=current_user) + + data = await agentic_service.filter.get_filter_by_id(criteria_id=criteria_id) + return data + + + +@router.post("/create_weight") +async def create_weight( + criteria_id: str, + weight: CriteriaWeight, + db=Depends(get_db), + current_user: CVUser = Depends(get_current_user), +): + try: + agentic_service = AgenticService(db=db, + user=current_user) + + cv_weight = CVWeight( + criteria_id=criteria_id, + + gpa_edu_1=weight.get("gpa_edu_1"), + gpa_edu_2=weight.get("gpa_edu_2"), + gpa_edu_3=weight.get("gpa_edu_3"), + + univ_edu_1=weight.get("univ_edu_1"), + univ_edu_2=weight.get("univ_edu_2"), + univ_edu_3=weight.get("univ_edu_3"), + + major_edu_1=weight.get("major_edu_1"), + major_edu_2=weight.get("major_edu_2"), + major_edu_3=weight.get("major_edu_3"), + + domicile=weight.get("domicile"), + yoe=weight.get("yoe"), + + hardskills=weight.get("hardskills"), + softskills=weight.get("softskills"), + certifications=weight.get("certifications"), + business_domain=weight.get("business_domain") + ) + + logger.info(f"cv_weight: {cv_weight}") + + data = await agentic_service.weight.create_weight(weight=cv_weight) + return { + "status": "success", + "message": "Weight created successfully", + "criteria_id": data + } + except Exception as E: + logger.error(f"create weight error: {E}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"create weight error: {E}" + ) + + +@router.post("/calculate_score") +async def calculate_score( + weight_id: str, + db=Depends(get_db), + current_user: CVUser = Depends(get_current_user), +): + # TODO: endpoint to calculate profile matching + pass + + +# @router.get("/get_profile_table") +# async def get_profile_table( +# limit: int, +# ): +# data = await get_all_cv_profiles(limit) +# return data + + +# @router.get("/get_profile_table_and_score") +# async def get_profile_table_and_score( +# criteria_id: str, +# profile_id: str, +# ): +# data = await get_cv_profile_with_scores( +# criteria_id=criteria_id, +# profile_id=profile_id, +# ) +# return data + + +# @router.post("/match_one") +# async def profile_matching_one( +# payload: PayloadMatchOne, +# ): +# """ +# Generate profile matching score between one profile and one criteria. + +# Returns: +# status: str +# message: str +# data: DataResponseExtractOne +# """ +# _start = time.time() +# try: +# agentic = Agent() +# response = await agentic.scoring_profile(input_scoring=payload) +# print(f"response match one profile:", response) +# _end = time.time() - _start +# logger.info(f"API runtime profile scoring: {_end}s") + +# return response +# except Exception as E: +# logger.error(f"profile scoring error, {E}") + +# _end = time.time() - _start +# logger.info(f"API runtime profile scoring: {_end}s") + +# return ResponseMatchOne( +# status="failed", +# message=f"profile scoring error, {E}", +# data=DataResponseMatchOne( +# profile_id=payload.get("profile_id"), +# criteria_id=payload.get("criteria").get("criteria_id"), +# score=0 +# ) +# ) + + +# @router.post("/match_bulk") +# async def profile_matching_bulk( +# payload: PayloadMatchBulk, +# ): +# """ +# Generate profile matching score between many profiles and one criteria. + +# Returns: +# status: str +# message: str +# data: DataResponseExtractOne +# """ +# _start = time.time() +# try: +# agentic = Agent() +# response = await agentic.scoring_profile(input_scoring=payload) +# print(f"response match one profile:", response) +# _end = time.time() - _start +# logger.info(f"API runtime profile scoring: {_end}s") + +# return response +# except Exception as E: +# logger.error(f"profile scoring error, {E}") + +# _end = time.time() - _start +# logger.info(f"API runtime profile scoring: {_end}s") + +# return ResponseMatchBulk( +# status="failed", +# message=f"profile scoring error, {E}", +# data=DataResponseMatchBulk( +# profile_id=payload.get("profile_id"), +# criteria_id=payload.get("criteria").get("criteria_id"), +# score=0 +# ) +# ) \ No newline at end of file diff --git a/interfaces/api/deps.py b/interfaces/api/deps.py new file mode 100644 index 0000000000000000000000000000000000000000..4f78886f89a0c498b474369d7f9f1031e54f8801 --- /dev/null +++ b/interfaces/api/deps.py @@ -0,0 +1,40 @@ +from config.constant import SecurityConstants +from externals.databases.pg_crud import get_user_by_id +from externals.databases.database import get_db +from fastapi import Depends, HTTPException, status +from fastapi.security import OAuth2PasswordBearer +from jose import jwt, JWTError +from sqlalchemy.ext.asyncio import AsyncSession + + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/admin/login") + + +async def get_current_user( + token: str = Depends(oauth2_scheme), + db: AsyncSession = Depends(get_db), +): + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": "Bearer"}, + ) + + try: + payload = jwt.decode( + token, + SecurityConstants.JWT_SECRET_KEY, + algorithms=[SecurityConstants.JWT_ALGORITHM], + ) + user_id: str | None = payload.get("sub") + if user_id is None: + raise credentials_exception + + except JWTError: + raise credentials_exception + + user = await get_user_by_id(db, user_id) + if not user: + raise credentials_exception + + return user \ No newline at end of file diff --git a/interfaces/api/file.py b/interfaces/api/file.py new file mode 100644 index 0000000000000000000000000000000000000000..4a8b4e2880bab2c3f9f36f3029721fad407a5d2d --- /dev/null +++ b/interfaces/api/file.py @@ -0,0 +1,107 @@ +from externals.databases.database import get_db +from fastapi import APIRouter, UploadFile, File, Depends, status, HTTPException +from interfaces.api.deps import get_current_user +from services.knowledge.knowledge_setup import KnowledgeService +from typing import List +from utils.logger import get_logger + + +logger = get_logger("File API") + +router = APIRouter( + prefix="/file", + tags=["File"], +) + + +@router.post( + "/upload", + status_code=status.HTTP_201_CREATED, + summary="Upload multiple PDF knowledge files", +) +async def upload_knowledge_many( + files: List[UploadFile] = File(...), + db=Depends(get_db), + current_user=Depends(get_current_user), +): + """ + Upload multiple PDF files to Azure Blob Storage and log metadata. + """ + + knowledge_service = KnowledgeService( + db=db, + user=current_user, + ) + + results = [] + for file in files: + if file.content_type != "application/pdf": + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"File '{file.filename}' is not a PDF", + ) + else: + result = await knowledge_service.file.upload(file) + results.append(result) + + return { + "message": "Upload completed", + "uploaded_by": current_user.email, + "files": results, + } + +@router.get( + "/{user_id}", + status_code=status.HTTP_200_OK, + summary="Get file metadata by user ID", +) +async def get_file_metadata_by_user( + user_id: str, + db=Depends(get_db), + current_user=Depends(get_current_user), +): + """ + Retrieve all file metadata uploaded by a specific user. + """ + + knowledge_service = KnowledgeService( + db=db, + user=current_user, + ) + + files = await knowledge_service.file.get_files_by_user(user_id) + + return { + "message": "File metadata retrieved successfully", + "requested_by": current_user.email, + "files": files, + } + + +@router.delete( + "/{filename}", + status_code=status.HTTP_200_OK, + summary="Delete knowledge file by filename", +) +async def delete_knowledge_file( + filename: str, + db=Depends(get_db), + current_user=Depends(get_current_user), +): + """ + Delete a PDF knowledge file from Azure Blob and database. + """ + + knowledge_service = KnowledgeService( + db=db, + user=current_user, + ) + + await knowledge_service.delete.delete(filename) + + return { + "message": "File deleted successfully", + "filename": filename, + "deleted_by": current_user.email, + } + diff --git a/interfaces/api/profile.py b/interfaces/api/profile.py new file mode 100644 index 0000000000000000000000000000000000000000..e9ab3776b92be129f501c053e30e3223d36f9f2c --- /dev/null +++ b/interfaces/api/profile.py @@ -0,0 +1,62 @@ +from externals.databases.pg_models import CVUser +from externals.databases.database import get_db +from fastapi import APIRouter, Depends, status, HTTPException +from interfaces.api.deps import get_current_user +from services.knowledge.knowledge_setup import KnowledgeService +from utils.logger import get_logger + + +logger = get_logger("Profile API") + +router = APIRouter( + prefix="/profile", + tags=["Profile"], +) + +@router.post("/extract_profile") +async def extract_profile( + filename: str, + db=Depends(get_db), + current_user: CVUser = Depends(get_current_user), +): + """ + Extract structured profile from CV PDF + """ + + knowledge_service = KnowledgeService( + db=db, + user=current_user, + ) + + return await knowledge_service.extract.extract(filename) + + + +@router.get("/{profile_id}") +async def get_profile( + profile_id: str, + current_user: CVUser = Depends(get_current_user), +): + """ + Get extracted profile by ID + """ + knowledge_service = KnowledgeService(user=current_user) + + profile = await knowledge_service.profile.get_profile(profile_id) + + if not profile: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Profile not found", + ) + + # 🔒 Tenant isolation (IMPORTANT) + if profile.tenant_id != current_user.tenant_id: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Not authorized to access this profile", + ) + + return profile + + diff --git a/interfaces/api/tenant.py b/interfaces/api/tenant.py new file mode 100644 index 0000000000000000000000000000000000000000..7286a971935996ac887ff81a943e86c5f7906940 --- /dev/null +++ b/interfaces/api/tenant.py @@ -0,0 +1,57 @@ +from externals.databases.database import get_db +from externals.databases.pg_crud import ( + get_tenant_by_name, + create_tenant, +) +from externals.databases.schemas.tenant import TenantCreate, TenantResponse +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.ext.asyncio import AsyncSession +from utils.logger import get_logger + + +logger = get_logger("tenant management") +router = APIRouter(prefix="/admin", tags=["Tenant"]) + + +# CREATE TENANT +@router.post( + "/tenants", + status_code=status.HTTP_201_CREATED, + response_model=TenantResponse, +) +async def create_tenant_endpoint( + tenant: TenantCreate, + db: AsyncSession = Depends(get_db), +): + logger.info("Create tenant request", extra={"tenant_name": tenant.tenant_name}) + + existing = await get_tenant_by_name(db, tenant.tenant_name) + if existing: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail="Tenant already exists", + ) + + created = await create_tenant(db, tenant) + return created + + +# GET TENANT BY NAME +@router.get( + "/tenants/{tenant_name}", + response_model=TenantResponse, +) +async def get_tenant_endpoint( + tenant_name: str, + db: AsyncSession = Depends(get_db), +): + logger.info("Get tenant request", extra={"tenant_name": tenant_name}) + + tenant = await get_tenant_by_name(db, tenant_name) + if not tenant: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Tenant not found", + ) + + return tenant diff --git a/interfaces/api/user.py b/interfaces/api/user.py new file mode 100644 index 0000000000000000000000000000000000000000..0e83901366694cef25209bc989e91a7e6b4ecc66 --- /dev/null +++ b/interfaces/api/user.py @@ -0,0 +1,104 @@ +from externals.databases.database import get_db +from externals.databases.pg_crud import ( + get_user_by_username, + create_user, + get_user_by_email, + # deactivate_user, + # get_tenant_by_name, + # create_tenant, +) +from externals.databases.schemas.user import UserCreate, UserResponse +from externals.databases.schemas.auth import LoginRequest, TokenResponse +from fastapi import APIRouter, Depends, HTTPException, status +from fastapi.security import OAuth2PasswordRequestForm +from sqlalchemy.ext.asyncio import AsyncSession +from utils.logger import get_logger +from utils.security import verify_password +from utils.jwt import create_access_token + + +logger = get_logger("user management") +router = APIRouter(prefix="/admin", tags=["User"]) + + + +@router.post( + "/users", + status_code=status.HTTP_201_CREATED, + response_model=UserResponse, +) +async def create_user_endpoint( + user: UserCreate, + db: AsyncSession = Depends(get_db), +): + logger.info("Create user request", extra={"username": user.username}) + + existing = await get_user_by_username(db, user.username) + if existing: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail="Username already exists", + ) + + return await create_user(db, user) + + + +# @router.get( +# "/users/{username}", +# response_model=UserResponse, +# ) +# async def get_user_endpoint( +# username: str, +# db: AsyncSession = Depends(get_db), +# ): +# logger.info("Get user request", extra={"username": username}) + +# user = await get_user_by_username(db, username) +# if not user: +# raise HTTPException( +# status_code=status.HTTP_404_NOT_FOUND, +# detail="User not found", +# ) + +# return user + + +@router.post("/login", response_model=TokenResponse) +async def login( + form_data: OAuth2PasswordRequestForm = Depends(), + db: AsyncSession = Depends(get_db), +): + user = await get_user_by_email(db, form_data.username) + + if not user or not verify_password(form_data.password, user.hashed_password): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid email or password", + ) + + token = create_access_token( + data={ + "sub": str(user.user_id), + "email": user.email, + "role": user.role, + "full_name": user.full_name, + } + ) + + return TokenResponse(access_token=token) + + + +from interfaces.api.deps import get_current_user + +@router.get("/me", response_model=UserResponse) +async def get_me( + current_user: UserResponse = Depends(get_current_user), +): + logger.info( + "Get current user", + extra={"user_id": current_user.user_id}, + ) + + return current_user \ No newline at end of file diff --git a/interfaces/auth/auth.py b/interfaces/auth/auth.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/interfaces/handlers/agentic_handlers.py b/interfaces/handlers/agentic_handlers.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/interfaces/handlers/handlers.py b/interfaces/handlers/handlers.py new file mode 100644 index 0000000000000000000000000000000000000000..139597f9cb07c5d48bed18984ec4747f4b4f3438 --- /dev/null +++ b/interfaces/handlers/handlers.py @@ -0,0 +1,2 @@ + + diff --git a/interfaces/handlers/knowledge_handlers.py b/interfaces/handlers/knowledge_handlers.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/interfaces/middlewares/cors.py b/interfaces/middlewares/cors.py new file mode 100644 index 0000000000000000000000000000000000000000..cf5ce287fbe0552ad50c8c1f664f50624ddc1c09 --- /dev/null +++ b/interfaces/middlewares/cors.py @@ -0,0 +1,8 @@ +from fastapi.middleware.cors import CORSMiddleware + +cors_context = {"middleware_class":CORSMiddleware, + "allow_origins": ["*"], + "allow_credentials": True, + "allow_methods": ["*"], + "allow_headers": ["*"] + } \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000000000000000000000000000000000000..405e3917b44482cd60dac565ec81c3b510de1616 --- /dev/null +++ b/main.py @@ -0,0 +1,39 @@ +from interfaces.middlewares.cors import cors_context +from interfaces.api.user import router as router_user +from interfaces.api.tenant import router as router_tenant +from interfaces.api.file import router as router_file +from interfaces.api.profile import router as router_profile +from interfaces.api.agentic import router as router_agentic +from fastapi import FastAPI +from fastapi.responses import JSONResponse + + +# ====================== APP ====================== +app = FastAPI( + title="Candidate Explorer Service", + description="Candidate Explorer Service", + docs_url="/docs", + root_path="/" + ) +app.add_middleware(**cors_context) + +# ====================== ROUTES ====================== +app.include_router(router_tenant) +app.include_router(router_user) +app.include_router(router_file) +app.include_router(router_profile) +app.include_router(router_agentic) + + +# ====================== HEALTHCHECK & INFO ====================== +@app.get("/health/ready") +def health_ready(): + return JSONResponse(content="Ready", status_code=200) + +@app.get("/health/live") +def health_live(): + return JSONResponse(content="Live", status_code=200) + +@app.get("/info") +async def info_endpoint(): + return {"agentId": "candidate-explorer-agent", "status":"Online", "description": "agent candidate explorer!"} diff --git a/models/security.py b/models/security.py new file mode 100644 index 0000000000000000000000000000000000000000..e913418d0cc0d7f9cc79152274e573a83a597ce3 --- /dev/null +++ b/models/security.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel + +class TokenRequest(BaseModel): + username: str + password: str + +class TokenResponse(BaseModel): + access_token: str + token_type: str = "bearer" + expires_in: int \ No newline at end of file diff --git a/playground/playground.py b/playground/playground.py new file mode 100644 index 0000000000000000000000000000000000000000..24073a266b90be2d80d1b08f5eeb08dfa9462101 --- /dev/null +++ b/playground/playground.py @@ -0,0 +1,7 @@ +import requests + +url = "https://api.typeform.com/responses/files/9223d2c317a66c9e7b0cfe2514d9f622c2be0568164be3fa7eb6e0a148a2b5f0/CV_Abdurahman_Wal_Ikram.pdf" + +res = requests.get(url=url) + +type(res.content) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..bdc91f11d02935c0a1fc74fc05be86dee28e0a55 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,31 @@ +[project] +name = "service.explorer.backend" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "aiohttp>=3.13.2", + "asyncpg>=0.31.0", + "azure-identity>=1.25.1", + "azure-storage-blob>=12.20.0", + "bcrypt==3.2.2", + "dotenv>=0.9.9", + "fastapi[standard]>=0.127.0", + "frontend>=0.0.3", + "langchain>=1.2.0", + "langchain-openai>=1.1.6", + "langfuse==2.33.0", + "pandas>=2.3.3", + "passlib==1.7.4", + "pdf2image>=1.17.0", + "psycopg2>=2.9.11", + "pymupdf>=1.26.7", + "pypdf>=6.5.0", + "pypdf2>=3.0.1", + "pytesseract>=0.3.13", + "python-jose[cryptography]>=3.5.0", + "pytz>=2025.2", + "sqlalchemy>=2.0.45", + "uvicorn>=0.40.0", +] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1eedc48871c549d796e7502fdaa1c04afcdd0e2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,356 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml -o requirements.txt +aiofiles==25.1.0 + # via frontend +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.13.3 + # via service-explorer-backend (pyproject.toml) +aiosignal==1.4.0 + # via aiohttp +annotated-doc==0.0.4 + # via + # fastapi + # typer +annotated-types==0.7.0 + # via pydantic +anyio==4.12.1 + # via + # httpx + # openai + # starlette + # watchfiles +asyncpg==0.31.0 + # via service-explorer-backend (pyproject.toml) +attrs==25.4.0 + # via aiohttp +azure-core==1.38.2 + # via + # azure-identity + # azure-storage-blob +azure-identity==1.25.2 + # via service-explorer-backend (pyproject.toml) +azure-storage-blob==12.28.0 + # via service-explorer-backend (pyproject.toml) +backoff==2.2.1 + # via langfuse +bcrypt==3.2.2 + # via service-explorer-backend (pyproject.toml) +certifi==2026.1.4 + # via + # httpcore + # httpx + # requests + # sentry-sdk +cffi==2.0.0 + # via + # bcrypt + # cryptography +charset-normalizer==3.4.4 + # via requests +click==8.3.1 + # via + # rich-toolkit + # typer + # uvicorn +colorama==0.4.6 + # via + # click + # tqdm + # uvicorn +cryptography==46.0.5 + # via + # azure-identity + # azure-storage-blob + # msal + # pyjwt + # python-jose +distro==1.9.0 + # via openai +dnspython==2.8.0 + # via email-validator +dotenv==0.9.9 + # via service-explorer-backend (pyproject.toml) +ecdsa==0.19.1 + # via python-jose +email-validator==2.3.0 + # via + # fastapi + # pydantic +fastapi==0.129.0 + # via service-explorer-backend (pyproject.toml) +fastapi-cli==0.0.23 + # via fastapi +fastapi-cloud-cli==0.13.0 + # via fastapi-cli +fastar==0.8.0 + # via fastapi-cloud-cli +frontend==0.0.3 + # via service-explorer-backend (pyproject.toml) +frozenlist==1.8.0 + # via + # aiohttp + # aiosignal +greenlet==3.3.1 + # via sqlalchemy +h11==0.16.0 + # via + # httpcore + # uvicorn +httpcore==1.0.9 + # via httpx +httptools==0.7.1 + # via uvicorn +httpx==0.28.1 + # via + # fastapi + # fastapi-cloud-cli + # langfuse + # langgraph-sdk + # langsmith + # openai +idna==3.11 + # via + # anyio + # email-validator + # httpx + # langfuse + # requests + # yarl +isodate==0.7.2 + # via azure-storage-blob +itsdangerous==2.2.0 + # via frontend +jinja2==3.1.6 + # via fastapi +jiter==0.13.0 + # via openai +jsonpatch==1.33 + # via langchain-core +jsonpointer==3.0.0 + # via jsonpatch +langchain==1.2.10 + # via service-explorer-backend (pyproject.toml) +langchain-core==1.2.14 + # via + # langchain + # langchain-openai + # langgraph + # langgraph-checkpoint + # langgraph-prebuilt +langchain-openai==1.1.10 + # via service-explorer-backend (pyproject.toml) +langfuse==2.33.0 + # via service-explorer-backend (pyproject.toml) +langgraph==1.0.9 + # via langchain +langgraph-checkpoint==4.0.0 + # via + # langgraph + # langgraph-prebuilt +langgraph-prebuilt==1.0.8 + # via langgraph +langgraph-sdk==0.3.8 + # via langgraph +langsmith==0.7.5 + # via langchain-core +markdown-it-py==4.0.0 + # via rich +markupsafe==3.0.3 + # via jinja2 +mdurl==0.1.2 + # via markdown-it-py +msal==1.34.0 + # via + # azure-identity + # msal-extensions +msal-extensions==1.3.1 + # via azure-identity +multidict==6.7.1 + # via + # aiohttp + # yarl +numpy==2.4.2 + # via pandas +openai==2.21.0 + # via langchain-openai +orjson==3.11.7 + # via + # langgraph-sdk + # langsmith +ormsgpack==1.12.2 + # via langgraph-checkpoint +packaging==23.2 + # via + # langchain-core + # langfuse + # langsmith + # pytesseract +pandas==3.0.1 + # via service-explorer-backend (pyproject.toml) +passlib==1.7.4 + # via service-explorer-backend (pyproject.toml) +pdf2image==1.17.0 + # via service-explorer-backend (pyproject.toml) +pillow==12.1.1 + # via + # pdf2image + # pytesseract +propcache==0.4.1 + # via + # aiohttp + # yarl +psycopg2==2.9.11 + # via service-explorer-backend (pyproject.toml) +pyasn1==0.6.2 + # via + # python-jose + # rsa +pycparser==3.0 + # via cffi +pydantic==2.12.5 + # via + # fastapi + # fastapi-cloud-cli + # langchain + # langchain-core + # langfuse + # langgraph + # langsmith + # openai + # pydantic-extra-types + # pydantic-settings +pydantic-core==2.41.5 + # via pydantic +pydantic-extra-types==2.11.0 + # via fastapi +pydantic-settings==2.13.1 + # via fastapi +pygments==2.19.2 + # via rich +pyjwt==2.11.0 + # via msal +pymupdf==1.27.1 + # via service-explorer-backend (pyproject.toml) +pypdf==6.7.1 + # via service-explorer-backend (pyproject.toml) +pypdf2==3.0.1 + # via service-explorer-backend (pyproject.toml) +pytesseract==0.3.13 + # via service-explorer-backend (pyproject.toml) +python-dateutil==2.9.0.post0 + # via pandas +python-dotenv==1.2.1 + # via + # dotenv + # pydantic-settings + # uvicorn +python-jose==3.5.0 + # via service-explorer-backend (pyproject.toml) +python-multipart==0.0.22 + # via fastapi +pytz==2025.2 + # via service-explorer-backend (pyproject.toml) +pyyaml==6.0.3 + # via + # langchain-core + # uvicorn +regex==2026.2.19 + # via tiktoken +requests==2.32.5 + # via + # azure-core + # langsmith + # msal + # requests-toolbelt + # tiktoken +requests-toolbelt==1.0.0 + # via langsmith +rich==14.3.3 + # via + # rich-toolkit + # typer +rich-toolkit==0.19.4 + # via + # fastapi-cli + # fastapi-cloud-cli +rignore==0.7.6 + # via fastapi-cloud-cli +rsa==4.9.1 + # via python-jose +sentry-sdk==2.53.0 + # via fastapi-cloud-cli +shellingham==1.5.4 + # via typer +six==1.17.0 + # via + # ecdsa + # python-dateutil +sniffio==1.3.1 + # via openai +sqlalchemy==2.0.46 + # via service-explorer-backend (pyproject.toml) +starlette==0.52.1 + # via + # fastapi + # frontend +tenacity==9.1.4 + # via langchain-core +tiktoken==0.12.0 + # via langchain-openai +tqdm==4.67.3 + # via openai +typer==0.24.0 + # via + # fastapi-cli + # fastapi-cloud-cli +typing-extensions==4.15.0 + # via + # azure-core + # azure-identity + # azure-storage-blob + # fastapi + # langchain-core + # openai + # pydantic + # pydantic-core + # pydantic-extra-types + # rich-toolkit + # sqlalchemy + # typing-inspection +typing-inspection==0.4.2 + # via + # fastapi + # pydantic + # pydantic-settings +tzdata==2025.3 + # via pandas +urllib3==2.6.3 + # via + # requests + # sentry-sdk +uuid-utils==0.14.0 + # via + # langchain-core + # langsmith +uvicorn==0.41.0 + # via + # service-explorer-backend (pyproject.toml) + # fastapi + # fastapi-cli + # fastapi-cloud-cli + # frontend +watchfiles==1.1.1 + # via uvicorn +websockets==16.0 + # via uvicorn +wrapt==1.17.3 + # via langfuse +xxhash==3.6.0 + # via + # langgraph + # langsmith +yarl==1.22.0 + # via aiohttp +zstandard==0.25.0 + # via langsmith diff --git a/run.sh b/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..ec75fb8e749e5761ba66f6420ba8f14adeb57da4 --- /dev/null +++ b/run.sh @@ -0,0 +1,5 @@ +uv sync + +uv lock + +uv run uvicorn main:app --host 0.0.0.0 --port 8000 \ No newline at end of file diff --git a/services/agentic/agentic_setup.py b/services/agentic/agentic_setup.py new file mode 100644 index 0000000000000000000000000000000000000000..c2247deaa58d326f0357f2ee41ba337d8f227436 --- /dev/null +++ b/services/agentic/agentic_setup.py @@ -0,0 +1,70 @@ +from sqlalchemy.ext.asyncio import AsyncSession +from externals.databases.pg_models import CVUser +from services.agentic.filter import AgenticFilterService +from services.agentic.weight import AgenticWeightService +# from services.agentic.matching import AgenticMatchingService +# from services.agentic.profile_scoring import AgenticScoringService + + +from utils.logger import get_logger + +logger = get_logger("agentic setup") + +class AgenticService: + """ + Facade / Orchestrator for all Agentic services + """ + + def __init__(self, db: AsyncSession, user: CVUser): + self.db = db + self.user = user + + self.filter = AgenticFilterService(db, user) + self.weight = AgenticWeightService(db, user) + # self.filter = AgenticMatchingService(db, user) + # self.filter = AgenticScoringService(db, user) + + + # async def scoring_profile(self, input_scoring: PayloadMatchOne): + # "Generate profile scoring from an extracted profile and a criteria" + # try: + # profile : Profile = await get_profile(input_scoring.get("profile_id")) + # # profile : Profile = asyncio.run(get_profile(input_scoring.get("profile_id"))) + + # tobe_match = InputScoring( + # **profile, + # criteria=input_scoring.get("criteria"), + # criteria_weight=input_scoring.get("criteria_weight") + # ) + # output = await match_one(input_scoring=tobe_match) + # # output = asyncio.run(match_one_profile(input_scoring=tobe_match)) + # return output + + # except Exception as E: + # logger.error(f"❌ scoring profile error, {E}") + + # return ResponseExtractOne( + # status="failed", + # message=f"scoring profile error, {E}", + # ) + + + # async def scoring_bulk_profile(self, input_scorings: PayloadMatchBulk): + # "Generate profile scoring from list of extracted profile and a criteria" + # try: + # input_scoring_bulk = InputScoringBulk( + # profile_ids=input_scorings.get("profile_ids"), + # criteria=input_scorings.get("criteria"), + # criteria_weight=input_scorings.get("criteria_weight"), + # ) + + # outputs = await match_bulk(input_scoring_bulk) + # return outputs + + # except Exception as E: + # logger.error(f"❌ scoring profile bulk error, {E}") + + # return ResponseMatchBulk( + # status="failed", + # message=f"scoring profile bulk error, {E}", + # ) \ No newline at end of file diff --git a/services/agentic/filter.py b/services/agentic/filter.py new file mode 100644 index 0000000000000000000000000000000000000000..3994811108414242ec6a132859447fc97a483fe7 --- /dev/null +++ b/services/agentic/filter.py @@ -0,0 +1,48 @@ +from fastapi import HTTPException, status +from sqlalchemy.ext.asyncio import AsyncSession + +from externals.databases.pg_models import CVFilter +from externals.databases.pg_crud import ( + create_filter, + get_filter, + get_filter_by_id, +) +from utils.logger import get_logger + +logger = get_logger("filter agentic service") + + +class AgenticFilterService: + def __init__(self, db: AsyncSession, user): + self.db = db + self.user = user + + async def create_filter(self, filter: CVFilter) -> str: + """Return criteria_id:str""" + + # check filter existence + existing_filter = await get_filter(self.db, filter) + if existing_filter: + logger.info(f"Filter already exists: {existing_filter}") + return existing_filter.criteria_id + + + # create filter + filter_id = await create_filter(self.db, filter) + logger.info(f"Filter not existed yet, creating new filter: {filter_id}") + return filter_id.criteria_id + + + async def get_filter_by_id(self, criteria_id: str) -> CVFilter: + """Return filter object""" + + filter = await get_filter_by_id(self.db, criteria_id) + if not filter: + logger.error(f"Filter not found: {criteria_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Filter not found: {criteria_id}" + ) + return filter + + \ No newline at end of file diff --git a/services/agentic/profile_scoring.py b/services/agentic/profile_scoring.py new file mode 100644 index 0000000000000000000000000000000000000000..9d4c0c3a64c1b1a854dc2d61e5210e3e3ed4745c --- /dev/null +++ b/services/agentic/profile_scoring.py @@ -0,0 +1,525 @@ +# from typing import List +from langchain_core.prompts import ChatPromptTemplate + +from config.constant import ProfileFieldTypes +from externals.databases.pg_crud import get_criteria_id, create_cv_filter, create_cv_matching, get_matching_id, create_cv_score, get_scoring_id +from externals.databases.pg_models import CVProfile, CVWeight, CVFilter +from services.llms.LLM import model_4o_2 +from services.base.BaseGenerator import BaseAIGenerator, MetadataObservability +from models.data_model import AIProfile +from services.models.data_model import ( + AIMatchProfile, + Criteria, + CriteriaWeight, + LOGIC_NUMERIC, + LOGIC_CATEGORICAL, + InputScoring, + DataResponseMatchOne, + ResponseMatchOne, + InputScoringBulk, + DataResponseMatchBulk, + ResponseMatchBulk + ) +# from services.knowledge.knowledge_setup import KnowledgeService +from services.agentic.weight import AgenticWeightService +from services.agentic.filter import AgenticFilterService +from services.knowledge.get_profile import KnowledgeGetProfileService +from sqlalchemy.ext.asyncio import AsyncSession +from utils.logger import get_logger + + + +logger = get_logger("profile scoring") + + +def helper_get_operator(col_name: str): + if col_name in ProfileFieldTypes.NUMERIC: + op:LOGIC_NUMERIC = "greater than or equal" + return op + elif col_name in ProfileFieldTypes.TEXT: + op:LOGIC_CATEGORICAL = "similar" + return op + +def helper_judge_scoring(a_profile, b_criteria, rules) -> bool: + if rules == "greater than": + return int(a_profile > b_criteria) + elif rules == "less than": + return int(a_profile < b_criteria) + elif rules == "equal": + return int(a_profile == b_criteria) + elif rules == "greater than or equal": + return int(a_profile >= b_criteria) + elif rules == "less than or equal": + return int(a_profile <= b_criteria) + return 0 + + +# @deprecated +# def comparison_parser(input_scoring: InputScoring): +# comparison = "| parameter | candidate_profile | criteria | true_if_rules | draft_matching_score |" +# comparison += "\n| --- | --- | --- | --- | --- |" +# criteria = input_scoring.get("criteria") +# excluded = ["criteria_id"] +# for k, v in criteria.items(): +# if v and not k.startswith("w_") and k not in excluded: +# op = helper_get_operator(k) + +# if 'gpa' in k or 'yoe' in k: +# # logger.info(f"👁️ a_profile={input_scoring.get(k)} | b_criteria={v}") +# judges = helper_judge_scoring(a_profile=input_scoring.get(k), +# b_criteria=v, +# rules=op) +# else: +# judges = '???' + +# comparison += f"\n| {k} | {input_scoring.get(k)} | {v} | {op} | {judges} |" +# return comparison + + +def comparison_parser(profile:AIProfile, criteria:Criteria): + comparison = "| parameter | candidate_profile | criteria | true_if_rules | draft_matching_score |" + comparison += "\n| --- | --- | --- | --- | --- |" + + for k, v in criteria.items(): + op = helper_get_operator(k) + if 'gpa' in k or 'yoe' in k: + judges = helper_judge_scoring(a_profile=profile.get(k), + b_criteria=v, + rules=op) + else: + judges = '???' + comparison += f"\n| {k} | {profile.get(k)} | {v} | {op} | {judges} |" + return comparison + + +# async def match_one_profile(input_scoring: InputScoring) -> ResponseMatchOne: +# """Matching between one profile to a criteria""" +# try: +# # 1. CHECKING CRITERIA EXISTED +# logger.info("👁️ 1. CHECKING CRITERIA EXISTED") +# status_criteria_id = await get_criteria_id(input_scoring.get("criteria")) # pg crud +# criteria_id = status_criteria_id.get("criteria_id") + +# if status_criteria_id.get("status") == "existing": +# # just get the criteria_id +# pass +# elif status_criteria_id.get("status") == "new": +# # get the criteria_id and insert the criteria +# status_insert = await create_cv_filter( +# { +# **input_scoring.get("criteria"), +# "criteria_id": criteria_id +# } +# ) +# if status_insert.get("status") == "success": +# logger.info(f"""status_insert: {status_insert}""") +# else: +# logger.error(f"""❌ error when create_cv_filter. {create_cv_filter.get("message")}""") +# return ResponseMatchOne( +# status=create_cv_filter.get("status"), +# message=create_cv_filter.get("message"), +# data=DataResponseMatchOne( +# profile_id=input_scoring.get("profile_id"), +# ) +# ) +# else: +# logger.error(f"""❌ error when get_criteria_id. {get_criteria_id.get("message")}""") +# return ResponseMatchOne( +# status=get_criteria_id.get("status"), +# message=get_criteria_id.get("message"), +# data=DataResponseMatchOne( +# profile_id=input_scoring.get("profile_id"), +# ) +# ) + + +# # 2. CHECKING MATCHING EXISTED +# logger.info("👁️ 2. CHECKING MATCHING EXISTED") +# status_matching_id = await get_matching_id(profile_id=input_scoring.get("profile_id"), +# criteria_id=criteria_id) +# matching_id = status_matching_id.get("matching_id") +# # logger.info(f"👁️ status_matching_id: {status_matching_id}") + +# if status_matching_id.get("status") == "existing": +# pass +# elif status_matching_id.get("status") == "new": +# matching_result = await ai_matching(input_scoring=input_scoring) +# # logger.info(f"👁️ matching_result: {matching_result}") + +# status_insert_matching = await create_cv_matching( +# profile_id = input_scoring.get("profile_id"), +# criteria_id = criteria_id, +# matching_id = matching_id, +# **matching_result +# ) + +# # logger.info(f"👁️ status_insert_matching: {status_insert_matching}") + +# if status_insert_matching.get("status") == "success": +# # logger.info(f"👁️ matching_result: {matching_result}") +# # logger.info(f"""👁️ criteria_weight: {input_scoring.get("criteria_weight")}""") +# score = helper_calculate_score(comparison_result=matching_result, +# criteria_weight=input_scoring.get("criteria_weight")) + +# status_scoring_id = await get_scoring_id(matching_id=matching_id) +# scoring_id = status_scoring_id.get("scoring_id") + +# if status_scoring_id.get("status") in ["existing", "new"]: +# status_insert_score = await create_cv_score(scoring_id=scoring_id, +# matching_id=matching_id, +# score=score, +# **input_scoring.get("criteria_weight") +# ) +# if status_insert_score.get("status") == "success": +# response = ResponseMatchOne( +# status="success", +# message="success", +# data=DataResponseMatchOne( +# profile_id=input_scoring.get("profile_id"), +# criteria_id=criteria_id, +# matching_id=matching_id, +# scoring_id=scoring_id, +# score=score, +# ) +# ) +# return response +# else: +# return ResponseMatchOne( +# status=status_insert_score.get("status"), +# message=status_insert_score.get("message"), +# data=DataResponseMatchOne( +# profile_id=input_scoring.get("profile_id"), +# criteria_id=criteria_id, +# matching_id=matching_id, +# scoring_id=scoring_id, +# score=score, +# ) +# ) +# else: +# return ResponseMatchOne( +# status=status_scoring_id.get("status"), +# message=status_scoring_id.get("message"), +# data=DataResponseMatchOne( +# profile_id=input_scoring.get("profile_id"), +# criteria_id=criteria_id, +# matching_id=matching_id, +# ) +# ) + +# else: +# logger.error(f"""❌ error when create_cv_matching. {status_matching_id.get("message")}""") +# return ResponseMatchOne( +# status=status_matching_id.get("status"), +# message=status_matching_id.get("message"), +# data=DataResponseMatchOne( +# profile_id=input_scoring.get("profile_id"), +# criteria_id=criteria_id, +# ) +# ) + +# else: +# logger.error(f"""❌ error when get_matching_id. {get_matching_id.get("message")}""") +# return ResponseMatchOne( +# status=get_matching_id.get("status"), +# message=get_matching_id.get("message"), +# data=DataResponseMatchOne( +# profile_id=input_scoring.get("profile_id"), +# ) +# ) + +# except Exception as E: +# logger.error(f"❌ match one profile error, {E}") +# response = ResponseMatchOne( +# status="failed", +# message=f"match_one_profile error, {E}", +# data=DataResponseMatchOne( +# profile_id=input_scoring.get("profile_id"), +# ) +# ) +# return response + + +# async def match_bulk_profile(input_scorings: InputScoringBulk, +# knowledge_service:KnowledgeService): +# """Generate list of profile matching """ +# try: +# status_ids = {} + +# # 1. GET PROFILE GENERATOR FOR EACH PROFILE_ID +# logger.info("👁️ 1. GET PROFILE GENERATORS") +# profile_generators = knowledge_service.profile.get_profiles_generator(input_scorings.get("profile_ids")) + +# # 2. CHECKING CRITERIA EXISTED +# criteria_id = "" +# logger.info("👁️ 2. CHECKING CRITERIA EXISTED") +# status_criteria_id = await get_criteria_id(input_scorings.get("criteria")) # pg crud +# criteria_id = status_criteria_id.get("criteria_id") + +# if status_criteria_id.get("status") == "existing": +# # just get the criteria_id +# pass +# elif status_criteria_id.get("status") == "new": +# # get the criteria_id and insert the criteria +# status_insert = await create_cv_filter( +# { +# **input_scorings.get("criteria"), +# "criteria_id": criteria_id +# } +# ) +# if status_insert.get("status") == "success": +# logger.info(f"""status_insert: {status_insert}""") +# else: +# logger.error(f"""❌ error when create_cv_filter. {create_cv_filter.get("message")}""") +# return ResponseMatchBulk( +# status=create_cv_filter.get("status"), +# message=create_cv_filter.get("message"), +# ) + +# else: +# logger.error(f"""❌ error when get_criteria_id. {get_criteria_id.get("message")}""") +# return ResponseMatchBulk( +# status=get_criteria_id.get("status"), +# message=get_criteria_id.get("message"), +# ) + +# # 3. CHECKING MATCHING EXISTED +# logger.info("👁️ 3. CHECKING MATCHING EXISTED") +# for profile_id, profile_gen in profile_generators.items(): +# status_matching_id = await get_matching_id(profile_id=profile_id, +# criteria_id=criteria_id) +# matching_id = status_matching_id.get("matching_id") + +# if status_matching_id.get("status") == "existing": +# pass +# elif status_matching_id.get("status") == "new": +# profile = await anext(profile_gen) +# input_scoring = InputScoring( +# profile_id=profile_id, +# criteria=input_scorings.get("criteria"), +# criteria_weight=input_scorings.get("criteria_weight"), +# **profile, +# ) +# matching_result = await ai_matching(input_scoring=input_scoring) + +# status_insert_matching = await create_cv_matching( +# profile_id = input_scoring.get("profile_id"), +# criteria_id = criteria_id, +# matching_id = matching_id, +# **matching_result +# ) + +# # logger.info(f"👁️ status_insert_matching: {status_insert_matching}") +# if status_insert_matching.get("status") == "success": +# # logger.info(f"👁️ matching_result: {matching_result}") +# # logger.info(f"""👁️ criteria_weight: {input_scoring.get("criteria_weight")}""") +# score = helper_calculate_score(comparison_result=matching_result, +# criteria_weight=input_scoring.get("criteria_weight")) + +# status_scoring_id = await get_scoring_id(matching_id=matching_id) +# scoring_id = status_scoring_id.get("scoring_id") + +# if status_scoring_id.get("status") in ["existing", "new"]: +# status_insert_score = await create_cv_score(scoring_id=scoring_id, +# matching_id=matching_id, +# score=score, +# **input_scoring.get("criteria_weight") +# ) +# if status_insert_score.get("status") == "success": +# status_ids.append({profile_id: "success"}) +# else: +# status_ids.append({profile_id: "failed, insert score data"}) +# else: +# status_ids.append({profile_id: "failed, get scoring id"}) +# else: +# status_ids.append({profile_id: "failed, insert matching data"}) +# else: +# status_ids.append({profile_id: "failed, get matching id"}) + +# n_success = sum([1 if v == "success" else 0 for k, v in status_ids.items()]) +# if len(status_ids) == n_success: +# status = "success" +# elif n_success == 0: +# status = "failed" +# else: +# status = "partial-success" + +# return ResponseMatchBulk( +# status=status, +# message=f"total success {n_success} from {len(status_ids)} profile_id", +# data=DataResponseMatchBulk( +# status_ids=status_ids, +# criteria_id=criteria_id +# ) +# ) +# except Exception as E: +# logger.error(f"❌ match bulk profile error, {E}") +# return ResponseMatchBulk( +# status="failed", +# message=f"match bulk profile error, {E}", +# ) + + +logger = get_logger("weight agentic service") + +class AgenticScoringService: + def __init__(self, db: AsyncSession, user): + self.db = db + self.user = user + self.criteria_service = AgenticFilterService(db=db, user=user) + self.weight_service = AgenticWeightService(db=db, user=user) + self.profile_service = KnowledgeGetProfileService(db=db, user=user) + + async def _ai_matching(self, profile:AIProfile, criteria:Criteria) -> AIMatchProfile: + "Helper function to matching between a profile and criteria" + + comparison_text = comparison_parser(profile=profile, criteria=criteria) + # logger.info(f"👁️ comparison_text: {comparison_text}") + + match_one_prompt = """ + **Goals:** + Determine if the 'candidate profile' is match to 'criteria' for each parameter based on 'true if rules'. \ + + **Framework matching**: + 1. Give 1 if 'candidate profile' results true based on 'true if rules' and 'criteria', else give 0. + 2. Beware of typo, please consider further for logical operator "similar". + 3. Under column draft_matching_score, there is sample of how to giving the score. + + Here is table comparison between candidate profile and lookup criteria: + {comparison} + """.strip() + prompt = ChatPromptTemplate.from_template(match_one_prompt) + + input_llm = { + "comparison": comparison_text + } + + llm = model_4o_2.with_structured_output(AIMatchProfile) + + gen_ai = BaseAIGenerator( + task_name=self._ai_matching.__name__, + prompt=prompt, + llm=llm, + input_llm=input_llm, + metadata_observability=MetadataObservability( + fullname="system", + task_id="system", + agent=self._ai_matching.__name__, + ) + ) + + matching_result = await gen_ai.agenerate() + return matching_result + + def _calculate_score(self, match_result:AIMatchProfile, weight_data:CriteriaWeight) -> float: + """Returns matching score (float) with min-max is 0-100.0 + + Args: + comparison_result (dict): key-value of criteria and boolean of matching profiles. Example {"gpa_edu_1": 1, "univ_edu_1": 0} this means gpa_edu_1 between candidate profile and criteria is match, else not match. + criteria_weight (dict): kev-value of criteria and its weight, all weight sum must be in range 0.0-1.0. + Returns: + score (float) + """ + + score = 0 + total_weight = 0 + norm_criteria = {} # weight + + # weight_data = self.weight_service.get_weight_by_weight_id(weight_id) + + for k, v in weight_data.items(): + if k.startswith("w_") and v: + total_weight += v + + # logger.info(f"👁️ helper_calculate_score/total_weight: {total_weight}") + + if total_weight > 1.0: + # normalized weight + for k, v in weight_data.items(): + if k.startswith("w_") and v: + norm_criteria[k] = v/total_weight + else: + norm_criteria = weight_data.copy() + + # logger.info(f"👁️ helper_calculate_score/norm_criteria: {norm_criteria}") + + for k, value_comparison in match_result.items(): + if f"w_{k}" in norm_criteria and value_comparison: + temp_score = norm_criteria[f"w_{k}"] * value_comparison * 100 + # logger.info(f"👁️ w_{k}: {temp_score}") + + score += temp_score + + # logger.info(f"👁️ helper_calculate_score/score: {score}") + return score + + async def scoring(self, profile_id: str, criteria_id: str, weight_id: str): + try: + _profile:CVProfile = self.profile_service.get_profile(profile_id=profile_id) + _criteria:CVFilter = self.criteria_service.get_filter_by_id(criteria_id=criteria_id) + _weight:CVWeight = self.weight_service.get_weight_by_weight_id(weight_id=weight_id) + + profile = AIProfile( + fullname=_profile.get("fullname"), + gpa_edu_1=_profile.get("gpa_edu_1"), + univ_edu_1=_profile.get("univ_edu_1"), + major_edu_1=_profile.get("major_edu_1"), + gpa_edu_2=_profile.get("gpa_edu_2"), + univ_edu_2=_profile.get("univ_edu_2"), + major_edu_2=_profile.get("major_edu_2"), + gpa_edu_3=_profile.get("gpa_edu_3"), + univ_edu_3=_profile.get("univ_edu_3"), + major_edu_3=_profile.get("major_edu_3"), + domicile=_profile.get("domicile"), + yoe=_profile.get("yoe"), + hardskills=_profile.get("hardskills"), + softskills=_profile.get("softskills"), + certifications=_profile.get("certifications"), + business_domain=_profile.get("business_domain") + ) + + criteria = Criteria( + gpa_edu_1=_criteria.get("gpa_edu_1"), + univ_edu_1=_criteria.get("univ_edu_1"), + major_edu_1=_criteria.get("major_edu_1"), + gpa_edu_2=_criteria.get("gpa_edu_2"), + univ_edu_2=_criteria.get("univ_edu_2"), + major_edu_2=_criteria.get("major_edu_2"), + gpa_edu_3=_criteria.get("gpa_edu_3"), + univ_edu_3=_criteria.get("univ_edu_3"), + major_edu_3=_criteria.get("major_edu_3"), + domicile=_criteria.get("domicile"), + yoe=_criteria.get("yoe"), + hardskills=_criteria.get("hardskills"), + softskills=_criteria.get("softskills"), + certifications=_criteria.get("certifications"), + business_domain=_criteria.get("business_domain") + ) + + weight = CriteriaWeight( + gpa_edu_1=_weight.get("gpa_edu_1"), + univ_edu_1=_weight.get("univ_edu_1"), + major_edu_1=_weight.get("major_edu_1"), + gpa_edu_2=_weight.get("gpa_edu_2"), + univ_edu_2=_weight.get("univ_edu_2"), + major_edu_2=_weight.get("major_edu_2"), + gpa_edu_3=_weight.get("gpa_edu_3"), + univ_edu_3=_weight.get("univ_edu_3"), + major_edu_3=_weight.get("major_edu_3"), + domicile=_weight.get("domicile"), + yoe=_weight.get("yoe"), + hardskills=_weight.get("hardskills"), + softskills=_weight.get("softskills"), + certifications=_weight.get("certifications"), + business_domain=_weight.get("business_domain") + ) + + match_result:AIMatchProfile = await self._ai_matching(profile, criteria) + score = self._calculate_score(match_result=match_result, weight_data=weight) + + return score + except Exception as E: + logger.error(f"profile scoring error, {E}") + raise + + + \ No newline at end of file diff --git a/services/agentic/weight.py b/services/agentic/weight.py new file mode 100644 index 0000000000000000000000000000000000000000..62bd27fd4ec11c3abf76c51d0819704d1ae2eeb3 --- /dev/null +++ b/services/agentic/weight.py @@ -0,0 +1,92 @@ +import os, sys + +from fastapi import HTTPException, status +from sqlalchemy.ext.asyncio import AsyncSession + +from externals.databases.pg_models import CVWeight +from externals.databases.pg_crud import ( + create_filter, + get_filter_by_id, + create_weight, + get_weight_by_id +) +from utils.logger import get_logger + +logger = get_logger("weight agentic service") + + +class AgenticWeightService: + def __init__(self, db: AsyncSession, user): + self.db = db + self.user = user + + + async def create_weight(self, weight: CVWeight) -> str: + """Return criteria_id:str""" + + try: + # check weight existence + filter = await get_filter_by_id(self.db, weight.criteria_id) + + # loop weight fields is none or empty list + weighted_field_name = [] # store field name for not none and not empty list + + for field in filter.__dict__.items(): + if field[1] is None or (isinstance(field[1], list) and not field[1]): + continue + weighted_field_name.append(field[0]) + print("weighted_field_name:", weighted_field_name) + + # check current weight, apply default weight + new_weight = CVWeight(criteria_id=weight.criteria_id) + excluded_fields = ["created_at", "_sa_instance_state", "criteria_id"] + all_weight = [ + getattr(weight, field) + for field in weighted_field_name + if getattr(weight, field) is not None and field not in excluded_fields + ] + print("all_weight", all_weight) + total_weight = sum(all_weight) + + + if total_weight == 0: + def_w = 1 / len(weighted_field_name) + for field_name in weighted_field_name: + setattr(new_weight, field_name, def_w) + elif total_weight > 0 and total_weight <= 1.0: # DOCS: assuming total_weight > 0 + for field_name in weighted_field_name: + curr_w = getattr(weight, field_name) + curr_w = curr_w if curr_w is not None else 0.01 # DOCS: default weight if the given weight is none or zero + setattr(new_weight, field_name, curr_w) + else: + # normalized weight + # total_weight = sum([getattr(new_weight, field_name) for field_name in weighted_field_name]) + for field_name in weighted_field_name: + curr_w = getattr(new_weight, field_name) + normalized_w = curr_w / total_weight + setattr(new_weight, field_name, normalized_w) + + # create weight + await create_weight(self.db, new_weight) + logger.info(f"Weight created: {new_weight.criteria_id}") + return new_weight.criteria_id + except Exception as E: + logger.error(f"❌ create weight error: {E}") + exc_type, exc_obj, exc_tb = sys.exc_info() + fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] + print(exc_type, fname, exc_tb.tb_lineno) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Create weight error: {E}" + ) + + + async def get_weight_by_weight_id(self, weight_id: str) -> CVWeight: + "Return weight json in dict" + + try: + weight_data = await get_weight_by_id(self.db, weight_id=weight_id) + return weight_data + except Exception as E: + logger.error(f"get weight by weight id error, {E}") + return {} \ No newline at end of file diff --git a/services/agents/AutograderAgent.py b/services/agents/AutograderAgent.py new file mode 100644 index 0000000000000000000000000000000000000000..c221ed8406139355b613c9165f8e170e3976b93f --- /dev/null +++ b/services/agents/AutograderAgent.py @@ -0,0 +1,198 @@ +import asyncio +# import os, glob +import uuid +import time +import pandas as pd +from dotenv import load_dotenv +load_dotenv() +from typing import AsyncIterable, List, Optional, Dict, Union +from langchain_core.messages import HumanMessage, AIMessage +from langchain_core.callbacks import AsyncCallbackHandler + +# from fastapi.middleware.cors import CORSMiddleware +# from fastapi.responses import StreamingResponse +# from langchain.chat_models import ChatOpenAI +# from pydantic import BaseModel +# from langchain_google_genai import ChatGoogleGenerativeAI +from services.llms.LLM import model_5mini, model_4o_2 +from services.agents.LLMAgent import LLMAgent +from models.data_model import OutProfile, Profile +from services.prompts.profile_extraction import extract_one_profile +from utils.utils import pdf_reader, ingest_one_profile, ingest_bulk_profile, retrieve_profile, pretty_profiles +# from concurrent.futures import ThreadPoolExecutor, as_completed + +prompt_template_filename = "AutograderPrompt.md" +prompt_autograder = open(f"src/prompts/{prompt_template_filename}", "rb").read().decode('utf-8') + + +class AutograderAgent(LLMAgent): + def __init__(self, model=model_4o_2): + super().__init__(model) + self.agent_name = "AutograderAgent" + self.prompt_template = prompt_autograder + self.prompt_extract_one_profile = extract_one_profile + + async def generate(self, user_profile: str) -> AsyncIterable[str]: + """Generates a response from messages using the model's astream method.""" + self.callback = AsyncCallbackHandler() + self.callbacks = [self.callback] + input = [ + HumanMessage(content=self.prompt_template.format(user_profile=user_profile)), + ] + try: + async for token in self.model.astream(input=input, callbacks=self.callbacks): + yield token.content + except Exception as e: + print(f"Caught exception: {e}") + + async def generate_one(self, file_path:str) -> Optional[OutProfile]: + "Generate extracted profile from a CV (curriculum vitae)" + try: + llm = self.model.with_structured_output(OutProfile) + cv = await pdf_reader(file_path) # get_pdf(path) + # extract_one_profile = extract_one_profile.format(cv=cv) + chain = self.prompt_extract_one_profile | llm + input_chain = { + "cv":cv + } + # profile = chain.invoke(input_chain, config=None) + profile = await chain.ainvoke(input_chain, config=None) + return profile + except Exception as E: + print(f"Failed to generate one profile for {file_path} due to error, {E}") + raise NotImplementedError(f"Failed to generate one profile for {file_path} due to error, {E}") + + # async def generate_bulk(self, folder_path:str, export_csv:bool=False) -> Optional[List[OutProfile]]: + # "Generate extracted profile from a CV (curriculum vitae)" + # try: + # st = time.time() + # llm = self.model.with_structured_output(OutProfile) + # files_path = glob.glob(f"{folder_path}/*.pdf") + + # profiles = [] + # n_files = len(files_path) + # for i, file_path in enumerate(files_path): + # cv = await pdf_reader(file_path) # get_pdf(path) + # chain = self.prompt_extract_one_profile | llm + # input_chain = { + # "cv":cv + # } + # profile = await chain.ainvoke(input_chain, config=None) + # profiles.append(profile) + # print(f"[{i+1}/{n_files}] profile extracted ✅") + # print(f"✅ Finish in {(time.time() - st)//60} min, {(time.time() - st)%60} sec") + # return profiles + # except Exception as E: + # print(f"Failed to generate one profile for {file_path} due to error, {E}") + # raise NotImplementedError(f"Failed to generate one profile for {file_path} due to error, {E}") + + # async def generate_bulk(self, folder_path:str, export_csv:bool=False) -> Optional[List[OutProfile]]: + # "Generate extracted profile from a CV (curriculum vitae)" + # try: + # st = time.time() + # llm = self.model.with_structured_output(OutProfile) + # files_path = glob.glob(f"{folder_path}/*.pdf") + + # profiles = [] + # n_files = len(files_path) + # for i, file_path in enumerate(files_path): + # cv = await pdf_reader(file_path) # get_pdf(path) + # chain = self.prompt_extract_one_profile | llm + # input_chain = { + # "cv":cv + # } + # profile = await chain.ainvoke(input_chain, config=None) + # profiles.append(profile) + # print(f"[{i+1}/{n_files}] profile extracted ✅") + # print(f"✅ Finish in {(time.time() - st)//60} min, {(time.time() - st)%60} sec") + # return profiles + # except Exception as E: + # print(f"Failed to generate one profile for {file_path} due to error, {E}") + # raise NotImplementedError(f"Failed to generate one profile for {file_path} due to error, {E}") + + # not using threadpool + # async def generate_bulk(self, pdfs:List, export_csv:bool=False) -> Optional[List[OutProfile]]: + # "Generate extracted profile from a CV (curriculum vitae)" + # try: + # st = time.time() + # llm = self.model.with_structured_output(OutProfile) + # profiles = [] + # n_files = len(pdfs) + # for i, file_path in enumerate(pdfs): + # print(f"Reading file [{i+1}/{n_files}]") + # cv = await pdf_reader(file_path) # get_pdf(path) + # chain = self.prompt_extract_one_profile | llm + # input_chain = { + # "cv":cv + # } + # profile = await chain.ainvoke(input_chain, config=None) + # profiles.append(profile) + # print(f"[{i+1}/{n_files}] profile extracted ✅") + # print(f"✅ Finish in {(time.time() - st)//60} min, {(time.time() - st)%60} sec") + # return profiles + # except Exception as E: + # print(f"Failed to generate one profile for {file_path} due to error, {E}") + # raise NotImplementedError(f"Failed to generate one profile for {file_path} due to error, {E}") + + async def _helper_generate_one(self, file_path): + st = time.time() + cv = await pdf_reader(file_path) # get_pdf(path) + llm = self.model.with_structured_output(OutProfile) + chain = self.prompt_extract_one_profile | llm + input_chain = { + "cv":cv + } + profile = await chain.ainvoke(input_chain, config=None) + rt = time.time() - st + print(f"Runtime extract one profile: {round(rt,2)}") + return profile + + async def generate_bulk(self, pdfs:List, export_csv:bool=False) -> Optional[List[OutProfile]]: + "Generate extracted profile from a CV (curriculum vitae)" + try: + st = time.time() + profiles = [] + n_files = len(pdfs) + tasks = [] + for i, file_path in enumerate(pdfs): + print(f"Reading file [{i+1}/{n_files}]") + task = asyncio.create_task(self._helper_generate_one(file_path)) + tasks.append(task) + print(f"[{i+1}/{n_files}] profile extracted ✅") + + profiles = await asyncio.gather(*tasks) + print(f"✅ Finish in {(time.time() - st)//60} min, {(time.time() - st)%60} sec") + return profiles + except Exception as E: + print(f"Failed to generate one profile for {file_path} due to error, {E}") + raise NotImplementedError(f"Failed to generate one profile for {file_path} due to error, {E}") + + + async def insert_one_profile(self, profile:Profile): + await ingest_one_profile(profile) + + async def insert_bulk_profile(self, profiles:List[Profile]): + await ingest_bulk_profile(profiles) + + async def get_profiles(self, criteria:str, limit:int): + retrieved_profiles = await retrieve_profile(input_user=criteria, limit=limit) + return retrieved_profiles + + async def get_dataframe_profiles(self, profiles:List[Profile]) -> pd.DataFrame: + df = await pretty_profiles(profiles) + return df + + + + +# import asyncio +# # myagent = AutograderAgent(model=model_gemini) +# myagent2 = AutograderAgent(model=model_4o) +# folder_path="src/data/cvs" +# files_path = glob.glob(f"{folder_path}/*.pdf") +# print(len(files_path)) +# # res = asyncio.run(myagent.generate_one(file_path=files_path[1])) +# res_bulk = asyncio.run(myagent2.generate_bulk(folder_path=folder_path)) +# profiles = asyncio.run(helper_prepare_profiles(files_path, res_bulk)) +# asyncio.run(myagent2.insert_bulk_profile(profiles)) + diff --git a/services/agents/LLMAgent.py b/services/agents/LLMAgent.py new file mode 100644 index 0000000000000000000000000000000000000000..8c091645299c0d46b0df85100089a5ec57fc5f9b --- /dev/null +++ b/services/agents/LLMAgent.py @@ -0,0 +1,42 @@ +from services.llms.LLM import model_gemini +from typing import AsyncIterable, Optional +from langchain.callbacks import AsyncIteratorCallbackHandler + +class LLMAgent: + def __init__(self, model = model_gemini): + self.agent_id:Optional[str] = None + self.session_id:Optional[str] = None + self.thread_id:Optional[str] = None + self.agent_name:Optional[str] = None + self.model = model + self.callback = AsyncIteratorCallbackHandler() + self.callbacks = [self.callback] + + async def generate(self, messages: list) -> AsyncIterable[str]: + """ Generates a response from messages using the model's astream method. + Args: + model (ChatGoogleGenerativeAI): The model to use for generating responses. + messages (list): A list of messages to send to the model. + ```python + from langchain_core.messages import HumanMessage, SystemMessage + + messages = [ + SystemMessage( + content="You are a helpful assistant! Your name is Bob." + ), + HumanMessage( + content="What is your name?" + ) + ]``` + Yields: + str: The content of each token generated by the model. + Raises: + Exception: If an error occurs during the generation process. + """ + + try: + async for token in self.model.astream(input=messages, callbacks=self.callbacks): + print(f"token: {token}") + yield token.content + except Exception as e: + print(f"Caught exception: {e}") \ No newline at end of file diff --git a/services/agents/LearningRoadmapAgent.py b/services/agents/LearningRoadmapAgent.py new file mode 100644 index 0000000000000000000000000000000000000000..39910c8af3512d41451083040d7050e2fc065331 --- /dev/null +++ b/services/agents/LearningRoadmapAgent.py @@ -0,0 +1,104 @@ +from pydantic import BaseModel +from typing import Optional, List, Annotated, TypedDict +from langchain_core.messages import BaseMessage, HumanMessage +from langgraph.graph.message import add_messages +from langgraph.graph import StateGraph, START, END +from langgraph.checkpoint.memory import MemorySaver +from langgraph.prebuilt import ToolNode +# tool_node = ToolNode(tools) + +from services.llms.LLM import model_4o_2 +from services.agents.LLMAgent import LLMAgent + +PROMPT_PATH = 'src/prompts/LearningRoadmapPrompt.md' +with open(PROMPT_PATH, encoding='utf-8') as f: + prompt_template = f.read() + + +class Competency(BaseModel): + skill: str + description: str + resources: List[str] + +class Roadmap(BaseModel): + roadmap: List[Competency] + insight: str + +class Roadmaps(BaseModel): + roadmaps: List[Roadmap] + +class AgentState(TypedDict): + """State for our agent""" + messages: Annotated[list[BaseMessage], add_messages] + roadmaps: Roadmaps + + + + +def gap_analysis(state: AgentState) -> AgentState: + """Gatekeeper: answer directly""" + roadmap_llm = model_4o_2.with_structured_output(Roadmaps) + + gap_analysis_prompt = """\ + {user_profile_and_target} + + Task: Create 3 options of learning roadmap for the user to achieve their target. + Each roadmap has 2 keys, 'roadmap' and 'insight'. In the 'roadmap' key provide list of 'skill', 'description', and 'resources' for each competency. + The 'insight' key should provide a brief summary of the roadmap and how it relates to the user's profile and target. + """ + + user_profile_and_target = state['messages'][-1].content + if not user_profile_and_target: + return {"error": "user_profile_and_target must be provided."} + + input_gap_analysis_prompt = gap_analysis_prompt.format( + user_profile_and_target = user_profile_and_target + ) + + result = roadmap_llm.invoke(input_gap_analysis_prompt) + recommendations = {} + for i, a_roadmap in enumerate(result.roadmaps): + recommendations[f'roadmap_{i+1}'] = {} + recommendations[f'roadmap_{i+1}']['competencies'] = [] + recommendations[f'roadmap_{i+1}']['insight'] = a_roadmap.insight + for a_competency in a_roadmap.roadmap: + recommendations[f'roadmap_{i+1}']['competencies'].append({"skill":a_competency.skill, "description": a_competency.description, "resources": a_competency.resources}) + return {**state, "roadmaps": recommendations} + + +class LearningRoadmapAgent(LLMAgent): + def __init__(self): + super().__init__() + self.user_profile: Optional[str] = None + self.user_target: Optional[str] = None + self.thread_id = None + self.session_id = None + self.roadmap_agent_graph = StateGraph(AgentState) + self.roadmap_agent_graph.add_node("gap_analysis", gap_analysis) + self.roadmap_agent_graph.add_edge(START, "gap_analysis") + self.roadmap_agent_graph.add_edge("gap_analysis", END) + self.roadmap_agent = self.roadmap_agent_graph.compile(checkpointer=MemorySaver()) + + + def generate_roadmap(self, user_profile: str = None, user_target: str = None) -> list: + """ + Generate a learning roadmap based on user_profile and user_target. + """ + + if user_profile is None or user_target is None: + return [{"error": "user_profile and user_target must be provided."}] + + merged_user_profile_target = """ + Please create roadmap from following input: + + User Profile: {user_profile} + + User Target: {user_target} + """.format(user_profile=user_profile, user_target=user_target).replace('{','{{').replace('}','}}') + + config = {"configurable": {"thread_id": self.thread_id, "session_id": self.session_id}} + result = self.roadmap_agent.invoke({"messages": [HumanMessage(content=merged_user_profile_target)]}, config) + if result and 'roadmaps' in result: + return result['roadmaps'] + else: + return [{"error": "Failed to generate roadmap."}] \ No newline at end of file diff --git a/services/agents/ProfileMatchingAgent.py b/services/agents/ProfileMatchingAgent.py new file mode 100644 index 0000000000000000000000000000000000000000..bef791298b086cd223eeca3abeb41643a84cb200 --- /dev/null +++ b/services/agents/ProfileMatchingAgent.py @@ -0,0 +1,130 @@ +import asyncio +import os, sys +import time +from dotenv import load_dotenv +load_dotenv() +from typing import AsyncIterable +from typing import List, Optional, Dict +from langchain.schema import HumanMessage, AIMessage +from langchain.callbacks import AsyncIteratorCallbackHandler + +# from fastapi.middleware.cors import CORSMiddleware +# from fastapi.responses import StreamingResponse +# from langchain.chat_models import ChatOpenAI +# from pydantic import BaseModel +# from langchain_google_genai import ChatGoogleGenerativeAI +from models.data_model import OutProfile, OutMatching +from services.llms.LLM import model_gemini, model_4o, model_4omini, model_5mini +from services.agents.LLMAgent import LLMAgent +from services.prompts.profile_matching import match_one_profile +from utils.utils import pdf_reader, ingest_one_profile, ingest_bulk_profile + + + +async def helper_profile_match_prompt(profile: OutProfile) -> str: + profile.high_edu_major_1 = profile.high_edu_major_1 if profile.high_edu_major_1 else "-" + profile.high_edu_univ_1 = profile.high_edu_univ_1 if profile.high_edu_univ_1 else "-" + profile.high_edu_gpa_1 = profile.high_edu_gpa_1 if profile.high_edu_gpa_1 else "-" + profile.high_edu_major_2 = profile.high_edu_major_2 if profile.high_edu_major_2 else "-" + profile.high_edu_univ_2 = profile.high_edu_univ_2 if profile.high_edu_univ_2 else "-" + profile.high_edu_gpa_2 = profile.high_edu_gpa_2 if profile.high_edu_gpa_2 else "-" + profile.high_edu_major_3 = profile.high_edu_major_3 if profile.high_edu_major_3 else "-" + profile.high_edu_univ_3 = profile.high_edu_univ_3 if profile.high_edu_univ_3 else "-" + profile.high_edu_gpa_3 = profile.high_edu_gpa_3 if profile.high_edu_gpa_3 else "-" + profile.hardskills = profile.hardskills if profile.hardskills else [] + profile.softskills = profile.softskills if profile.softskills else [] + profile.certifications = profile.certifications if profile.certifications else [] + profile.business_domain_experiences = profile.business_domain_experiences if profile.business_domain_experiences else [] + + profile_text = f""" +# Candidate Profile + +**Education** +- Bachelor degree major: {profile.high_edu_major_1 or "-"} +- Bachelor university: {profile.high_edu_univ_1 or "-"} +- Bachelor GPA: {profile.high_edu_gpa_1 or "-"} + +- Master degree major: {profile.high_edu_major_2 or "-"} +- Master university: {profile.high_edu_univ_2 or "-"} +- Master GPA: {profile.high_edu_gpa_2 or "-"} + +- Doctor/Phd degree major: {profile.high_edu_major_3 or "-"} +- Doctor/Phd university: {profile.high_edu_univ_3 or "-"} +- Doctor/Phd GPA: {profile.high_edu_gpa_3 or "-"} + +**Year of Working Experience** +{profile.yoe} year + +**Hardskills** +{", ".join([p for p in profile.hardskills if p not in ['null', '']])} + +**Softskills** +{", ".join([p for p in profile.softskills if p not in ['null', '']])} + +**Certifications** +{", ".join([p for p in profile.certifications if p not in ['null', '']])} + +**Business domain experiences** +{", ".join([p for p in profile.business_domain_experiences if p not in ['null', '']])} +""".strip() + return profile_text + + +class ProfileMatchingAgent(LLMAgent): + def __init__(self, model=model_5mini): + super().__init__(model) + self.agent_name = "ProfileMatchingAgent" + self.prompt_template = match_one_profile + + async def _helper_matching_one(self, profile_id:int, profile_dict:Dict, profile_text:str, criteria:str) -> Dict: + llm = self.model.with_structured_output(OutMatching) + chain = self.prompt_template | llm + input_chain = { + "profile_text":profile_text, + "criteria":criteria, + } + matched_profile = await chain.ainvoke(input_chain, config=None) + print(f"_helper_matching_one/matched_profile:\n{matched_profile}") + + # matched_profile = matched_profile.model_dump() + # matched_profile["profile_id"] = profile_id + + profile_dict["score"] = matched_profile.score + profile_dict["reason"] = matched_profile.reason + profile_dict["profile_id"] = profile_id + + return profile_dict + + async def matching_profile_bulk(self, profiles:List[OutProfile], criteria:str) -> Optional[List]: + try: + st = time.time() + tasks = [] + profiles_text = [] + profiles_dict = [] + n_profiles = len(profiles) + + for profile_id, p in enumerate(profiles): + print(f"Processing [{profile_id+1}/{n_profiles}]") + profile_text = await helper_profile_match_prompt(p) + profile_dict = p.model_dump() + profiles_dict.append(profile_dict) + profiles_text.append(profile_text) + + task = asyncio.create_task(self._helper_matching_one(profile_id=profile_id, + profile_dict=profile_dict, + profile_text=profile_text, + criteria=criteria)) + tasks.append(task) + + profiles_with_scores = await asyncio.gather(*tasks) + + print(f"✅ Profile matching finished in {(time.time() - st)//60} min, {(time.time() - st)%60} sec") + return profiles_with_scores + except Exception as E: + error_message = f"Processing profile matching error: {E}" + print(error_message) + exc_type, exc_obj, exc_tb = sys.exc_info() + fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] + print(exc_type, fname, exc_tb.tb_lineno) + + diff --git a/services/agents/__init__.py b/services/agents/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f0ee98a09e1c686fe93fe9d733b28de4dcea0a1b --- /dev/null +++ b/services/agents/__init__.py @@ -0,0 +1,4 @@ +__all__ = ['LLMAgent', 'LearningRoadmapAgent'] + +from .LearningRoadmapAgent import LearningRoadmapAgent +from .LLMAgent import LLMAgent diff --git a/services/base/BaseGenerator.py b/services/base/BaseGenerator.py new file mode 100644 index 0000000000000000000000000000000000000000..95de5a43c24b112839d4f61f9cd303cbc97a2eb8 --- /dev/null +++ b/services/base/BaseGenerator.py @@ -0,0 +1,194 @@ +from pydantic import BaseModel +from langchain_core.prompts import ChatPromptTemplate +from langchain_openai import AzureChatOpenAI +from tenacity import ( + retry, + stop_after_attempt, + wait_exponential, + retry_if_exception_type +) +from typing import Dict + +from externals.observability.langfuse import langfuse_handler, langfuse +from services.llms.LLM import model_5mini, model_4omini +from utils.decorator import trace_runtime +from utils.logger import get_logger + +logger = get_logger("base generator") + +class MetadataObservability(BaseModel): + fullname: str + task_id: str + agent: str + +class BaseAIGenerator: + """ + Args: + name:str, + prompt: ChatPromptTemplate, + input_llm: Dict, + metadata_observability: MetadataObservability, + output_model: BaseModel, + llm:AzureChatOpenAI = model_5mini | model_4omini, + """ + def __init__(self, + task_name:str, + prompt: ChatPromptTemplate, + input_llm: Dict, + metadata_observability: MetadataObservability, + llm:AzureChatOpenAI = model_5mini | model_4omini, + ): + self.name = task_name + self.llm = llm + self.prompt = prompt + self.input_llm = input_llm + self.metadata_observability = metadata_observability + + @retry( + reraise=True, + stop=stop_after_attempt(2), # retry max 3 times + wait=wait_exponential(multiplier=1, min=1, max=5), + retry=retry_if_exception_type(Exception) # retry on any exception from LLM + ) + async def _asafe_invoke(self, chain, input_llm, config): + """private helper for retries""" + return await chain.ainvoke(input_llm, config=config) + + @retry( + reraise=True, + stop=stop_after_attempt(2), # retry max 3 times + wait=wait_exponential(multiplier=1, min=1, max=5), + retry=retry_if_exception_type(Exception) # retry on any exception from LLM + ) + async def _safe_invoke(self, chain, input_llm, config): + """private helper for retries""" + return chain.invoke(input_llm, config=config) + + # @trace_runtime + # async def agenerate(self): + # try: + # chain = self.prompt | self.llm + # config = {"callbacks": [langfuse_handler]} + + # with langfuse.start_as_current_observation( + # as_type='generation', + # name=self.name, + # input=self.input_llm, + # ) as trace: + # trace.update_trace(user_id=self.metadata_observability.fullname, + # session_id=self.metadata_observability.task_id, + # metadata=self.metadata_observability.model_dump() + # ) + # output = await self._asafe_invoke(chain=chain, + # input_llm=self.input_llm, + # config=config) + # trace.update_trace(output=output) + # return output + # except Exception as E: + # logger.error(f"❌ BaseGenerator, agenerate error, {E}") + # return None + + # @trace_runtime + # async def generate(self): + # try: + # chain = self.prompt | self.llm + # config = {"callbacks": [langfuse_handler]} + + # with langfuse.start_as_current_observation( + # as_type='generation', + # name=self.name, + # input=self.input_llm, + # ) as trace: + # trace.update_trace(user_id=self.metadata_observability.fullname, + # session_id=self.metadata_observability.task_id, + # metadata=self.metadata_observability.model_dump() + # ) + # output = self._safe_invoke(chain=chain, + # input_llm=self.input_llm, + # config=config) + # trace.update_trace(output=output) + # return output + # except Exception as E: + # logger.error(f"❌ BaseGenerator, generate error, {E}") + # return None + + @trace_runtime + async def agenerate(self): + trace = None + try: + chain = self.prompt | self.llm + config = {"callbacks": [langfuse_handler]} + + # ✅ Create trace (no context manager, no end()) + trace = langfuse.trace( + name=self.name, + input=self.input_llm, + ) + + trace.update( + user_id=self.metadata_observability.fullname, + session_id=self.metadata_observability.task_id, + metadata=self.metadata_observability.model_dump(), + ) + + output = await self._asafe_invoke( + chain=chain, + input_llm=self.input_llm, + config=config, + ) + + trace.update(output=output) + + return output + + except Exception as e: + logger.exception("❌ BaseGenerator agenerate error") + + if trace: + trace.update( + status="error", + error=str(e), + ) + + return None + + @trace_runtime + async def generate(self): + trace = None + try: + chain = self.prompt | self.llm + config = {"callbacks": [langfuse_handler]} + + trace = langfuse.trace( + name=self.name, + input=self.input_llm, + ) + + trace.update( + user_id=self.metadata_observability.fullname, + session_id=self.metadata_observability.task_id, + metadata=self.metadata_observability.model_dump(), + ) + + output = self._safe_invoke( + chain=chain, + input_llm=self.input_llm, + config=config, + ) + + trace.update(output=output) + + return output + + except Exception as e: + logger.exception("❌ BaseGenerator generate error") + + if trace: + trace.update( + status="error", + error=str(e), + ) + + return None + + diff --git a/services/embed_model/__init__.py b/services/embed_model/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/services/embed_model/embed_model.py b/services/embed_model/embed_model.py new file mode 100644 index 0000000000000000000000000000000000000000..ac1e1ada3de223cd46a9fe8154f8a718ceb12f8a --- /dev/null +++ b/services/embed_model/embed_model.py @@ -0,0 +1,23 @@ +import os +import dotenv +dotenv.load_dotenv() +from datetime import datetime +from langchain_openai import AzureOpenAIEmbeddings + + +def serve_embed_model(): + try: + embed_model = AzureOpenAIEmbeddings( + model=os.environ.get('azureai--embedmodel--name'), + azure_endpoint=os.environ.get('azureai--embedmodel--endpoint'), + api_key=os.environ.get('azureai--embedmodel--api-key'), + api_version=os.environ.get('azureai--embedmodel--api--version') + ) + # asyncio.run(embed_model.aembed_documents("Hello my name is EMA")) + print(f"✅ [INFO] Initialized embedding model succeeded") + return embed_model + except Exception as E: + print(f"❌ [ERROR] Initialized embedding model failed") + + +embed_model = serve_embed_model() \ No newline at end of file diff --git a/services/extractor/pdf.py b/services/extractor/pdf.py new file mode 100644 index 0000000000000000000000000000000000000000..5c4945e32274cab45a08564eb474104d49a45a74 --- /dev/null +++ b/services/extractor/pdf.py @@ -0,0 +1,34 @@ +# import fitz # PyMuPDF +# from io import BytesIO + +# async def extract_text_from_pdf_bytes(pdf_bytes: bytes) -> str: +# """ +# Extract text from PDF file in bytes +# Return plain text +# """ +# text_chunks = [] + +# with fitz.open(stream=pdf_bytes, filetype="pdf") as doc: +# for page in doc: +# page_text = page.get_text() +# if page_text: +# text_chunks.append(page_text) + +# return "\n".join(text_chunks).strip() + +from io import BytesIO +from pypdf import PdfReader + +async def extract_text_from_pdf_bytes(pdf_bytes: bytes) -> str: + if not isinstance(pdf_bytes, (bytes, bytearray)): + raise TypeError("pdf_bytes must be bytes") + + reader = PdfReader(BytesIO(pdf_bytes)) + + text_parts = [] + for page in reader.pages: + page_text = page.extract_text() + if page_text: + text_parts.append(page_text) + + return "\n".join(text_parts) \ No newline at end of file diff --git a/services/knowledge/delete_file.py b/services/knowledge/delete_file.py new file mode 100644 index 0000000000000000000000000000000000000000..fa139f0679d8159260db84f51df884cd1cefc075 --- /dev/null +++ b/services/knowledge/delete_file.py @@ -0,0 +1,58 @@ +from fastapi import HTTPException, status +from sqlalchemy.ext.asyncio import AsyncSession + +from externals.databases.pg_crud import ( + get_file_by_filename, + delete_file_by_filename, +) +from externals.storages.azure_blob import delete_blob_by_filename +from utils.logger import get_logger + +logger = get_logger("knowledge-delete") + + +class KnowledgeDeleteService: + def __init__(self, db: AsyncSession, user): + self.db = db + self.user = user + + async def delete(self, filename: str) -> None: + logger.info( + "knowledge.delete.requested", + extra={ + "cv_filename": filename, + "user_id": str(self.user.user_id), + "tenant_id": str(self.user.tenant_id), + }, + ) + + # 1️⃣ Check DB record + cv_file = await get_file_by_filename(self.db, + filename=filename, + user_id=self.user.user_id) + if not cv_file: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"File '{filename}' not found", + ) + + # 2️⃣ Delete blob + blob_deleted = await delete_blob_by_filename(filename=filename, + tenant_id=self.user.tenant_id, + user_id=self.user.user_id) + if not blob_deleted: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Failed to delete blob file", + ) + + # 3️⃣ Delete DB record + await delete_file_by_filename(self.db, filename) + + logger.info( + "knowledge.delete.success", + extra={ + "cv_filename": filename, + "user_id": str(self.user.user_id), + }, + ) diff --git a/services/knowledge/extract_profile.py b/services/knowledge/extract_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..fa6186940d0cf15e3e00d84ae1a7a9ae09ad0adc --- /dev/null +++ b/services/knowledge/extract_profile.py @@ -0,0 +1,196 @@ +import time +from uuid import uuid4 +from pydantic import Field +from typing import TypedDict, List, Dict, Union +from langchain_core.prompts import ChatPromptTemplate + +from services.models.data_model import AIProfile, RawProfile, Profiles +from services.base.BaseGenerator import BaseAIGenerator, MetadataObservability +from services.llms.LLM import model_5mini, model_4o_2 +from utils.decorator import trace_runtime +from utils.logger import get_logger +from fastapi import HTTPException, status +logger = get_logger("profile extraction") + + +from sqlalchemy.ext.asyncio import AsyncSession +from externals.databases.pg_crud import ( + get_file_by_filename, + mark_file_extracted, + create_profile, +) +from externals.databases.pg_models import CVUser, CVProfile +from utils.logger import get_logger +from externals.storages.azure_blob import download_blob_by_filename +from services.extractor.pdf import extract_text_from_pdf_bytes +logger = get_logger("knowledge.extract") + + +class KnowledgeExtractService: + + def __init__(self, db: AsyncSession, user: CVUser): + self.db = db + self.user = user + + @trace_runtime + async def extract(self, filename: str) -> CVProfile: + # 1️⃣ Ambil metadata file + file = await get_file_by_filename(self.db, + filename=filename, + user_id=self.user.user_id) + + if not file: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"File '{filename}' not found", + ) + + if file.is_extracted: + logger.info(f"ℹ️ File already extracted: {filename}") + + # 2️⃣ Download PDF + pdf_bytes: bytes = await download_blob_by_filename( + filename=file.filename, + tenant_id=self.user.tenant_id, + user_id=self.user.user_id, + ) + + # 3️⃣ Extract text + text = await extract_text_from_pdf_bytes(pdf_bytes) + + if not text.strip(): + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="PDF contains no extractable text", + ) + + # 4️⃣ Build RawProfile + raw_profile = RawProfile( + filename=file.filename, + content_type=file.file_type, + content=text, + profile_id=str(uuid4()) + ) + + # 5️⃣ Extract with AI + ai_profile: AIProfile = await self._extract_with_ai(raw_profile) + + if not ai_profile: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI extraction failed", + ) + + # 6️⃣ INSERT profile ke cv_profile + profile = await create_profile( + db=self.db, + # user_id=self.user.user_id, + # tenant_id=self.user.tenant_id, + filename=file.filename, + file_id=file.file_id, + profile=ai_profile, + ) + + # 7️⃣ UPDATE cv_file.is_extracted + await mark_file_extracted( + db=self.db, + file_id=file.file_id, + ) + + await self.db.commit() + + logger.info( + "✅ Profile extracted & persisted", + extra={"context": { + "filename": filename, + "profile_id": profile.profile_id, + }}, + ) + + return profile + + + @trace_runtime + async def _extract_with_ai(self, raw_profile: RawProfile) -> AIProfile: + """ + Extract structured profile from CV content + """ + + try: + extract_one_profile_prompt = """ + You are an intelligent information extraction assistant. + Your task is to read the following Curriculum Vitae (CV) text and extract structured information according to the expected output below. + + ---------------------------- + candidate's curriculum vitae: + {cv} + ---------------------------- + + + **Expected Output**: + Follow the data schema from AIProfile + + + **Instructions**: + 1. Read the provided CV and extract information needed based on expected output. + 2. Reformat the extracted info using correct word spacing. + 3. Do not verbose, just return the final answer. + """.strip() + prompt = ChatPromptTemplate.from_template(extract_one_profile_prompt) + input_llm = { + "cv": raw_profile.get("content") + } + # llm = model_4o_2.with_structured_output(AIProfile) + llm = model_4o_2.with_structured_output(AIProfile) + + gen_ai = BaseAIGenerator( + task_name=self.extract.__name__, + prompt=prompt, + input_llm=input_llm, + llm=llm, + metadata_observability=MetadataObservability( + fullname="local test", + task_id=raw_profile.get("profile_id"), + agent=self.extract.__name__, + ) + ) + result = await gen_ai.agenerate() + # result = asyncio.run(gen_ai.agenerate()) + + if result: + logger.info(f"✅ extract one profile success") + return result + else: + logger.error(f"""❌ extract one profile failed, something went wrong for profile_id {raw_profile.get("profile_id")}""") + return {} + except Exception as E: + logger.error(f"""❌ extract one profile error for profile_id {raw_profile.get("profile_id")}, {E}""") + return {} + + + + # @trace_runtime + # async def extract_bulk_profile(self, raw_profiles: List[RawProfile]) -> Profiles: + # try: + # profiles = [] + # failed_id = [] + # for _, cv_text in enumerate(raw_profiles): + # profile = await self.extract(cv_text.get("content")) + # time.sleep(2) + # if profile: + # logger.info(f"✅ extract bulk profile success [{_+1}/{len(raw_profiles)}]") + # profiles.append(profile) + # else: + # logger.info(f"""❌ extract bulk profile error for profile {cv_text.get("profile_id")}, [{_+1}/{len(raw_profiles)}]""") + # profiles[cv_text.get("profile_id")] = profile + # failed_id.append(cv_text.get("profile_id")) + + # bulk_profile = Profiles( + # profiles=profiles + # ) + # return bulk_profile + # except Exception as E: + # logger.error(f"❌ extract bulk profile error for profile_id {failed_id}, {E}") + # return Profiles( + # profiles=[] + # ) diff --git a/services/knowledge/get_profile.py b/services/knowledge/get_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..c65ba06a2f718061c09dc9152758d1548d7f200e --- /dev/null +++ b/services/knowledge/get_profile.py @@ -0,0 +1,74 @@ +from externals.databases.pg_crud import get_profile_by_filename, get_profile_by_id +from externals.databases.pg_models import CVUser, CVProfile +from services.models.data_model import Profile +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List, Dict, Generator, Union, Any +from utils.logger import get_logger + +logger = get_logger("get profile") + + +class KnowledgeGetProfileService: + + def __init__(self, db: AsyncSession, user: CVUser): + self.db = db + self.user = user + + async def get_by_filename(self, filename: str) -> CVProfile | None: + """ + Retrieve extracted profile securely + """ + + logger.info(f"📄 Fetching profile: {filename}") + + profile = await get_profile_by_filename(self.db, filename) + if not profile: + return None + + # 🔐 Tenant isolation + if profile.tenant_id != self.user.tenant_id: + raise PermissionError("Access denied") + + return profile + + + async def get_profile(self, profile_id: str) -> CVProfile: + try: + profile = await get_profile_by_id(profile_id=profile_id) + return profile + except Exception as E: + logger.error(f"❌ get profile error for profile_id {profile_id}, {E}") + return {} + + + async def get_profile_generator(self, profile_id: str): + try: + profile = await get_profile_by_id(profile_id=profile_id) + yield profile + except Exception as E: + logger.error(f"❌ get profile error for profile_id {profile_id}, {E}") + return + + + async def get_profiles_generator(self, profile_ids: List[str]) -> Dict[str, Union[Generator, Any]]: + try: + profiles = {} + failed_ids = [] + for profile_id in profile_ids: + temp_profile_generators = self.get_profile_generator(profile_id=profile_id) + + if temp_profile_generators: # if the variable is a generator + profiles[profile_id] = temp_profile_generators + else: + profiles[profile_id] = temp_profile_generators + failed_ids.append(profile_id) + + if failed_ids: + logger.warning(f"⚠️ get profile success [{len(profile_ids)-len(failed_ids)}/{len(failed_ids)}] success, error for profile_id {failed_ids}") + return profiles + else: + logger.info(f"✅ get profiles success") + return profiles + except Exception as E: + logger.error(f"❌ get profile error, {E}") + return {} \ No newline at end of file diff --git a/services/knowledge/knowledge_setup.py b/services/knowledge/knowledge_setup.py new file mode 100644 index 0000000000000000000000000000000000000000..898ad2aad187bb789cae0c2dd9fafa20e4a207c1 --- /dev/null +++ b/services/knowledge/knowledge_setup.py @@ -0,0 +1,33 @@ +# import os, sys +# from typing import List + +# from externals.databases.pg_crud import create_profile, get_profile_by_id + +# from services.models.data_model import RawProfile, Profile, AIProfile, Profiles, ResponseExtractOne, ResponseExtractBulk +# from services.knowledge.extract_profile import extract_one_profile as extract_one, extract_bulk_profile as extract_bulk + + +from utils.logger import get_logger +logger = get_logger("knowledge setup") + +from sqlalchemy.ext.asyncio import AsyncSession +from externals.databases.pg_models import CVUser +from services.knowledge.upload_file import KnowledgeFileService +from services.knowledge.get_profile import KnowledgeGetProfileService +from services.knowledge.delete_file import KnowledgeDeleteService +from services.knowledge.extract_profile import KnowledgeExtractService + + +class KnowledgeService: + """ + Facade / Orchestrator for all Knowledge services + """ + + def __init__(self, db: AsyncSession, user: CVUser): + self.db = db + self.user = user + + self.file = KnowledgeFileService(db, user) + self.profile = KnowledgeGetProfileService(db, user) + self.delete = KnowledgeDeleteService(db, user) + self.extract = KnowledgeExtractService(db, user) diff --git a/services/knowledge/upload_file.py b/services/knowledge/upload_file.py new file mode 100644 index 0000000000000000000000000000000000000000..9732ee836c9f6da50766bff0099a98b0a6f8dea1 --- /dev/null +++ b/services/knowledge/upload_file.py @@ -0,0 +1,174 @@ +from fastapi import UploadFile +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.exc import IntegrityError +from externals.storages.azure_blob import upload_pdf as upload_file +from externals.databases.pg_crud import get_file_by_filename, get_file_by_user_id +from externals.databases.pg_models import CVFile, CVUser +from utils.logger import get_logger + +logger = get_logger("knowledge.upload") + + +class KnowledgeFileService: + def __init__(self, db, user: CVUser): + self.db = db + self.user = user + + async def upload(self, file: UploadFile) -> CVFile: + """ + Upload PDF to Azure Blob Storage and log metadata into cv_file table + """ + + logger.info( + "📤 Knowledge upload requested", + extra={"context": { + "cv_filename": file.filename, + "file_content_type": file.content_type, + "user_id": str(self.user.user_id), + "tenant_id": str(self.user.tenant_id), + }} + ) + + # 1️⃣ Check DB first (idempotent behavior) + existing = await get_file_by_filename(self.db, + filename=file.filename, + user_id=self.user.user_id) + if existing: + logger.info( + "ℹ️ File already exists, skipping upload", + extra={"context": { + "filename": file.filename, + "file_id": str(existing.file_id), + }} + ) + return existing + else: + # 2️⃣ Upload to Azure Blob + upload_result = await upload_file(file, self.user.tenant_id, self.user.user_id) + + if not upload_result.get("uploaded"): + logger.error( + "❌ Azure upload failed", + extra={"context": {"filename": file.filename}}, + ) + raise RuntimeError(upload_result.get("message", "Upload failed")) + + # 3️⃣ Persist metadata into DB + cv_file = CVFile( + user_id=self.user.user_id, + file_type=file.content_type or "application/pdf", + filename=file.filename, + url=upload_result["url"], + is_extracted=False, + ) + + try: + self.db.add(cv_file) + await self.db.commit() + await self.db.refresh(cv_file) + + logger.info("✅ File successfully logged", extra={"context": { + "file_id": str(cv_file.file_id), + "filename": cv_file.filename, + "uploaded_by": self.user.email, + }}) + + return cv_file + + except IntegrityError: + await self.db.rollback() + + logger.warning( + "⚠️ Duplicate file detected during insert", + extra={"context": {"filename": file.filename}}, + ) + + # Fetch the already-existing row + existing = await get_file_by_filename(self.db, + filename=file.filename, + user_id=self.user.user_id) + if existing: + return existing + + + + + async def get_files_by_user(self, user_id: str): + """ + Retrieve all file metadata uploaded by a specific user. + """ + + logger.info( + "📄 Fetching files for user", + extra={"context": { + "requested_user_id": user_id, + "requested_by": str(self.user.user_id), + }} + ) + + files = await get_file_by_user_id( + self.db, + user_id=user_id + ) + + file_list = [] + for file in files: + file_list.append({ + "file_id": str(file.file_id), + "filename": file.filename, + "file_type": file.file_type, + "url": file.url, + "is_extracted": file.is_extracted, + "uploaded_at": file.uploaded_at.isoformat(), + "date_modified": file.date_modified.isoformat(), + }) + + logger.info( + "✅ Files retrieved successfully", + extra={"context": { + "file_count": len(file_list), + "requested_user_id": user_id, + }} + ) + + return file_list + +# class KnowledgeUploadService: + +# def __init__(self, db: AsyncSession, user: CVUser): +# self.db = db +# self.user = user + +# async def upload(self, file: UploadFile) -> CVFile: +# """ +# Upload file to Azure Blob and log metadata to cv_file table +# """ + +# logger.info(f"📤 Uploading file: {file.filename}") + +# # 1️⃣ Upload to Azure Blob +# upload_result = await upload_file(file) + +# if not upload_result.get("uploaded"): +# raise RuntimeError(upload_result.get("message")) + +# # 2️⃣ Check existing file record +# existing = await get_file_by_filename(self.db, file.filename) +# if existing: +# logger.info(f"ℹ️ File already exists in DB: {file.filename}") +# return existing + +# # 3️⃣ Persist metadata +# cv_file = CVFile( +# file_type=file.content_type or "application/pdf", +# filename=file.filename, +# url=upload_result["url"], +# is_extracted=False, +# ) + +# self.db.add(cv_file) +# await self.db.commit() +# await self.db.refresh(cv_file) + +# logger.info(f"✅ File logged into cv_file: {file.filename}") +# return cv_file diff --git a/services/knowledge_base/PipelineKBIngestion.py b/services/knowledge_base/PipelineKBIngestion.py new file mode 100644 index 0000000000000000000000000000000000000000..f77bc420e968354e5b1d11f14783e299a482e506 --- /dev/null +++ b/services/knowledge_base/PipelineKBIngestion.py @@ -0,0 +1,173 @@ +import io +import time +import base64 +import asyncio +# import requests +import pandas as pd +import asyncio, aiohttp +from PyPDF2 import PdfReader +# from typing import List +from services.agents.AutograderAgent import AutograderAgent +# from multiprocessing import Pool +from functools import wraps +from typing import List + +# LOAD URLS CV +urls = pd.read_excel("src/knowledge_base/CV_urls.xlsx", engine='openpyxl') +urls = urls["url_cv"].tolist() +print(len(urls)) +autograder_agent = AutograderAgent() + + +def measure_runtime(func): + if asyncio.iscoroutinefunction(func): + @wraps(func) + async def async_wrapper(*args, **kwargs): + start = time.perf_counter() + result = await func(*args, **kwargs) + end = time.perf_counter() + print(f"⏱️ Async function '{func.__name__}' executed in {end - start:.10f} seconds") + return result + return async_wrapper + + else: + @wraps(func) + def sync_wrapper(*args, **kwargs): + start = time.perf_counter() + result = func(*args, **kwargs) + end = time.perf_counter() + print(f"⏱️ Function '{func.__name__}' executed in {end - start:.10f} seconds") + return result + return sync_wrapper + +async def response_builder(url, session): + async with session.get(url) as response: + if response.status == 200: + content = await response.read() + # enc_content = base64.encodebytes(content) + return {url: content} + else: + print(f"Failed to fetch {url} with status {response.status}, {response}") + +@measure_runtime +async def afetch_urls(urls): + async with aiohttp.ClientSession() as session: + tasks = [response_builder(url, session) for url in urls] + result = await asyncio.gather(*tasks) + return result + + + +# INGEST TO DB +# res = asyncio.run(afetch_urls(urls[:3])) +# len(res) + +# res[-1].keys() + +# reader = PdfReader(io.BytesIO(base64.decodebytes(res[-1]))) +# reader.pages[0].extract_text() + +from externals.databases._pgdb import execute_query, execute_insert + +# template_ingest_to_cv_raw = """ +# insert into cv_raw (filename, file_content) +# values ('{filename}', '{file_content}'); +# """.format(filename=list(res[-1].keys())[0], +# file_content=res[-1][list(res[-1].keys())[0]] +# ) + +async def RawIngest(urls: List[str]): + try: + response = await afetch_urls(urls) + for res in response: + await execute_insert(filename=list(res.keys())[0], + file_content=res[list(res.keys())[0]]) + except Exception as E: + print(f"❌ Error when Ingesting to cv_raw, {E}") + + +async def run_rawingest_pipeline(): + chunk_size = 20 + urls_sample = urls[-2000:-1000] + for chunk in range(0, len(urls_sample), chunk_size): + chunk_urls = urls_sample[chunk:chunk+chunk_size] + await RawIngest(urls=chunk_urls) + + +asyncio.run(run_rawingest_pipeline()) + + +# async def get_cv_from_url(url:str) -> dict: +# try: +# response = requests.get(url) +# return {f"{url}":response.content} +# except: +# print(f"Failed to get cv from {url}") +# return {f"{url}":b""} + + +# def get_cv_from_urls_na(urls: List) -> List: +# _st = time.time() +# cvs = [] +# n_urls = len(urls) +# for i, url in enumerate(urls): +# response = requests.get(url) +# cv = {f"{url}":response.content} +# cvs.append(cv) +# print(f"Loading... {round((i+1)*100/n_urls)}%") +# _rt = time.time() - _st +# print(f"✅ Get CV from urls finished in {round(_rt,2)}s") +# return cvs + +# async def get_cv_from_urls(urls: List, BATCH_SIZE:int=1000): +# _st = time.time() +# print(f"Loading... 0%") +# N_BATCH = (len(urls) // BATCH_SIZE) + (1 if (len(urls) % BATCH_SIZE) > 0 else 0) +# batched_urls = [] +# for i in range(N_BATCH): +# one_batch_urls = urls[(i)*BATCH_SIZE:(i+1)*BATCH_SIZE] +# batched_urls.append(one_batch_urls) + +# cvs = [] +# for i, one_batch_urls in enumerate(batched_urls): +# tasks = [] +# for url in one_batch_urls: +# task = asyncio.create_task(get_cv_from_url(url)) +# tasks.append(task) + +# one_batch_cvs = await asyncio.gather(*tasks) +# print(f"Loading... {round((i+1)*100/len(batched_urls))}%") +# cvs.extend(one_batch_cvs) +# _rt = time.time() - _st +# print(f"✅ Get CV from urls finished in {round(_rt,2)}s") +# return cvs + + +# import io +# from src.utils.utils import pdf_reader +# from PyPDF2 import PdfReader + +# cvs = asyncio.run(get_cv_from_urls(urls[:100], BATCH_SIZE=2)) #154.68s +# cvs = asyncio.run(get_cv_from_urls(urls[:100], BATCH_SIZE=2)) #154.68s +# len(cvs) + +# cvs = get_cv_from_urls_na(urls[:100]) #163.93s + +# url_img = "https://api.typeform.com/responses/files/915940175d9054dec0a8cec98bc3d5345bed0153ed7ffdd60514a94e1055ee57/CV_Dhanendra_Wiryohutomo.pdf" +# res = asyncio.run(get_cv_from_url(url_img)) +# cv_img = res[list(res.keys())[0]] + +# cv = cvs[0][list(cvs[0].keys())[0]] +# reader = asyncio.run(pdf_reader(cv)) +# print(reader) + +# reader = PdfReader(io.BytesIO(cv_img)) +# reader = asyncio.run(pdf_reader(io.BytesIO(cv_img))) +# reader = asyncio.run(pdf_reader(cv_img)) + +# user_profile = "" +# for page in reader.pages: +# text = page.extract_text() +# if text: +# user_profile += text + "\n" +# print(user_profile) \ No newline at end of file diff --git a/services/llms/LLM.py b/services/llms/LLM.py new file mode 100644 index 0000000000000000000000000000000000000000..27bebd8de9c33a1022466e247a147ae4dfbc7bbc --- /dev/null +++ b/services/llms/LLM.py @@ -0,0 +1,88 @@ +import os +from dotenv import load_dotenv +load_dotenv() +from langchain_openai import AzureChatOpenAI +# from langchain_google_genai import ChatGoogleGenerativeAI +# from langchain.callbacks import AsyncIteratorCallbackHandler +# from langfuse.callback import CallbackHandler + + +# langfuse_handler = CallbackHandler( +# secret_key=os.environ.get('buma--langfuse--secret-key'), +# public_key=os.environ.get('buma--langfuse--public-key'), +# host=os.environ.get('buma--langfuse--host') +# ) + + +####### +# LLM +####### + +# model_4o = AzureChatOpenAI( +# azure_endpoint=os.environ.get("azureai--endpoint--url--4o"), # or your deployment +# openai_api_version=os.environ.get("azureai--api--version--4o"), # or your api version +# deployment_name=os.environ.get("azureai--deployment--name--4o"), +# openai_api_key=os.environ.get("azureai--api-key--4o"), +# openai_api_type="azure", +# max_retries=2, +# disable_streaming=True +# ) + +model_4o_2 = AzureChatOpenAI( + azure_endpoint=os.environ.get("azureai--endpoint--url--4o-2"), # or your deployment + openai_api_version=os.environ.get("azureai--api--version--4o-2"), # or your api version + deployment_name=os.environ.get("azureai--deployment--name--4o-2"), + openai_api_key=os.environ.get("azureai--api-key--4o-2"), + openai_api_type="azure", + max_retries=2, + disable_streaming=True +) + +model_4omini = AzureChatOpenAI( + azure_endpoint=os.environ.get("azureai--endpoint--url--4omini"), # or your deployment + openai_api_version=os.environ.get("azureai--api--version--4omini"), # or your api version + deployment_name=os.environ.get("azureai--deployment--name--4omini"), + openai_api_key=os.environ.get("azureai--api-key--4omini"), + openai_api_type="azure", + max_retries=2, + disable_streaming=True +) + +model_5mini = AzureChatOpenAI( + azure_endpoint=os.environ.get("azureai--endpoint--url--5mini"), # or your deployment + openai_api_version=os.environ.get("azureai--api--version--5mini"), # or your api version + deployment_name=os.environ.get("azureai--deployment--name--5mini"), + openai_api_key=os.environ.get("azureai--api-key--5mini"), + openai_api_type="azure", + max_retries=2, + disable_streaming=True +) + +# model_5_1 = AzureChatOpenAI( +# azure_endpoint=os.environ.get("azureai--endpoint--url--5.1"), +# openai_api_version=os.environ.get("azureai--api--version--5.1"), +# deployment_name=os.environ.get("azureai--deployment--name--5.1"), +# openai_api_key=os.environ.get("azureai--api-key--5.1"), +# openai_api_type="azure", +# max_retries=2, +# disable_streaming=True +# ) + +# model_5_1codex = AzureChatOpenAI( +# azure_endpoint=os.environ.get("azureai--endpoint--url--5.1-codex"), +# openai_api_version=os.environ.get("azureai--api--version--5.1-codex"), +# deployment_name=os.environ.get("azureai--deployment--name--5.1-codex"), +# openai_api_key=os.environ.get("azureai--api-key--5.1-codex"), +# openai_api_type="azure", +# max_retries=2, +# disable_streaming=True +# ) + +# model_gemini = ChatGoogleGenerativeAI( +# model="gemini-2.0-flash", +# disable_streaming=False, +# # callbacks=[callback], +# verbose=True) + +# response = model_gemini.invoke("Buatkan satu lagu dalam bahasa indonesia, bertema pertemanan") +# print(response.content) \ No newline at end of file diff --git a/services/llms/__init__.py b/services/llms/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..45cd6281697eb88ea87bb02bfc1ad600e04b51bb --- /dev/null +++ b/services/llms/__init__.py @@ -0,0 +1,3 @@ +__all__ = ['model_4omini', 'model_5mini', 'model_4o_2'] + +from .LLM import model_4omini, model_5mini, model_4o_2 \ No newline at end of file diff --git a/services/models/data_model.py b/services/models/data_model.py new file mode 100644 index 0000000000000000000000000000000000000000..182927603fb11f22a8db0a12b1a34985cc7a6915 --- /dev/null +++ b/services/models/data_model.py @@ -0,0 +1,230 @@ +from config.get_config import master_config +from datetime import datetime +from pydantic import Field, BaseModel +from typing import Optional, List, Literal, Dict +from typing_extensions import TypedDict +from uuid import uuid4 + + + +tzinfo = master_config.tzinfo + +LOGIC_NUMERIC = Literal["greater than", + "less than", + "equal", + "greater than or equal", + "less than or equal" + ] + +LOGIC_CATEGORICAL = Literal[ + "equal", + "similar", + "not similar"] + + +class RawProfile(TypedDict): + profile_id: str + content_type: Literal["pdf", "docx", "txt"] = "pdf" + filename: str + content: str + +class AIProfile(TypedDict): + fullname: str = Field(description="Fullname of the candidate", default="-") + # gender: str = Field(description="Gender of the candidate, if available", default="null") + # age: int = Field(description="Age in number") + gpa_edu_1: float = Field(description="""GPA of candidate's bachelor degree, if exists.""", default=0) + univ_edu_1: str = Field(description="""University where candidate take bachelor degree, if exists.""", default="-") + major_edu_1: str = Field(description="""Major of candidate's bachelor degree, if exists.""", default="-") + + gpa_edu_2: float = Field(description="""GPA of candidate's master degree, if exists.""", default=0) + univ_edu_2: str = Field(description="""University where candidate take master degree, if exists.""", default="-") + major_edu_2: str = Field(description="""Major of candidate's master degree, if exists.""", default="-") + + gpa_edu_3: float = Field(description="""GPA of candidate's doctoral or phd degree, if exists.""", default=0) + univ_edu_3: str = Field(description="""University where candidate take doctoral or phd degree, if exists.""", default="-") + major_edu_3: str = Field(description="""Major of candidate's doctoral or phd degree, if exists.""", default="-") + + domicile: str = Field(description="Current domicile of the candidate", default="-") + + yoe: float = Field(description="The candidate's total years of experience (as an float)", default=0) + hardskills: Optional[List[str]] = Field(description="List of the candidate's hard skills", default=[]) + softskills: Optional[List[str]] = Field(description="List of the candidate's soft skills", default=[]) + certifications: Optional[List[str]] = Field(description="List of the candidate's certifications", default=[]) + business_domain: Optional[List[str]] = Field(description="List of the candidate's business domain experience based on working experience or project", default=[]) + +class Profile(AIProfile): + profile_id: str + created_at: datetime = datetime.now().replace(tzinfo=tzinfo) + +class Profiles(TypedDict): + profiles: List[Profile] + +class Criteria(TypedDict): + gpa_edu_1: Optional[float] = None + univ_edu_1: Optional[str] = None + major_edu_1: Optional[str] = None + gpa_edu_2: Optional[float] = None + univ_edu_2: Optional[str] = None + major_edu_2: Optional[str] = None + gpa_edu_3: Optional[float] = None + univ_edu_3: Optional[str] = None + major_edu_3: Optional[str] = None + domicile: Optional[str] = None + yoe: Optional[int] = None + hardskills: Optional[List] = None + softskills: Optional[List] = None + certifications: Optional[List] = None + business_domain: Optional[List] = None + + +class CriteriaWeight(TypedDict): + gpa_edu_1: Optional[float] = None + univ_edu_1: Optional[float] = None + major_edu_1: Optional[float] = None + gpa_edu_2: Optional[float] = None + univ_edu_2: Optional[float] = None + major_edu_2: Optional[float] = None + gpa_edu_3: Optional[float] = None + univ_edu_3: Optional[float] = None + major_edu_3: Optional[float] = None + domicile: Optional[float] = None + yoe: Optional[float] = None + hardskills: Optional[float] = None + softskills: Optional[float] = None + certifications: Optional[float] = None + business_domain: Optional[float] = None + + +# class InputScoring(AIProfile): +# profile_id: str = Field(description="profile id") +# criteria: Criteria = Field(description="Criteria to be matched with the profile") +# criteria_weight: CriteriaWeight = Field(description="Criteria weight to be applied when profile matching") + +class InputScoring(TypedDict): + profile_id: str = Field(description="profile id") + weight_id: str = Field(description="weight id") + +class InputScoringBulk(TypedDict): + profile_ids: List = Field(description="list of profile id") + criteria: Criteria = Field(description="Criteria to be matched with the profile") + criteria_weight: CriteriaWeight = Field(description="Criteria weight to be applied when profile matching") + +class PayloadExtractOne(TypedDict): + profile_id: str = str(uuid4()) + filename: str + content_type: Literal["pdf", "docx", "txt"] = "pdf" + content: str +class DataResponseExtractOne(TypedDict): + profile_id: Optional[str] +class ResponseExtractOne(TypedDict): + status: Literal["success", "failed", "canceled"] + message: Optional[str] = "empty" + data: Optional[DataResponseExtractOne] = None + + +# EXTRACT PROFILE BULK +class DataResponseExtractBulk(TypedDict): + status_ids: Dict + criteria_id: str +class PayloadExtractBulk(TypedDict): + profile_id: str + content_type: Literal["pdf", "docx", "txt"] = "pdf" + content: str +class ResponseExtractBulk(TypedDict): + status: Literal["success", "partial-success", "failed", "canceled"] + message: Optional[str] + data: Optional[DataResponseExtractBulk] = None + + +# MATCH PROFILE ONE +class PayloadMatchOne(TypedDict): + profile_id: str + criteria: Criteria + criteria_weight: CriteriaWeight + +class Score(TypedDict): + profile_id: str + score: float +class DataResponseMatchOne(TypedDict): + profile_id: str + criteria_id: Optional[str] = None + matching_id: Optional[str] = None + scoring_id: Optional[str] = None + score: Optional[float] = None +class ResponseMatchOne(Score): + status: Literal["success", "failed", "canceled"] + message: Optional[str] = None + data: Optional[DataResponseMatchOne] = None + + +# MATCH PROFILE BULK +class DataResponseMatchBulk(TypedDict): + status_ids: Dict + criteria_id: str +class PayloadMatchBulk(TypedDict): + filter: List[str] + criteria: Criteria + criteria_weight: CriteriaWeight +class ResponseMatchBulk(TypedDict): + status: Literal["success", "partial-success", "failed", "canceled"] + message: Optional[str] + data: Optional[DataResponseExtractBulk] = None + +# class DataResponseExtractBulk(TypedDict): +# status_ids: Dict +# criteria_id: str +# class PayloadExtractBulk(TypedDict): +# profile_id: str +# content_type: Literal["pdf", "docx", "txt"] = "pdf" +# content: str +# class ResponseExtractBulk(TypedDict): +# status: Literal["success", "partial-success", "failed", "canceled"] +# message: Optional[str] +# data: Optional[DataResponseExtractBulk] = None + + +desc_AIMatchProfile = "choose 1 if match else 0" +class AIMatchProfile(TypedDict): + gpa_edu_1: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + univ_edu_1: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + major_edu_1: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + gpa_edu_2: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + univ_edu_2: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + major_edu_2: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + gpa_edu_3: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + univ_edu_3: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + major_edu_3: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + domicile: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + yoe: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + hardskills: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + softskills: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + certifications: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + business_domain: Optional[Literal[1, 0]] = Field(description=desc_AIMatchProfile, default=None) + + +class OutProfile(BaseModel): + fullname: str = Field(description="Fullname of the candidate", default="-") + # gender: str = Field(description="Gender of the candidate, if available", default="null") + # age: int = Field(description="Age in number") + high_edu_univ_1: str = Field(description="""University where candidate take bachelor degree, if exists.""", default="-") + high_edu_major_1: str = Field(description="""Major of candidate's bachelor degree, if exists.""", default="-") + high_edu_gpa_1: float = Field(description="""GPA of candidate's bachelor degree, if exists.""", default=0) + + high_edu_univ_2: str = Field(description="""University where candidate take master degree, if exists.""", default="-") + high_edu_major_2: str = Field(description="""Major of candidate's master degree, if exists.""", default="-") + high_edu_gpa_2: float = Field(description="""GPA of candidate's master degree, if exists.""", default=0) + + high_edu_univ_3: str = Field(description="""University where candidate take doctoral or phd degree, if exists.""", default="-") + high_edu_major_3: str = Field(description="""Major of candidate's doctoral or phd degree, if exists.""", default="-") + high_edu_gpa_3: float = Field(description="""GPA of candidate's doctoral or phd degree, if exists.""", default=0) + domicile: str = Field(description="Current domicile of the candidate", default="-") + + yoe: float = Field(description="The candidate's total years of experience (as an float)", default=0) + hardskills: Optional[List[str]] = Field(description="List of the candidate's hard skills", default=[]) + softskills: Optional[List[str]] = Field(description="List of the candidate's soft skills", default=[]) + certifications: Optional[List[str]] = Field(description="List of the candidate's certifications", default=[]) + business_domain_experiences: Optional[List[str]] = Field(description="List of the candidate's business domain experience based on working experience or project", default=[]) + +class OutMatching(BaseModel): + score: int = Field(description="Score of profile matching, in range 0-100. If profile and criteria is closed then will give higher score.", default=0) + reason: str = Field(description="Reason behind why you give that such score to current profile.", default="-") diff --git a/services/pipelines/PipelineKBIngestion.py b/services/pipelines/PipelineKBIngestion.py new file mode 100644 index 0000000000000000000000000000000000000000..20c33c70d690f1bc9ff1fbcc59410719191de51f --- /dev/null +++ b/services/pipelines/PipelineKBIngestion.py @@ -0,0 +1,161 @@ +import os +# os.chdir("../") +# print(f"Current working directory: {os.getcwd()}") +# import io +# import time +# import base64 +import asyncio +# import requests +import pandas as pd +import asyncio, aiohttp +# from typing import List +# from multiprocessing import Pool +from PyPDF2 import PdfReader +from typing import List +from services.agents.AutograderAgent import AutograderAgent +from externals.databases._pgdb import fetch_data, execute_query, execute_insert_binary +from utils.utils import measure_runtime +# from agents.AutograderAgent import AutograderAgent +# from databases.pgdb import fetch_data, execute_query, execute_insert_binary +# from utils.utils import measure_runtime + +# LOAD URLS CV +urls = pd.read_excel("src/knowledge_base/CV_urls.xlsx", engine='openpyxl') +urls = urls["url_cv"].tolist() +print(len(urls)) +autograder_agent = AutograderAgent() + + +async def response_builder(url, session): + async with session.get(url) as response: + if response.status == 200: + content = await response.read() + # enc_content = base64.encodebytes(content) + return {url: content} + else: + print(f"Failed to fetch {url} with status {response.status}, {response}") + +@measure_runtime +async def afetch_urls(urls): + async with aiohttp.ClientSession() as session: + tasks = [response_builder(url, session) for url in urls] + result = await asyncio.gather(*tasks) + return result + + + +# INGEST TO DB +# res = asyncio.run(afetch_urls(urls[:3])) +# len(res) + +# res[-1].keys() + +# reader = PdfReader(io.BytesIO(base64.decodebytes(res[-1]))) +# reader.pages[0].extract_text() + + +# template_ingest_to_cv_raw = """ +# insert into cv_raw (filename, file_content) +# values ('{filename}', '{file_content}'); +# """.format(filename=list(res[-1].keys())[0], +# file_content=res[-1][list(res[-1].keys())[0]] +# ) + +async def RawIngest(urls: List[str]): + try: + response = await afetch_urls(urls) + for res in response: + await execute_insert_binary(filename=list(res.keys())[0], + file_content=res[list(res.keys())[0]]) + except Exception as E: + print(f"❌ Error when Ingesting to cv_raw, {E}") + + +async def run_rawingest_pipeline(): + chunk_size = 20 + ingested_filenames = await fetch_data("select distinct filename from cv_raw;") + ingested_filenames = [f["filename"] for f in ingested_filenames] + urls_focus = [u for u in urls if u not in ingested_filenames] + + for chunk in range(0, len(urls_focus), chunk_size): + chunk_urls = urls_focus[chunk:chunk+chunk_size] + await RawIngest(urls=chunk_urls) + + +asyncio.run(run_rawingest_pipeline()) + + +# async def get_cv_from_url(url:str) -> dict: +# try: +# response = requests.get(url) +# return {f"{url}":response.content} +# except: +# print(f"Failed to get cv from {url}") +# return {f"{url}":b""} + + +# def get_cv_from_urls_na(urls: List) -> List: +# _st = time.time() +# cvs = [] +# n_urls = len(urls) +# for i, url in enumerate(urls): +# response = requests.get(url) +# cv = {f"{url}":response.content} +# cvs.append(cv) +# print(f"Loading... {round((i+1)*100/n_urls)}%") +# _rt = time.time() - _st +# print(f"✅ Get CV from urls finished in {round(_rt,2)}s") +# return cvs + +# async def get_cv_from_urls(urls: List, BATCH_SIZE:int=1000): +# _st = time.time() +# print(f"Loading... 0%") +# N_BATCH = (len(urls) // BATCH_SIZE) + (1 if (len(urls) % BATCH_SIZE) > 0 else 0) +# batched_urls = [] +# for i in range(N_BATCH): +# one_batch_urls = urls[(i)*BATCH_SIZE:(i+1)*BATCH_SIZE] +# batched_urls.append(one_batch_urls) + +# cvs = [] +# for i, one_batch_urls in enumerate(batched_urls): +# tasks = [] +# for url in one_batch_urls: +# task = asyncio.create_task(get_cv_from_url(url)) +# tasks.append(task) + +# one_batch_cvs = await asyncio.gather(*tasks) +# print(f"Loading... {round((i+1)*100/len(batched_urls))}%") +# cvs.extend(one_batch_cvs) +# _rt = time.time() - _st +# print(f"✅ Get CV from urls finished in {round(_rt,2)}s") +# return cvs + + +# import io +# from src.utils.utils import pdf_reader +# from PyPDF2 import PdfReader + +# cvs = asyncio.run(get_cv_from_urls(urls[:100], BATCH_SIZE=2)) #154.68s +# cvs = asyncio.run(get_cv_from_urls(urls[:100], BATCH_SIZE=2)) #154.68s +# len(cvs) + +# cvs = get_cv_from_urls_na(urls[:100]) #163.93s + +# url_img = "https://api.typeform.com/responses/files/915940175d9054dec0a8cec98bc3d5345bed0153ed7ffdd60514a94e1055ee57/CV_Dhanendra_Wiryohutomo.pdf" +# res = asyncio.run(get_cv_from_url(url_img)) +# cv_img = res[list(res.keys())[0]] + +# cv = cvs[0][list(cvs[0].keys())[0]] +# reader = asyncio.run(pdf_reader(cv)) +# print(reader) + +# reader = PdfReader(io.BytesIO(cv_img)) +# reader = asyncio.run(pdf_reader(io.BytesIO(cv_img))) +# reader = asyncio.run(pdf_reader(cv_img)) + +# user_profile = "" +# for page in reader.pages: +# text = page.extract_text() +# if text: +# user_profile += text + "\n" +# print(user_profile) \ No newline at end of file diff --git a/services/pipelines/PipelineKBProfileExtraction.py b/services/pipelines/PipelineKBProfileExtraction.py new file mode 100644 index 0000000000000000000000000000000000000000..716b88ac23286401ade002c66dbe14dddac346cd --- /dev/null +++ b/services/pipelines/PipelineKBProfileExtraction.py @@ -0,0 +1,202 @@ +# retrieve data dari table cv_raw, extract profile, insert profile ke table cv_profile_extracted +import json +import asyncio +from typing import ByteString, Dict, List +from services.llms.LLM import model_4o_2 +from services.prompts.profile_extraction import extract_one_profile +from externals.databases._pgdb import fetch_data, execute_query +from models.data_model import OutProfile, Union +from utils.utils import pdf_reader, measure_runtime + + +query_get_cv_raw = "select profile_id, file_content " \ +"from public.cv_raw " \ +"where is_extracted = false " \ +"limit {batch_size};" + +query_get_cv_raw_excluded_id = "select profile_id, file_content " \ +"from public.cv_raw " \ +"where is_extracted = false " \ +"and profile_id not in {failed_id}" \ +"limit {batch_size};" + + +query_get_cv_raw_by_id = "select profile_id, file_content " \ +"from public.cv_raw " \ +"where profile_id = {profile_id};" + +query_update_cv_raw = """ +UPDATE cv_raw +SET is_extracted = true +WHERE profile_id = {profile_id}; +""" + +async def retrieve_raw_profiles(batch_size: int = 10, failed_id: List = []): + if failed_id == []: + query = query_get_cv_raw.format(batch_size=batch_size) + else: + query = query_get_cv_raw_excluded_id.format(failed_id=tuple(failed_id), batch_size=batch_size) + data = await fetch_data(query) + return data + +async def retrieve_raw_profiles_by_id(id: int): + query = query_get_cv_raw_by_id.format(profile_id=id) + data = await fetch_data(query) + return data + +async def update_raw_profile(profile_id: int): + query = query_update_cv_raw.format(profile_id=profile_id) + await execute_query(query) + + +@measure_runtime +async def extract_profile(file:ByteString): + cv = await pdf_reader(file) + llm = model_4o.with_structured_output(OutProfile) + chain = extract_one_profile | llm + input_chain = { + "cv":cv + } + profile = await chain.ainvoke(input_chain, config=None) + return profile + +def sanitize_type(data:Dict): + data_mutated = data.copy() + neutralized_mapper = { + 'fullname' : "-", + 'high_edu_univ_1' : "-", + 'high_edu_major_1' : "-", + 'high_edu_gpa_1' : 0, + 'high_edu_univ_2' : "-", + 'high_edu_major_2' : "-", + 'high_edu_gpa_2' : 0, + 'high_edu_univ_3' : "-", + 'high_edu_major_3' : "-", + 'high_edu_gpa_3' : 0, + 'domicile' : "-", + 'yoe' : 0, + 'hardskills' : [], + 'softskills' : [], + 'certifications' : [], + 'business_domain_experiences': [] + } + + for k, v in data_mutated.items(): + if v is None or (type(v) == str and v.lower() in ['null', '']): + data_mutated[k] = neutralized_mapper[k] + return data_mutated + +def helper_handle_list_to_text(data:Dict, cols:List): + data_mutated = data.copy() + for col in cols: + if col in data_mutated: + if type(data_mutated[col]) == list and data_mutated[col] != []: + data_mutated[col] = ", ".join([p for p in data_mutated[col]]) + elif type(data_mutated[col]) == list and data_mutated[col] == []: + data_mutated[col] = "-" + return data_mutated + + +query_insert_profile_extracted = """ +insert into cv_profile_extracted +("fullname", "profile_id", +"univ_edu_1", "major_edu_1", "gpa_edu_1", +"univ_edu_2", "major_edu_2", "gpa_edu_2", +"univ_edu_3", "major_edu_3", "gpa_edu_3", +"domicile", "yoe", +"hardskills", "softskills", "certifications", "business_domain") +values +('{fullname}', {profile_id}, +'{high_edu_univ_1}', '{high_edu_major_1}', {high_edu_gpa_1}, +'{high_edu_univ_2}', '{high_edu_major_2}', {high_edu_gpa_2}, +'{high_edu_univ_3}', '{high_edu_major_3}', {high_edu_gpa_3}, +'{domicile}', {yoe}, +'{hardskills}', '{softskills}', '{certifications}', '{business_domain_experiences}'); +""" + +async def wrap_extract_profile(file:ByteString, profile_id: Union[int, str], failed_id: List = []): + try: + extracted_profile = await extract_profile(file) + extracted_profile = sanitize_type(extracted_profile.model_dump()) + extracted_profile = helper_handle_list_to_text(extracted_profile, cols=["hardskills", "softskills", "certifications", "business_domain_experiences"]) + + query = query_insert_profile_extracted.format( + fullname=extracted_profile['fullname'], + profile_id=profile_id, + high_edu_univ_1=extracted_profile['high_edu_univ_1'], + high_edu_major_1=extracted_profile['high_edu_major_1'], + high_edu_gpa_1=extracted_profile['high_edu_gpa_1'], + high_edu_univ_2=extracted_profile['high_edu_univ_2'], + high_edu_major_2=extracted_profile['high_edu_major_2'], + high_edu_gpa_2=extracted_profile['high_edu_gpa_2'], + high_edu_univ_3=extracted_profile['high_edu_univ_3'], + high_edu_major_3=extracted_profile['high_edu_major_3'], + high_edu_gpa_3=extracted_profile['high_edu_gpa_3'], + domicile=extracted_profile['domicile'], + yoe=extracted_profile['yoe'], + hardskills=extracted_profile['hardskills'], + softskills=extracted_profile['softskills'], + certifications=extracted_profile['certifications'], + business_domain_experiences=extracted_profile['business_domain_experiences'] + ) + await execute_query(query) + # check profile inserted + is_inserted = await fetch_data("select profile_id from cv_profile_extracted where profile_id = {profile_id}".format(profile_id=profile_id)) + if is_inserted: + await update_raw_profile(profile_id=profile_id) + print(f"✅ Profile extracted and inserted for profile_id: {profile_id}") + else: + print(f"❌ Profile insertion failed for profile_id: {profile_id}") + except Exception as E: + failed_id.append({profile_id: str(E)}) + print(f"❌ wrap_extract_profile error for profile_id: {profile_id}") + + +# data = asyncio.run(retrieve_raw_profiles_by_id(369)) +# profile_id = data[0]["profile_id"] +# file_content = data[0]["file_content"] +# text = asyncio.run(pdf_reader(file_content)) +# extracted_profile = asyncio.run(extract_profile(file_content)) +# profile = asyncio.run(wrap_extract_profile(file=file_content, profile_id=profile_id)) +# extracted_profile = sanitize_type(extracted_profile.model_dump()) +# extracted_profile = helper_handle_list_to_text(extracted_profile, cols=["hardskills", "softskills", "certifications", "business_domain_experiences"]) + + +async def KBProfileExtraction(batch_size: int = 10, failed_id: List = []): + try: + raw_profiles = await retrieve_raw_profiles(batch_size=batch_size, failed_id=failed_id) + + tasks = [] + for raw_profile in raw_profiles: + profile_id = raw_profile["profile_id"] + file_content = raw_profile["file_content"] + task = asyncio.create_task(wrap_extract_profile(file=file_content, profile_id=profile_id, failed_id=failed_id)) + tasks.append(task) + + extract_profiles = await asyncio.gather(*tasks) + return True + except Exception as E: + print(f"❌ Error extracting profile, {E}") + return False + + +async def run_rawingest_pipeline(): + profile_id_raw = await fetch_data("select distinct profile_id from cv_raw;") + profile_id_raw = [f["profile_id"] for f in profile_id_raw] + profile_id_extracted = await fetch_data("select distinct profile_id from cv_profile_extracted;") + profile_id_extracted = [f["profile_id"] for f in profile_id_extracted] + + profile_id_tobe_extracted = [p for p in profile_id_raw if p not in profile_id_extracted] + + batch_size = 5 + failed_id = [] + nloops = (len(profile_id_tobe_extracted) // batch_size) + (1 if len(profile_id_tobe_extracted) % batch_size > 0 else 0) + + for _ in range(nloops): + await KBProfileExtraction(batch_size=batch_size, failed_id=failed_id) + + with open('failed_id.json', 'w') as fp: + json.dump({"failed_id": failed_id}, fp) + + +asyncio.run(run_rawingest_pipeline()) \ No newline at end of file diff --git a/services/pipelines/PipelineKBProfileNorm.py b/services/pipelines/PipelineKBProfileNorm.py new file mode 100644 index 0000000000000000000000000000000000000000..bd7d9be15e69c0726e63126b39fdf9df976ad1e0 --- /dev/null +++ b/services/pipelines/PipelineKBProfileNorm.py @@ -0,0 +1 @@ +# retrieve data dari table cv_profile_extracted, normalize profile, insert profile ke table cv_profile_norm \ No newline at end of file diff --git a/services/prompts/AutograderPrompt.md b/services/prompts/AutograderPrompt.md new file mode 100644 index 0000000000000000000000000000000000000000..9ce7dee8ac17e27ef19128b925796acc60489008 --- /dev/null +++ b/services/prompts/AutograderPrompt.md @@ -0,0 +1,223 @@ +You are an expert AI career analyst. Given the following user profile, extract the following information and output it in valid JSON format. Only use information that is explicitly present in the user profile. Do not make assumptions or fabricate (hallucinate) any data. If certain information is missing, leave the corresponding field empty or null. Ensure your output is accurate, safe, and based strictly on the provided input. + + +- yoe: The user's total years of experience (as an integer or string). +- last_job: The user's most recent job title. +- skills: Categorize all relevant skills into "hardskill" and "softskill". Inside each, further categorize skills into subcategories (e.g., for hardskill: Programming, Data Analysis, etc.; for softskill: Communication, Leadership, etc.), and list the skills under each subcategory. +- education: Extract the user's degree, major, and GPA (if available). +- projects: List the user's project experiences (personal or professional). + + +The LLM must first think through the extraction and reasoning process, and always its thinking process and final answer with '--response--'. After the thinking section, output only the JSON object as described below. + +Input variable: +{user_profile} +-------- + + + + +Instructions: +1. Analyze the user profile to extract: + - Total years of experience (yoe). If the user is a fresh graduate, calculate yoe only from their internship experience (if available). + - Last job title (last_job) + - All relevant skills, categorized as described above + - Education details: degree, major, and GPA (if available) + - Project experiences (personal or professional) +2. Organize the skills into the required categories and subcategories. + +3. Output the result as a JSON object with the following structure: + +{{ + "personal_info": {{ + "full_name": , + "email": , + "phone": , + "linkedin_profile": , + "portfolio_url": , + "address": {{ + "street": , + "city": , + "state": , + "zip_code": , + "country": + }} + }}, + "summary": , + "yoe":, + "work_experience": [ + {{ + "job_title": , + "company_name": , + "location": , + "start_date": , + "end_date": , + "is_current": , + "responsibilities": [, ], + "achievements": [, ] + }} + ], + "education": [ + {{ + "degree": , + "major": , + "institution": , + "location": , + "start_date": , + "end_date": , + "gpa": + }} + ], + "skills": {{ + "technical_skills": [, ], + "soft_skills": [, ], + "tools_technologies": [, ] + }}, + "projects": [ + {{ + "project_name": , + "description": , + "technologies_used": [, ], + "project_url": , + "start_date": , + "end_date": + }} + ], + "certifications": [ + {{ + "name": , + "issuing_organization": , + "issue_date": , + "expiration_date": + }} + ], + "languages": [ + {{ + "language": , + "proficiency": + }} + ], + "awards_honors": [ + {{ + "name": , + "issuing_organization": , + "date": + }} + ], + "publications": [ + {{ + "title": , + "journal_conference": <journal_conference>, + "publication_date": <YYYY-MM-DD>, + "url": <url> + }} + ], + "interests": [<interest1>, <interest2>], + "character_traits_keywords": [<trait1>, <trait2>] +}} + +If a date (year, month, or day) is not available, assume it as '1' for the missing part(s). For example, if only the year is available, use 'YYYY-01-01'. If year and month are available, use 'YYYY-MM-01'. + + + + +Example output: +{{ + "personal_info": {{ + "full_name": "John Doe", + "email": "john.doe@email.com", + "phone": "+628123456789", + "linkedin_profile": "https://www.linkedin.com/in/johndoe", + "portfolio_url": "https://www.johndoe.com", + "address": {{ + "street": "123 Example St.", + "city": "Jakarta", + "state": "DKI Jakarta", + "zip_code": "12345", + "country": "Indonesia" + }} + }}, + "summary": "Experienced data scientist with a strong background in machine learning and data analysis.", + "yoe": 5, + "work_experience": [ + {{ + "job_title": "Data Scientist", + "company_name": "Tech Solutions", + "location": "Jakarta, Indonesia", + "start_date": "2020-01-01", + "end_date": "2023-06-01", + "is_current": false, + "responsibilities": [ + "Developed predictive models for business analytics", + "Collaborated with cross-functional teams" + ], + "achievements": [ + "Increased model accuracy by 15%", + "Automated data pipeline, reducing processing time by 30%" + ] + }} + ], + "education": [ + {{ + "degree": "Bachelor of Science", + "major": "Computer Science", + "institution": "University of Indonesia", + "location": "Depok, Indonesia", + "start_date": "2015-08-01", + "end_date": "2019-07-01", + "gpa": "3.8" + }} + ], + "skills": {{ + "technical_skills": ["Python", "SQL", "Machine Learning", "Data Analysis"], + "soft_skills": ["Communication", "Teamwork", "Problem Solving"], + "tools_technologies": ["Jira", "Git", "Docker"] + }}, + "projects": [ + {{ + "project_name": "Sentiment Analysis Web App", + "description": "A web application for real-time sentiment analysis of social media data.", + "technologies_used": ["Python", "Flask", "scikit-learn"], + "project_url": "https://github.com/johndoe/sentiment-app", + "start_date": "2021-03-01", + "end_date": "2021-08-01" + }} + ], + "certifications": [ + {{ + "name": "AWS Certified Solutions Architect", + "issuing_organization": "Amazon Web Services", + "issue_date": "2022-05-01", + "expiration_date": "2025-05-01" + }} + ], + "languages": [ + {{ + "language": "English", + "proficiency": "Fluent" + }}, + {{ + "language": "Indonesian", + "proficiency": "Native" + }} + ], + "awards_honors": [ + {{ + "name": "Best Data Science Project", + "issuing_organization": "Tech Conference 2022", + "date": "2022-11-01" + }} + ], + "publications": [ + {{ + "title": "Deep Learning for Text Classification", + "journal_conference": "International Journal of Data Science", + "publication_date": "2023-04-01", + "url": "https://doi.org/10.1234/ijdatasci.2023.12345" + }} + ], + "interests": ["Artificial Intelligence", "Open Source", "Traveling"], + "character_traits_keywords": ["Proactive", "Innovative", "Detail-oriented"] +}} + +First, output your reasoning/thinking process, before you giving the final answer please write '--response--'. Then, output only the JSON object, no explanations or extra text. \ No newline at end of file diff --git a/services/prompts/LearningRoadmapPrompt.md b/services/prompts/LearningRoadmapPrompt.md new file mode 100644 index 0000000000000000000000000000000000000000..5c874db37fc457912917431994d465a468ee5e95 --- /dev/null +++ b/services/prompts/LearningRoadmapPrompt.md @@ -0,0 +1,10 @@ +User Profile: {user_profile} +User Target: {user_target} +Task: Create a learning roadmap to help the user achieve their target. For each competency, provide: +- title: name of the competency +- description: short description of the competency +- outcomes: outcomes from learning that competency +- link: a relevant source link (search the internet if needed) +- estimated_duration: estimated duration to learn this competency (in hour) +If available, use these relevant links as sources: {relevant_links} +Output as a JSON (list of objects) with the specified keys. \ No newline at end of file diff --git a/services/prompts/__init__.py b/services/prompts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/services/prompts/profile_extraction.py b/services/prompts/profile_extraction.py new file mode 100644 index 0000000000000000000000000000000000000000..7633443bf25c103842fbccb2b9727d6d32f4b331 --- /dev/null +++ b/services/prompts/profile_extraction.py @@ -0,0 +1,41 @@ +from langchain_core.prompts import ChatPromptTemplate + +extract_one_profile = """ +You are an intelligent information extraction assistant. +Your task is to read the following Curriculum Vitae (CV) text and extract structured information according to the expected output below. + +---------------------------- +**CV (curriculum vitae)**: + +{cv} +---------------------------- + + +**Expected Output**: +- fullname. str, Fullname of the candidate. +- high_edu_univ_1. str, University where candidate take bachelor degree, if exists. Default = "-". +- high_edu_major_1. str, Major of candidate's bachelor degree, if exists. Default = "-". +- high_edu_gpa_1. float, GPA of candidate's bachelor degree, if exists. Default = 0. + +- high_edu_univ_2. str, University where candidate take master degree, if exists. Default = "-". +- high_edu_major_2. str, Major of candidate's master degree, if exists. Default = "-". +- high_edu_gpa_2. float, GPA of candidate's master degree, if exists. Default = 0. + +- high_edu_univ_3. str, University where candidate take doctoral or phd degree, if exists. Default = "-". +- high_edu_major_3. str, Major of candidate's doctoral or phd degree, if exists. Default = "-". +- high_edu_gpa_3. float, GPA of candidate's doctoral or phd degree, if exists. Default = 0. +- domicile. str, Current domicile of the candidate. Default = "-". + +- yoe. float, Year of working experience of the candidate. Default = 0. +- hardskills. list, List of the candidate's hard skills. Default = "-". +- softskills. list, List of the candidate's soft skills. Default = "-". +- certifications. list, List of the candidate's certifications. Default = "-". +- business_domain_experiences. list, List of the candidate's business domain experience based on company's business on working experience or project's domain business, do not hallucinate! Default = "-". + + + +**Instructions**: +1. Read the provided CV and extract information needed based on expected output. +2. Do not verbose, just return the final answer. +""" +extract_one_profile = ChatPromptTemplate.from_template(extract_one_profile) \ No newline at end of file diff --git a/services/prompts/profile_matching.py b/services/prompts/profile_matching.py new file mode 100644 index 0000000000000000000000000000000000000000..3b8573e80512f705f078cc636a8d4495c414fe43 --- /dev/null +++ b/services/prompts/profile_matching.py @@ -0,0 +1,41 @@ +from langchain_core.prompts import ChatPromptTemplate + +match_one_profile = """ +You are an intelligent information extraction assistant. +Your task is to read the following Curriculum Vitae (CV) text and extract structured information according to the expected output below. + +---------------------------- +**Candidate Profile**: +{profile_text} + + +**Criteria** +{criteria} +---------------------------- + + +**Expected Output**: +- fullname: str // Fullname of the candidate. +- high_edu_univ_1: str // University where candidate take bachelor degree, if exists. Default = "-". +- high_edu_major_1: str // Major of candidate's bachelor degree, if exists. Default = "-". +- high_edu_gpa_1: float // GPA of candidate's bachelor degree, if exists. Default = 0. +- high_edu_univ_2: str // University where candidate take master degree, if exists. Default = "-". +- high_edu_major_2: str // Major of candidate's master degree, if exists. Default = "-". +- high_edu_gpa_2: float // GPA of candidate's master degree, if exists. Default = 0. +- high_edu_univ_3: str // University where candidate take doctoral or phd degree, if exists. Default = "-". +- high_edu_major_3: str // Major of candidate's doctoral or phd degree, if exists. Default = "-". +- high_edu_gpa_3: float // GPA of candidate's doctoral or phd degree, if exists. Default = 0. +- domicile: str // Current domicile of the candidate. Default = "-". +- yoe: int // Year of working experience of the candidate. Default = 0. +- hardskills: list // List of the candidate's hard skills. Default = "-". +- softskills: list // List of the candidate's soft skills. Default = "-". +- certification: list // List of the candidate's certifications. Default = "-". +- business_domain_experiences: list // List of the candidate's business domain experience based on company's business on working experience or project's domain business, do not hallucinate! Default = "-". + + + +**Instructions**: +1. Read the provided CV and extract information needed based on expected output. You must comply to expected output. +2. Do not verbose, just return the final answer. +""" +match_one_profile = ChatPromptTemplate.from_template(match_one_profile) \ No newline at end of file diff --git a/services/tools/__init__.py b/services/tools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c060f8c47950ea007ef82d25341f6a236e690b1c --- /dev/null +++ b/services/tools/__init__.py @@ -0,0 +1,3 @@ +__all__ = ['searching_tool'] + +from .SearchingTools import searching_tool diff --git a/services/tools/profile_scoring.py b/services/tools/profile_scoring.py new file mode 100644 index 0000000000000000000000000000000000000000..1ab5b944403cc0b3f268e9ce08dbcbd7fcb37883 --- /dev/null +++ b/services/tools/profile_scoring.py @@ -0,0 +1 @@ +# retrieve data dari table cv_profile_norm, score profile, insert profile ke table cv_profile_scored \ No newline at end of file diff --git a/services/uploader/azure_blob_service.py b/services/uploader/azure_blob_service.py new file mode 100644 index 0000000000000000000000000000000000000000..e4cb1c1d046ce257dd41421a9529c2b5e972e5b7 --- /dev/null +++ b/services/uploader/azure_blob_service.py @@ -0,0 +1,98 @@ +import os +import dotenv +dotenv.load_dotenv() + +from azure.identity import DefaultAzureCredential +from azure.storage.blob.aio import BlobServiceClient, ContainerClient +# from azure.storage.blob import BlobServiceClient, ContainerClient +from fastapi import UploadFile + + +from config.config import azure_blob_config +from utils.logger import get_logger +# from src.utils.decorator import trace_runtime + +logger = get_logger("azure blob") + + +# --- Environment Variables --- +# NOTE: Set the AZURE_STORAGE_CONNECTION_STRING in your environment (e.g., .env file or production environment). +# CONNECTION_STRING = os.getenv("AZURE_STORAGE_CONNECTION_STRING") +# CONTAINER_NAME = "pdf-uploads" # The name of your Azure Blob Storage container + +async def get_blob_service_client(url=os.environ.get('azureai--container--endpoint')) -> BlobServiceClient: + try: + default_credential = DefaultAzureCredential() + blob_service_client = BlobServiceClient(url, credential=default_credential) + return blob_service_client + except Exception as E: + logger.error(f'❌ Getting blob service client error, {E}') + + +async def get_container_client(url=os.environ.get('azureai--container--endpoint'), container_name=os.environ.get("azureai--container--name")) -> ContainerClient: + try: + blob_service_client = await get_blob_service_client(url=url) + blob_client = blob_service_client.get_container_client(container_name) + return blob_client + except Exception as E: + logger.error(f'❌ Getting container client error, {E}') + + +class AzureBlobStorageService: + """ + A dedicated service class for interacting with Azure Blob Storage. + Uses asynchronous clients for non-blocking I/O operations. + """ + def __init__(self): + # Initialize the BlobServiceClient for the entire application lifetime + self.blob_service_client = get_blob_service_client() + self.container_client = get_container_client() + self.prefix = azure_blob_config.blob_prefix + + if not self.blob_service_client: + raise ValueError("azure service client is not set.") + + + async def upload_pdf(self, file: UploadFile) -> str: + """ + Uploads a file stream directly to Azure Blob Storage. + + Args: + file: The FastAPI UploadFile object. + + Returns: + The URL of the uploaded blob. + """ + # 1. Create a unique blob name (use the original filename for simplicity, + # but consider using a UUID for production to avoid collisions) + blob_name = file.filename + + # 2. Get the blob client + blob_client = self.container_client.get_blob_client(blob_name) + + # 3. Read the file content asynchronously + # The file is read in chunks to avoid loading the entire file into memory + # if it's very large. + content = await file.read() + + # 4. Upload the content + # Setting content_settings is crucial for the browser to handle the file correctly + await blob_client.upload_blob( + content, + blob_type="BlockBlob", + overwrite=True, + content_settings={"content_type": "application/pdf"} + ) + + # 5. Return the URL + # Note: This is the URL to the blob. If it needs to be publicly accessible, + # ensure your container's access policy is configured correctly. + return blob_client.url + + # --- Cleanup for Graceful Shutdown (Optional but Recommended) --- + async def close(self): + """Closes the Blob Service Client connection.""" + await self.blob_service_client.close() + +# Initialize the service globally +blob_storage_service = AzureBlobStorageService() \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a333c68fbc8680eb129aff6ae6a77b5fefc71b45 --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1,5 @@ +__all__ = [ + 'pdf_decoder', + ] + +from .utils import pdf_decoder \ No newline at end of file diff --git a/utils/decorator.py b/utils/decorator.py new file mode 100644 index 0000000000000000000000000000000000000000..d53923b95ed7e11ca362be122da89b3bc03d061d --- /dev/null +++ b/utils/decorator.py @@ -0,0 +1,54 @@ +import asyncio +import inspect +import functools +import time +import warnings +from functools import wraps +from typing import Callable, Any + +def trace_runtime(func: Callable) -> Callable: + @wraps(func) + async def async_wrapper(*args, **kwargs) -> Any: + # This wrapper runs if the original func was async + start_time = time.perf_counter() + # Await the coroutine returned by func(*args, **kwargs) + result = await func(*args, **kwargs) + end_time = time.perf_counter() + duration = end_time - start_time + print(f"⏱️ ASYNC Function '{func.__name__}' took {duration:.6f} seconds") + return result + + @wraps(func) + def sync_wrapper(*args, **kwargs) -> Any: + # This wrapper runs if the original func was sync + start_time = time.perf_counter() + result = func(*args, **kwargs) + end_time = time.perf_counter() + duration = end_time - start_time + print(f"⏱️ SYNC Function '{func.__name__}' took {duration:.6f} seconds") + return result + + # Check if the function being decorated is an async function + if inspect.iscoroutinefunction(func): + # If it's async, return the async wrapper + return async_wrapper + else: + # If it's sync, return the sync wrapper + return sync_wrapper + + +def deprecated(reason): + """ + This is a decorator which can be used to mark functions + and classes as deprecated. + """ + def decorator(func_or_class): + @functools.wraps(func_or_class) + def new_func(*args, **kwargs): + warnings.warn(f"Call to deprecated {func_or_class.__name__}." + f" Reason: {reason}", + category=FutureWarning, + stacklevel=2) + return func_or_class(*args, **kwargs) + return new_func + return decorator \ No newline at end of file diff --git a/utils/jwt.py b/utils/jwt.py new file mode 100644 index 0000000000000000000000000000000000000000..9d0a562984f25046ddc3379aca73c1115d8fb528 --- /dev/null +++ b/utils/jwt.py @@ -0,0 +1,17 @@ +from config.constant import SecurityConstants +from datetime import datetime, timedelta +from jose import jwt + + +def create_access_token(data: dict) -> str: + to_encode = data.copy() + expire = datetime.now() + timedelta( + minutes=SecurityConstants.JWT_EXPIRE_MINUTES + ) + to_encode.update({"exp": expire}) + + return jwt.encode( + to_encode, + SecurityConstants.JWT_SECRET_KEY, + algorithm=SecurityConstants.JWT_ALGORITHM, + ) \ No newline at end of file diff --git a/utils/logger.py b/utils/logger.py new file mode 100644 index 0000000000000000000000000000000000000000..41d27a764c6b8a814c28f9e4812f669397450dd6 --- /dev/null +++ b/utils/logger.py @@ -0,0 +1,7 @@ +import logging + +def get_logger(tag_name:str, level:int = logging.INFO): + FORMAT = '%(message)s' + logging.basicConfig(format=FORMAT, level=level) + logger = logging.getLogger(tag_name) + return logger \ No newline at end of file diff --git a/utils/security.py b/utils/security.py new file mode 100644 index 0000000000000000000000000000000000000000..da25f0b2a8b1d7ad1d4b2334b673b20b378d5788 --- /dev/null +++ b/utils/security.py @@ -0,0 +1,30 @@ +import hashlib +from config.constant import SecurityConstants +from passlib.hash import bcrypt + + +def _prepare_password(password: str) -> bytes: + password_bytes = password.encode("utf-8") + + # SHA-256 = 32 bytes (ALWAYS < 72) + digest = hashlib.sha256(password_bytes).digest() + + # This slice is technically redundant, but explicit + return digest[:SecurityConstants.BCRYPT_MAX_BYTES] + + +def hash_password(password: str) -> str: + prepared = _prepare_password(password) + + # ASSERTION (fail fast if something is wrong) + assert len(prepared) <= 72, f"bcrypt input too long: {len(prepared)} bytes" + + return bcrypt.hash(prepared) + + +def verify_password(plain_password: str, hashed_password: str) -> bool: + prepared = _prepare_password(plain_password) + + assert len(prepared) <= 72, f"bcrypt input too long: {len(prepared)} bytes" + + return bcrypt.verify(prepared, hashed_password) diff --git a/utils/utils.py b/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..a8682aeeeac3e667bd5150cbe6d18e069999f4f5 --- /dev/null +++ b/utils/utils.py @@ -0,0 +1,383 @@ +import os +import sys +import io +import time +import dotenv +import PyPDF2 +import asyncio +import pandas as pd +# import fitz +import pytesseract +dotenv.load_dotenv() +from PyPDF2 import PdfReader +from functools import wraps +from typing import ByteString +from pdf2image import convert_from_path, convert_from_bytes + + +def measure_runtime(func): + if asyncio.iscoroutinefunction(func): + @wraps(func) + async def async_wrapper(*args, **kwargs): + start = time.perf_counter() + result = await func(*args, **kwargs) + end = time.perf_counter() + print(f"⏱️ Async function '{func.__name__}' executed in {end - start:.10f} seconds") + return result + return async_wrapper + + else: + @wraps(func) + def sync_wrapper(*args, **kwargs): + start = time.perf_counter() + result = func(*args, **kwargs) + end = time.perf_counter() + print(f"⏱️ Function '{func.__name__}' executed in {end - start:.10f} seconds") + return result + return sync_wrapper + +# async def is_nonsearchable_pdf(pdf_path: str) -> str: +# try: +# doc = fitz.open(pdf_path) +# for page_num in range(doc.page_count): +# page = doc.load_page(page_num) +# # Attempt to extract text from the page +# text = page.get_text("text") +# text = f"__{text.strip()}__" +# if text == "____": +# print("Non Searchable") +# return True +# else: +# print("Searchable") +# return False +# except Exception as E: +# print(f"Failed to identify nonsearchable, {E}") +# return False + # finally: + # doc.close() + +def pdf_decoder(pdf_bytes: bytes) -> str: + """Decode PDF bytes to a string.""" + pdf_stream = io.BytesIO(pdf_bytes) + reader = PdfReader(pdf_stream) + + # Extract and concatenate text from all pages + user_profile = "" + for page in reader.pages: + text = page.extract_text() + if text: + user_profile += text + "\n" + + return user_profile.strip() + +# from fastapi.datastructures import UploadedFile + +# async def pdf_reader(pdf_path: str) -> str: +# """Decode PDF bytes to a string.""" +# try: +# is_empty = await is_nonsearchable_pdf(pdf_path) +# print(f">> Is nonsearchable: {is_empty}") + +# if is_empty: +# pdf_writer = PyPDF2.PdfWriter() +# poppler_path = None +# if sys.platform == "win32": +# poppler_path = "src/software/poppler-24.08.0/Library/bin" +# print(f"pdf_path",pdf_path) +# print(f"type pdf_path",type(pdf_path)) +# # if type(pdf_path) != str: +# # images = convert_from_bytes(pdf_path, poppler_path=poppler_path) +# # else: +# images = convert_from_bytes(pdf_path, poppler_path=poppler_path) + +# pytesseract.pytesseract.tesseract_cmd = r"src/software/Tesseract-OCR/tesseract.exe" + +# for image in images: +# page = pytesseract.image_to_pdf_or_hocr(image, extension='pdf') +# pdf = PyPDF2.PdfReader(io.BytesIO(page)) +# pdf_writer.add_page(pdf.pages[0]) + +# output_bytes_stream = io.BytesIO() +# pdf_writer.write(output_bytes_stream) +# reader = PyPDF2.PdfReader(output_bytes_stream) +# user_profile = "" +# for page in reader.pages: +# text = page.extract_text() +# user_profile += text + "\n" +# return user_profile +# else: +# reader = PdfReader(pdf_path) +# # Extract and concatenate text from all pages +# user_profile = "" +# for page in reader.pages: +# text = page.extract_text() +# if text: +# user_profile += text + "\n" +# print(f">>> user profile: {user_profile.strip()}") +# return user_profile.strip() +# except Exception as E: +# print(f"pdf reader error, {E}") +# exc_type, exc_obj, exc_tb = sys.exc_info() +# fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] +# print(exc_type, fname, exc_tb.tb_lineno) +# import tempfile + + +async def pdf_reader(pdf_path: ByteString) -> str: + """Read PDF bytes to a string.""" + try: + user_profile = "" + + if type(pdf_path) == bytes: + reader = PdfReader(io.BytesIO(pdf_path)) + else: + reader = PdfReader(pdf_path) + + for page in reader.pages: + text = page.extract_text() + if text: + user_profile += text + "\n" + + if user_profile.strip() != "": + return user_profile.strip() + else: + pdf_writer = PyPDF2.PdfWriter() + poppler_path = None + if sys.platform == "win32": + poppler_path = "src/software/poppler-24.08.0/Library/bin" + + + # images = convert_from_bytes(pdf_path.getvalue(), poppler_path=poppler_path) + images = convert_from_bytes(pdf_path, poppler_path=poppler_path) + + pytesseract.pytesseract.tesseract_cmd = r"src/software/Tesseract-OCR/tesseract.exe" + + for image in images: + page = pytesseract.image_to_pdf_or_hocr(image, extension='pdf') + pdf = PyPDF2.PdfReader(io.BytesIO(page)) + # pdf = PyPDF2.PdfReader(page) + pdf_writer.add_page(pdf.pages[0]) + + output_bytes_stream = io.BytesIO() + pdf_writer.write(output_bytes_stream) + reader = PyPDF2.PdfReader(output_bytes_stream) + user_profile = "" + for page in reader.pages: + text = page.extract_text() + user_profile += text + "\n" + return user_profile.strip() + except Exception as E: + print(f"pdf reader error, {E}") + exc_type, exc_obj, exc_tb = sys.exc_info() + fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] + print(exc_type, fname, exc_tb.tb_lineno) + + +# cv = pdf_reader("src/data/cvs/1. Balu Rama Chandra_Data Scientist_Linkedin.pdf") +# print(cv) +# len(cv.pages) +# for page in cv.pages: +# print(page.extract_text()) + + +# ------------------ +# QDRANT +# ------------------ +# from qdrant_client import QdrantClient, models +# import uuid +# from src.embed_model.embed_model import embed_model +# from qdrant_client import AsyncQdrantClient, models +# from fastapi import HTTPException +# from typing import Dict, List, Union +# from src.models.data_model import Profile, OutProfile + + +# qdrant_client = AsyncQdrantClient( +# url=os.environ.get('ss--qdrant--endpoint--url'), +# api_key=os.environ.get('ss--qdrant--api-key'), +# ) +# qdrant_collection_name = os.environ.get('ss--qdrant--collection--name') + + +# async def check_collection(qdrant_client:AsyncQdrantClient=qdrant_client, collection_name: str=qdrant_collection_name): +# try: +# colls = await qdrant_client.get_collections() +# if collection_name not in [item.name for item in colls.collections]: +# await qdrant_client.create_collection( +# collection_name=qdrant_collection_name, +# vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE), +# ) +# print(f"✅ collection '{collection_name}' is created!") +# return True +# else: +# print(f"✅ collection '{collection_name}' already created!") +# except Exception as E: +# print(f"❌ Something when wrong!, {E}") +# return False + + +# async def prettyfy_profile(profile:Dict) -> str: +# template = "----\n" +# for k, v in profile.items(): +# template += f"{k}: {v} \n" +# template += "----" +# return template + + +# async def ingest_one_profile(profile:Profile, qdrant_client:AsyncQdrantClient=qdrant_client, collection_name:str=qdrant_collection_name): +# try: +# await check_collection(qdrant_client, collection_name) +# text = await prettyfy_profile(profile.profile.model_dump()) +# doc_id = profile.profile_id +# embeddings = await embed_model.aembed_query(text = text) + +# qdrant_client.upload_points( +# collection_name=collection_name, +# points=[ +# models.PointStruct( +# id=doc_id, +# payload=profile.model_dump(), +# vector=embeddings, +# ) +# ] +# ) +# print(f"✅ Ingest one profile succeeded!") +# except Exception as E: +# print(f"❌ Ingest one profile error!, {E}") +# raise HTTPException(status_code=500, detail=f"❌ Ingest one profile error!, {E}") + + +# async def ingest_bulk_profile(profiles:List[Profile], qdrant_client:AsyncQdrantClient=qdrant_client, collection_name:str=qdrant_collection_name): +# try: +# await check_collection(qdrant_client, collection_name) +# points = [] +# for profile in profiles: +# text = await prettyfy_profile(profile.profile.model_dump()) +# doc_id = profile.profile_id +# embeddings = await embed_model.aembed_query(text = text) +# points.append( +# models.PointStruct( +# id=doc_id, +# payload=profile.model_dump(), +# vector=embeddings, +# ) +# ) + +# qdrant_client.upload_points( +# collection_name=collection_name, +# points=points +# ) +# print(f"✅ Ingest bulk profile succeeded!") +# except Exception as E: +# print(f"❌ Ingest bulk profile error!, {E}") +# raise HTTPException(status_code=500, detail=f"❌ Ingest bulk profile error!, {E}") + + + +# async def pretty_profiles(profiles:List[Union[Profile, Dict]]) -> pd.DataFrame: +# try: +# records = [] +# for profile in profiles: +# temp = {} +# # text = await prettyfy_profile(profile.profile.model_dump()) +# # doc_id = profile.profile_id +# filename = profile.filename + +# # if type(profile.profile) != Dict: +# # temp = {**{"filename":filename}, **profile.profile.model_dump()} +# # else: +# if type(profile.profile) == dict: +# temp = {**{"filename":filename}, **profile.profile} +# elif type(profile.profile) == OutProfile: +# temp = {**{"filename":filename}, **profile.profile.model_dump()} + + +# if type(temp["hardskills"]) == list and temp["hardskills"] != []: +# temp["hardskills"] = ", ".join(temp["hardskills"]) +# else: +# temp["hardskills"] = "-" + +# if type(temp["softskills"]) == list and temp["softskills"] != []: +# temp["softskills"] = ", ".join(temp["softskills"]) +# else: +# temp["softskills"] = "-" + +# if type(temp["certifications"]) == list and temp["certifications"] != []: +# temp["certifications"] = ", ".join(temp["certifications"]) +# else: +# temp["certifications"] = "-" + +# if type(temp["business_domain_experiences"]) == list and temp["business_domain_experiences"] != []: +# temp["business_domain_experiences"] = ", ".join(temp["business_domain_experiences"]) +# else: +# temp["business_domain_experiences"] = "-" + +# records.append(temp) +# # embeddings = await embed_model.aembed_query(text = text) +# print(f"✅ Export profile succeeded!") +# df = pd.DataFrame(records) +# return df +# except Exception as E: +# print(f"❌ Export profile error!, {E}") +# error_message = f"Processing pretty profile error: {E}" +# print(error_message) +# exc_type, exc_obj, exc_tb = sys.exc_info() +# fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] +# print(exc_type, fname, exc_tb.tb_lineno) +# raise HTTPException(status_code=500, detail=f"❌ Export profile error!, {E}") + + +# async def helper_prepare_profiles(file_names:List, output_profiles:List[Union[OutProfile, Dict]]): +# if len(file_names) == len(output_profiles): +# profiles = [] +# for i in range(len(output_profiles)): +# one_profile = Profile( +# filename=file_names[i].split('\\')[-1], +# profile_id=str(uuid.uuid4()), +# profile=output_profiles[i] +# ) +# profiles.append(one_profile) +# return profiles +# else: +# return [] + + +# asyncio.run(ingest_one_profile(profile)) +# asyncio.run(ingest_one_profile(fake_profile)) + + +# async def retrieve_profile(input_user: str, qdrant_client:AsyncQdrantClient=qdrant_client, collection_name:str=qdrant_collection_name, limit:int=5): +# try: +# embeddings = await embed_model.aembed_query(text = input_user) +# query_result = await qdrant_client.query_points( +# collection_name=collection_name, +# query=embeddings, +# limit=limit, +# ) +# return query_result.points +# except Exception as E: +# print(f"❌ retrieve_profile error, {E}") +# return [] + + +# criteria1 = """latest_university: Institut Teknologi Sepuluh November (ITS) +# major: Matematika +# gpa: >3.6 +# hardskill: Certified Business Strategic Business Analyst, analytics +# business_domain_experience: people analytics""" + +# criteria1 = """universitas: Institut Teknologi Sepuluh November (ITS)""" + +# retrieved_profiles = asyncio.run(retrieve_profile(criteria1, limit=None)) +# len(retrieved_profiles) +# retrieved_profiles[-1].payload + + +# from langchain_community.document_loaders import PyPDFLoader + +# loader = PyPDFLoader(files_path[0]) +# pages = [] +# for page in loader.lazy_load(): +# pages.append(page) + +# len(pages) diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000000000000000000000000000000000000..7ae84070d708061792beddf97a92f5daeaf97ea3 --- /dev/null +++ b/uv.lock @@ -0,0 +1,2633 @@ +version = 1 +revision = 2 +requires-python = ">=3.13" + +[[package]] +name = "aiofiles" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994, upload-time = "2025-10-28T20:59:39.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/78/7e90ca79e5aa39f9694dcfd74f4720782d3c6828113bb1f3197f7e7c4a56/aiohttp-3.13.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7519bdc7dfc1940d201651b52bf5e03f5503bda45ad6eacf64dda98be5b2b6be", size = 732139, upload-time = "2025-10-28T20:57:02.455Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/1f59215ab6853fbaa5c8495fa6cbc39edfc93553426152b75d82a5f32b76/aiohttp-3.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:088912a78b4d4f547a1f19c099d5a506df17eacec3c6f4375e2831ec1d995742", size = 490082, upload-time = "2025-10-28T20:57:04.784Z" }, + { url = "https://files.pythonhosted.org/packages/68/7b/fe0fe0f5e05e13629d893c760465173a15ad0039c0a5b0d0040995c8075e/aiohttp-3.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5276807b9de9092af38ed23ce120539ab0ac955547b38563a9ba4f5b07b95293", size = 489035, upload-time = "2025-10-28T20:57:06.894Z" }, + { url = "https://files.pythonhosted.org/packages/d2/04/db5279e38471b7ac801d7d36a57d1230feeee130bbe2a74f72731b23c2b1/aiohttp-3.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1237c1375eaef0db4dcd7c2559f42e8af7b87ea7d295b118c60c36a6e61cb811", size = 1720387, upload-time = "2025-10-28T20:57:08.685Z" }, + { url = "https://files.pythonhosted.org/packages/31/07/8ea4326bd7dae2bd59828f69d7fdc6e04523caa55e4a70f4a8725a7e4ed2/aiohttp-3.13.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96581619c57419c3d7d78703d5b78c1e5e5fc0172d60f555bdebaced82ded19a", size = 1688314, upload-time = "2025-10-28T20:57:10.693Z" }, + { url = "https://files.pythonhosted.org/packages/48/ab/3d98007b5b87ffd519d065225438cc3b668b2f245572a8cb53da5dd2b1bc/aiohttp-3.13.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2713a95b47374169409d18103366de1050fe0ea73db358fc7a7acb2880422d4", size = 1756317, upload-time = "2025-10-28T20:57:12.563Z" }, + { url = "https://files.pythonhosted.org/packages/97/3d/801ca172b3d857fafb7b50c7c03f91b72b867a13abca982ed6b3081774ef/aiohttp-3.13.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:228a1cd556b3caca590e9511a89444925da87d35219a49ab5da0c36d2d943a6a", size = 1858539, upload-time = "2025-10-28T20:57:14.623Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0d/4764669bdf47bd472899b3d3db91fffbe925c8e3038ec591a2fd2ad6a14d/aiohttp-3.13.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac6cde5fba8d7d8c6ac963dbb0256a9854e9fafff52fbcc58fdf819357892c3e", size = 1739597, upload-time = "2025-10-28T20:57:16.399Z" }, + { url = "https://files.pythonhosted.org/packages/c4/52/7bd3c6693da58ba16e657eb904a5b6decfc48ecd06e9ac098591653b1566/aiohttp-3.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2bef8237544f4e42878c61cef4e2839fee6346dc60f5739f876a9c50be7fcdb", size = 1555006, upload-time = "2025-10-28T20:57:18.288Z" }, + { url = "https://files.pythonhosted.org/packages/48/30/9586667acec5993b6f41d2ebcf96e97a1255a85f62f3c653110a5de4d346/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:16f15a4eac3bc2d76c45f7ebdd48a65d41b242eb6c31c2245463b40b34584ded", size = 1683220, upload-time = "2025-10-28T20:57:20.241Z" }, + { url = "https://files.pythonhosted.org/packages/71/01/3afe4c96854cfd7b30d78333852e8e851dceaec1c40fd00fec90c6402dd2/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bb7fb776645af5cc58ab804c58d7eba545a97e047254a52ce89c157b5af6cd0b", size = 1712570, upload-time = "2025-10-28T20:57:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/11/2c/22799d8e720f4697a9e66fd9c02479e40a49de3de2f0bbe7f9f78a987808/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1b4951125ec10c70802f2cb09736c895861cd39fd9dcb35107b4dc8ae6220b8", size = 1733407, upload-time = "2025-10-28T20:57:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/34/cb/90f15dd029f07cebbd91f8238a8b363978b530cd128488085b5703683594/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:550bf765101ae721ee1d37d8095f47b1f220650f85fe1af37a90ce75bab89d04", size = 1550093, upload-time = "2025-10-28T20:57:26.257Z" }, + { url = "https://files.pythonhosted.org/packages/69/46/12dce9be9d3303ecbf4d30ad45a7683dc63d90733c2d9fe512be6716cd40/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fe91b87fc295973096251e2d25a811388e7d8adf3bd2b97ef6ae78bc4ac6c476", size = 1758084, upload-time = "2025-10-28T20:57:28.349Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c8/0932b558da0c302ffd639fc6362a313b98fdf235dc417bc2493da8394df7/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0c8e31cfcc4592cb200160344b2fb6ae0f9e4effe06c644b5a125d4ae5ebe23", size = 1716987, upload-time = "2025-10-28T20:57:30.233Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8b/f5bd1a75003daed099baec373aed678f2e9b34f2ad40d85baa1368556396/aiohttp-3.13.2-cp313-cp313-win32.whl", hash = "sha256:0740f31a60848d6edb296a0df827473eede90c689b8f9f2a4cdde74889eb2254", size = 425859, upload-time = "2025-10-28T20:57:32.105Z" }, + { url = "https://files.pythonhosted.org/packages/5d/28/a8a9fc6957b2cee8902414e41816b5ab5536ecf43c3b1843c10e82c559b2/aiohttp-3.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:a88d13e7ca367394908f8a276b89d04a3652044612b9a408a0bb22a5ed976a1a", size = 452192, upload-time = "2025-10-28T20:57:34.166Z" }, + { url = "https://files.pythonhosted.org/packages/9b/36/e2abae1bd815f01c957cbf7be817b3043304e1c87bad526292a0410fdcf9/aiohttp-3.13.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2475391c29230e063ef53a66669b7b691c9bfc3f1426a0f7bcdf1216bdbac38b", size = 735234, upload-time = "2025-10-28T20:57:36.415Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e3/1ee62dde9b335e4ed41db6bba02613295a0d5b41f74a783c142745a12763/aiohttp-3.13.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f33c8748abef4d8717bb20e8fb1b3e07c6adacb7fd6beaae971a764cf5f30d61", size = 490733, upload-time = "2025-10-28T20:57:38.205Z" }, + { url = "https://files.pythonhosted.org/packages/1a/aa/7a451b1d6a04e8d15a362af3e9b897de71d86feac3babf8894545d08d537/aiohttp-3.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ae32f24bbfb7dbb485a24b30b1149e2f200be94777232aeadba3eecece4d0aa4", size = 491303, upload-time = "2025-10-28T20:57:40.122Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/209958dbb9b01174870f6a7538cd1f3f28274fdbc88a750c238e2c456295/aiohttp-3.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7f02042c1f009ffb70067326ef183a047425bb2ff3bc434ead4dd4a4a66a2b", size = 1717965, upload-time = "2025-10-28T20:57:42.28Z" }, + { url = "https://files.pythonhosted.org/packages/08/aa/6a01848d6432f241416bc4866cae8dc03f05a5a884d2311280f6a09c73d6/aiohttp-3.13.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93655083005d71cd6c072cdab54c886e6570ad2c4592139c3fb967bfc19e4694", size = 1667221, upload-time = "2025-10-28T20:57:44.869Z" }, + { url = "https://files.pythonhosted.org/packages/87/4f/36c1992432d31bbc789fa0b93c768d2e9047ec8c7177e5cd84ea85155f36/aiohttp-3.13.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0db1e24b852f5f664cd728db140cf11ea0e82450471232a394b3d1a540b0f906", size = 1757178, upload-time = "2025-10-28T20:57:47.216Z" }, + { url = "https://files.pythonhosted.org/packages/ac/b4/8e940dfb03b7e0f68a82b88fd182b9be0a65cb3f35612fe38c038c3112cf/aiohttp-3.13.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b009194665bcd128e23eaddef362e745601afa4641930848af4c8559e88f18f9", size = 1838001, upload-time = "2025-10-28T20:57:49.337Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ef/39f3448795499c440ab66084a9db7d20ca7662e94305f175a80f5b7e0072/aiohttp-3.13.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c038a8fdc8103cd51dbd986ecdce141473ffd9775a7a8057a6ed9c3653478011", size = 1716325, upload-time = "2025-10-28T20:57:51.327Z" }, + { url = "https://files.pythonhosted.org/packages/d7/51/b311500ffc860b181c05d91c59a1313bdd05c82960fdd4035a15740d431e/aiohttp-3.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66bac29b95a00db411cd758fea0e4b9bdba6d549dfe333f9a945430f5f2cc5a6", size = 1547978, upload-time = "2025-10-28T20:57:53.554Z" }, + { url = "https://files.pythonhosted.org/packages/31/64/b9d733296ef79815226dab8c586ff9e3df41c6aff2e16c06697b2d2e6775/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4ebf9cfc9ba24a74cf0718f04aac2a3bbe745902cc7c5ebc55c0f3b5777ef213", size = 1682042, upload-time = "2025-10-28T20:57:55.617Z" }, + { url = "https://files.pythonhosted.org/packages/3f/30/43d3e0f9d6473a6db7d472104c4eff4417b1e9df01774cb930338806d36b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a4b88ebe35ce54205c7074f7302bd08a4cb83256a3e0870c72d6f68a3aaf8e49", size = 1680085, upload-time = "2025-10-28T20:57:57.59Z" }, + { url = "https://files.pythonhosted.org/packages/16/51/c709f352c911b1864cfd1087577760ced64b3e5bee2aa88b8c0c8e2e4972/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98c4fb90bb82b70a4ed79ca35f656f4281885be076f3f970ce315402b53099ae", size = 1728238, upload-time = "2025-10-28T20:57:59.525Z" }, + { url = "https://files.pythonhosted.org/packages/19/e2/19bd4c547092b773caeb48ff5ae4b1ae86756a0ee76c16727fcfd281404b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:ec7534e63ae0f3759df3a1ed4fa6bc8f75082a924b590619c0dd2f76d7043caa", size = 1544395, upload-time = "2025-10-28T20:58:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/cf/87/860f2803b27dfc5ed7be532832a3498e4919da61299b4a1f8eb89b8ff44d/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5b927cf9b935a13e33644cbed6c8c4b2d0f25b713d838743f8fe7191b33829c4", size = 1742965, upload-time = "2025-10-28T20:58:03.972Z" }, + { url = "https://files.pythonhosted.org/packages/67/7f/db2fc7618925e8c7a601094d5cbe539f732df4fb570740be88ed9e40e99a/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:88d6c017966a78c5265d996c19cdb79235be5e6412268d7e2ce7dee339471b7a", size = 1697585, upload-time = "2025-10-28T20:58:06.189Z" }, + { url = "https://files.pythonhosted.org/packages/0c/07/9127916cb09bb38284db5036036042b7b2c514c8ebaeee79da550c43a6d6/aiohttp-3.13.2-cp314-cp314-win32.whl", hash = "sha256:f7c183e786e299b5d6c49fb43a769f8eb8e04a2726a2bd5887b98b5cc2d67940", size = 431621, upload-time = "2025-10-28T20:58:08.636Z" }, + { url = "https://files.pythonhosted.org/packages/fb/41/554a8a380df6d3a2bba8a7726429a23f4ac62aaf38de43bb6d6cde7b4d4d/aiohttp-3.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:fe242cd381e0fb65758faf5ad96c2e460df6ee5b2de1072fe97e4127927e00b4", size = 457627, upload-time = "2025-10-28T20:58:11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8e/3824ef98c039d3951cb65b9205a96dd2b20f22241ee17d89c5701557c826/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f10d9c0b0188fe85398c61147bbd2a657d616c876863bfeff43376e0e3134673", size = 767360, upload-time = "2025-10-28T20:58:13.358Z" }, + { url = "https://files.pythonhosted.org/packages/a4/0f/6a03e3fc7595421274fa34122c973bde2d89344f8a881b728fa8c774e4f1/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e7c952aefdf2460f4ae55c5e9c3e80aa72f706a6317e06020f80e96253b1accd", size = 504616, upload-time = "2025-10-28T20:58:15.339Z" }, + { url = "https://files.pythonhosted.org/packages/c6/aa/ed341b670f1bc8a6f2c6a718353d13b9546e2cef3544f573c6a1ff0da711/aiohttp-3.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c20423ce14771d98353d2e25e83591fa75dfa90a3c1848f3d7c68243b4fbded3", size = 509131, upload-time = "2025-10-28T20:58:17.693Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f0/c68dac234189dae5c4bbccc0f96ce0cc16b76632cfc3a08fff180045cfa4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e96eb1a34396e9430c19d8338d2ec33015e4a87ef2b4449db94c22412e25ccdf", size = 1864168, upload-time = "2025-10-28T20:58:20.113Z" }, + { url = "https://files.pythonhosted.org/packages/8f/65/75a9a76db8364b5d0e52a0c20eabc5d52297385d9af9c35335b924fafdee/aiohttp-3.13.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:23fb0783bc1a33640036465019d3bba069942616a6a2353c6907d7fe1ccdaf4e", size = 1719200, upload-time = "2025-10-28T20:58:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/8df2ed78d7f41d232f6bd3ff866b6f617026551aa1d07e2f03458f964575/aiohttp-3.13.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1a9bea6244a1d05a4e57c295d69e159a5c50d8ef16aa390948ee873478d9a5", size = 1843497, upload-time = "2025-10-28T20:58:24.672Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e0/94d7215e405c5a02ccb6a35c7a3a6cfff242f457a00196496935f700cde5/aiohttp-3.13.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a3d54e822688b56e9f6b5816fb3de3a3a64660efac64e4c2dc435230ad23bad", size = 1935703, upload-time = "2025-10-28T20:58:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/0b/78/1eeb63c3f9b2d1015a4c02788fb543141aad0a03ae3f7a7b669b2483f8d4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a653d872afe9f33497215745da7a943d1dc15b728a9c8da1c3ac423af35178e", size = 1792738, upload-time = "2025-10-28T20:58:29.787Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/aaf1eea4c188e51538c04cc568040e3082db263a57086ea74a7d38c39e42/aiohttp-3.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:56d36e80d2003fa3fc0207fac644216d8532e9504a785ef9a8fd013f84a42c61", size = 1624061, upload-time = "2025-10-28T20:58:32.529Z" }, + { url = "https://files.pythonhosted.org/packages/9b/c2/3b6034de81fbcc43de8aeb209073a2286dfb50b86e927b4efd81cf848197/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78cd586d8331fb8e241c2dd6b2f4061778cc69e150514b39a9e28dd050475661", size = 1789201, upload-time = "2025-10-28T20:58:34.618Z" }, + { url = "https://files.pythonhosted.org/packages/c9/38/c15dcf6d4d890217dae79d7213988f4e5fe6183d43893a9cf2fe9e84ca8d/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:20b10bbfbff766294fe99987f7bb3b74fdd2f1a2905f2562132641ad434dcf98", size = 1776868, upload-time = "2025-10-28T20:58:38.835Z" }, + { url = "https://files.pythonhosted.org/packages/04/75/f74fd178ac81adf4f283a74847807ade5150e48feda6aef024403716c30c/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9ec49dff7e2b3c85cdeaa412e9d438f0ecd71676fde61ec57027dd392f00c693", size = 1790660, upload-time = "2025-10-28T20:58:41.507Z" }, + { url = "https://files.pythonhosted.org/packages/e7/80/7368bd0d06b16b3aba358c16b919e9c46cf11587dc572091031b0e9e3ef0/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:94f05348c4406450f9d73d38efb41d669ad6cd90c7ee194810d0eefbfa875a7a", size = 1617548, upload-time = "2025-10-28T20:58:43.674Z" }, + { url = "https://files.pythonhosted.org/packages/7d/4b/a6212790c50483cb3212e507378fbe26b5086d73941e1ec4b56a30439688/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:fa4dcb605c6f82a80c7f95713c2b11c3b8e9893b3ebd2bc9bde93165ed6107be", size = 1817240, upload-time = "2025-10-28T20:58:45.787Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f7/ba5f0ba4ea8d8f3c32850912944532b933acbf0f3a75546b89269b9b7dde/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf00e5db968c3f67eccd2778574cf64d8b27d95b237770aa32400bd7a1ca4f6c", size = 1762334, upload-time = "2025-10-28T20:58:47.936Z" }, + { url = "https://files.pythonhosted.org/packages/7e/83/1a5a1856574588b1cad63609ea9ad75b32a8353ac995d830bf5da9357364/aiohttp-3.13.2-cp314-cp314t-win32.whl", hash = "sha256:d23b5fe492b0805a50d3371e8a728a9134d8de5447dce4c885f5587294750734", size = 464685, upload-time = "2025-10-28T20:58:50.642Z" }, + { url = "https://files.pythonhosted.org/packages/9f/4d/d22668674122c08f4d56972297c51a624e64b3ed1efaa40187607a7cb66e/aiohttp-3.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:ff0a7b0a82a7ab905cbda74006318d1b12e37c797eb1b0d4eb3e316cf47f658f", size = 498093, upload-time = "2025-10-28T20:58:52.782Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/ce/8a777047513153587e5434fd752e89334ac33e379aa3497db860eeb60377/anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0", size = 228266, upload-time = "2025-11-28T23:37:38.911Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/9c/36c5c37947ebfb8c7f22e0eb6e4d188ee2d53aa3880f3f2744fb894f0cb1/anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb", size = 113362, upload-time = "2025-11-28T23:36:57.897Z" }, +] + +[[package]] +name = "asyncpg" +version = "0.31.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cc/d18065ce2380d80b1bcce927c24a2642efd38918e33fd724bc4bca904877/asyncpg-0.31.0.tar.gz", hash = "sha256:c989386c83940bfbd787180f2b1519415e2d3d6277a70d9d0f0145ac73500735", size = 993667, upload-time = "2025-11-24T23:27:00.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/11/97b5c2af72a5d0b9bc3fa30cd4b9ce22284a9a943a150fdc768763caf035/asyncpg-0.31.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c204fab1b91e08b0f47e90a75d1b3c62174dab21f670ad6c5d0f243a228f015b", size = 661111, upload-time = "2025-11-24T23:26:04.467Z" }, + { url = "https://files.pythonhosted.org/packages/1b/71/157d611c791a5e2d0423f09f027bd499935f0906e0c2a416ce712ba51ef3/asyncpg-0.31.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:54a64f91839ba59008eccf7aad2e93d6e3de688d796f35803235ea1c4898ae1e", size = 636928, upload-time = "2025-11-24T23:26:05.944Z" }, + { url = "https://files.pythonhosted.org/packages/2e/fc/9e3486fb2bbe69d4a867c0b76d68542650a7ff1574ca40e84c3111bb0c6e/asyncpg-0.31.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0e0822b1038dc7253b337b0f3f676cadc4ac31b126c5d42691c39691962e403", size = 3424067, upload-time = "2025-11-24T23:26:07.957Z" }, + { url = "https://files.pythonhosted.org/packages/12/c6/8c9d076f73f07f995013c791e018a1cd5f31823c2a3187fc8581706aa00f/asyncpg-0.31.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bef056aa502ee34204c161c72ca1f3c274917596877f825968368b2c33f585f4", size = 3518156, upload-time = "2025-11-24T23:26:09.591Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3b/60683a0baf50fbc546499cfb53132cb6835b92b529a05f6a81471ab60d0c/asyncpg-0.31.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0bfbcc5b7ffcd9b75ab1558f00db2ae07db9c80637ad1b2469c43df79d7a5ae2", size = 3319636, upload-time = "2025-11-24T23:26:11.168Z" }, + { url = "https://files.pythonhosted.org/packages/50/dc/8487df0f69bd398a61e1792b3cba0e47477f214eff085ba0efa7eac9ce87/asyncpg-0.31.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22bc525ebbdc24d1261ecbf6f504998244d4e3be1721784b5f64664d61fbe602", size = 3472079, upload-time = "2025-11-24T23:26:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/13/a1/c5bbeeb8531c05c89135cb8b28575ac2fac618bcb60119ee9696c3faf71c/asyncpg-0.31.0-cp313-cp313-win32.whl", hash = "sha256:f890de5e1e4f7e14023619399a471ce4b71f5418cd67a51853b9910fdfa73696", size = 527606, upload-time = "2025-11-24T23:26:14.78Z" }, + { url = "https://files.pythonhosted.org/packages/91/66/b25ccb84a246b470eb943b0107c07edcae51804912b824054b3413995a10/asyncpg-0.31.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc5f2fa9916f292e5c5c8b2ac2813763bcd7f58e130055b4ad8a0531314201ab", size = 596569, upload-time = "2025-11-24T23:26:16.189Z" }, + { url = "https://files.pythonhosted.org/packages/3c/36/e9450d62e84a13aea6580c83a47a437f26c7ca6fa0f0fd40b6670793ea30/asyncpg-0.31.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f6b56b91bb0ffc328c4e3ed113136cddd9deefdf5f79ab448598b9772831df44", size = 660867, upload-time = "2025-11-24T23:26:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/82/4b/1d0a2b33b3102d210439338e1beea616a6122267c0df459ff0265cd5807a/asyncpg-0.31.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:334dec28cf20d7f5bb9e45b39546ddf247f8042a690bff9b9573d00086e69cb5", size = 638349, upload-time = "2025-11-24T23:26:19.689Z" }, + { url = "https://files.pythonhosted.org/packages/41/aa/e7f7ac9a7974f08eff9183e392b2d62516f90412686532d27e196c0f0eeb/asyncpg-0.31.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98cc158c53f46de7bb677fd20c417e264fc02b36d901cc2a43bd6cb0dc6dbfd2", size = 3410428, upload-time = "2025-11-24T23:26:21.275Z" }, + { url = "https://files.pythonhosted.org/packages/6f/de/bf1b60de3dede5c2731e6788617a512bc0ebd9693eac297ee74086f101d7/asyncpg-0.31.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9322b563e2661a52e3cdbc93eed3be7748b289f792e0011cb2720d278b366ce2", size = 3471678, upload-time = "2025-11-24T23:26:23.627Z" }, + { url = "https://files.pythonhosted.org/packages/46/78/fc3ade003e22d8bd53aaf8f75f4be48f0b460fa73738f0391b9c856a9147/asyncpg-0.31.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19857a358fc811d82227449b7ca40afb46e75b33eb8897240c3839dd8b744218", size = 3313505, upload-time = "2025-11-24T23:26:25.235Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e9/73eb8a6789e927816f4705291be21f2225687bfa97321e40cd23055e903a/asyncpg-0.31.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ba5f8886e850882ff2c2ace5732300e99193823e8107e2c53ef01c1ebfa1e85d", size = 3434744, upload-time = "2025-11-24T23:26:26.944Z" }, + { url = "https://files.pythonhosted.org/packages/08/4b/f10b880534413c65c5b5862f79b8e81553a8f364e5238832ad4c0af71b7f/asyncpg-0.31.0-cp314-cp314-win32.whl", hash = "sha256:cea3a0b2a14f95834cee29432e4ddc399b95700eb1d51bbc5bfee8f31fa07b2b", size = 532251, upload-time = "2025-11-24T23:26:28.404Z" }, + { url = "https://files.pythonhosted.org/packages/d3/2d/7aa40750b7a19efa5d66e67fc06008ca0f27ba1bd082e457ad82f59aba49/asyncpg-0.31.0-cp314-cp314-win_amd64.whl", hash = "sha256:04d19392716af6b029411a0264d92093b6e5e8285ae97a39957b9a9c14ea72be", size = 604901, upload-time = "2025-11-24T23:26:30.34Z" }, + { url = "https://files.pythonhosted.org/packages/ce/fe/b9dfe349b83b9dee28cc42360d2c86b2cdce4cb551a2c2d27e156bcac84d/asyncpg-0.31.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bdb957706da132e982cc6856bb2f7b740603472b54c3ebc77fe60ea3e57e1bd2", size = 702280, upload-time = "2025-11-24T23:26:32Z" }, + { url = "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6d11b198111a72f47154fa03b85799f9be63701e068b43f84ac25da0bda9cb31", size = 682931, upload-time = "2025-11-24T23:26:33.572Z" }, + { url = "https://files.pythonhosted.org/packages/a6/45/6009040da85a1648dd5bc75b3b0a062081c483e75a1a29041ae63a0bf0dc/asyncpg-0.31.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18c83b03bc0d1b23e6230f5bf8d4f217dc9bc08644ce0502a9d91dc9e634a9c7", size = 3581608, upload-time = "2025-11-24T23:26:35.638Z" }, + { url = "https://files.pythonhosted.org/packages/7e/06/2e3d4d7608b0b2b3adbee0d0bd6a2d29ca0fc4d8a78f8277df04e2d1fd7b/asyncpg-0.31.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e009abc333464ff18b8f6fd146addffd9aaf63e79aa3bb40ab7a4c332d0c5e9e", size = 3498738, upload-time = "2025-11-24T23:26:37.275Z" }, + { url = "https://files.pythonhosted.org/packages/7d/aa/7d75ede780033141c51d83577ea23236ba7d3a23593929b32b49db8ed36e/asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3b1fbcb0e396a5ca435a8826a87e5c2c2cc0c8c68eb6fadf82168056b0e53a8c", size = 3401026, upload-time = "2025-11-24T23:26:39.423Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7a/15e37d45e7f7c94facc1e9148c0e455e8f33c08f0b8a0b1deb2c5171771b/asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8df714dba348efcc162d2adf02d213e5fab1bd9f557e1305633e851a61814a7a", size = 3429426, upload-time = "2025-11-24T23:26:41.032Z" }, + { url = "https://files.pythonhosted.org/packages/13/d5/71437c5f6ae5f307828710efbe62163974e71237d5d46ebd2869ea052d10/asyncpg-0.31.0-cp314-cp314t-win32.whl", hash = "sha256:1b41f1afb1033f2b44f3234993b15096ddc9cd71b21a42dbd87fc6a57b43d65d", size = 614495, upload-time = "2025-11-24T23:26:42.659Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d7/8fb3044eaef08a310acfe23dae9a8e2e07d305edc29a53497e52bc76eca7/asyncpg-0.31.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bd4107bb7cdd0e9e65fae66a62afd3a249663b844fa34d479f6d5b3bef9c04c3", size = 706062, upload-time = "2025-11-24T23:26:44.086Z" }, +] + +[[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 = "azure-core" +version = "1.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/83/41c9371c8298999c67b007e308a0a3c4d6a59c6908fa9c62101f031f886f/azure_core-1.37.0.tar.gz", hash = "sha256:7064f2c11e4b97f340e8e8c6d923b822978be3016e46b7bc4aa4b337cfb48aee", size = 357620, upload-time = "2025-12-11T20:05:13.518Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/34/a9914e676971a13d6cc671b1ed172f9804b50a3a80a143ff196e52f4c7ee/azure_core-1.37.0-py3-none-any.whl", hash = "sha256:b3abe2c59e7d6bb18b38c275a5029ff80f98990e7c90a5e646249a56630fcc19", size = 214006, upload-time = "2025-12-11T20:05:14.96Z" }, +] + +[[package]] +name = "azure-identity" +version = "1.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "azure-core" }, + { name = "cryptography" }, + { name = "msal" }, + { name = "msal-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/8d/1a6c41c28a37eab26dc85ab6c86992c700cd3f4a597d9ed174b0e9c69489/azure_identity-1.25.1.tar.gz", hash = "sha256:87ca8328883de6036443e1c37b40e8dc8fb74898240f61071e09d2e369361456", size = 279826, upload-time = "2025-10-06T20:30:02.194Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/7b/5652771e24fff12da9dde4c20ecf4682e606b104f26419d139758cc935a6/azure_identity-1.25.1-py3-none-any.whl", hash = "sha256:e9edd720af03dff020223cd269fa3a61e8f345ea75443858273bcb44844ab651", size = 191317, upload-time = "2025-10-06T20:30:04.251Z" }, +] + +[[package]] +name = "azure-storage-blob" +version = "12.27.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "azure-core" }, + { name = "cryptography" }, + { name = "isodate" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/7c/2fd872e11a88163f208b9c92de273bf64bb22d0eef9048cc6284d128a77a/azure_storage_blob-12.27.1.tar.gz", hash = "sha256:a1596cc4daf5dac9be115fcb5db67245eae894cf40e4248243754261f7b674a6", size = 597579, upload-time = "2025-10-29T12:27:16.185Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/9e/1c90a122ea6180e8c72eb7294adc92531b0e08eb3d2324c2ba70d37f4802/azure_storage_blob-12.27.1-py3-none-any.whl", hash = "sha256:65d1e25a4628b7b6acd20ff7902d8da5b4fde8e46e19c8f6d213a3abc3ece272", size = 428954, upload-time = "2025-10-29T12:27:18.072Z" }, +] + +[[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 = "3.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/36/edc85ab295ceff724506252b774155eff8a238f13730c8b13badd33ef866/bcrypt-3.2.2.tar.gz", hash = "sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb", size = 42455, upload-time = "2022-05-01T17:58:52.348Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c2/05354b1d4351d2e686a32296cc9dd1e63f9909a580636df0f7b06d774600/bcrypt-3.2.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e", size = 50049, upload-time = "2022-05-01T18:05:47.625Z" }, + { url = "https://files.pythonhosted.org/packages/8c/b3/1257f7d64ee0aa0eb4fb1de5da8c2647a57db7b737da1f2342ac1889d3b8/bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26", size = 54914, upload-time = "2022-05-01T18:03:00.752Z" }, + { url = "https://files.pythonhosted.org/packages/61/3d/dce83194830183aa700cab07c89822471d21663a86a0b305d1e5c7b02810/bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb", size = 54403, upload-time = "2022-05-01T18:03:02.483Z" }, + { url = "https://files.pythonhosted.org/packages/86/1b/f4d7425dfc6cd0e405b48ee484df6d80fb39e05f25963dbfcc2c511e8341/bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a", size = 62337, upload-time = "2022-05-01T18:05:49.524Z" }, + { url = "https://files.pythonhosted.org/packages/3e/df/289db4f31b303de6addb0897c8b5c01b23bd4b8c511ac80a32b08658847c/bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521", size = 61026, upload-time = "2022-05-01T18:05:51.107Z" }, + { url = "https://files.pythonhosted.org/packages/40/8f/b67b42faa2e4d944b145b1a402fc08db0af8fe2dfa92418c674b5a302496/bcrypt-3.2.2-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40", size = 64672, upload-time = "2022-05-01T18:05:52.748Z" }, + { url = "https://files.pythonhosted.org/packages/fc/9a/e1867f0b27a3f4ce90e21dd7f322f0e15d4aac2434d3b938dcf765e47c6b/bcrypt-3.2.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa", size = 56795, upload-time = "2022-05-01T18:03:04.028Z" }, + { url = "https://files.pythonhosted.org/packages/18/76/057b0637c880e6cb0abdc8a867d080376ddca6ed7d05b7738f589cc5c1a8/bcrypt-3.2.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa", size = 62075, upload-time = "2022-05-01T18:05:54.412Z" }, + { url = "https://files.pythonhosted.org/packages/f1/64/cd93e2c3e28a5fa8bcf6753d5cc5e858e4da08bf51404a0adb6a412532de/bcrypt-3.2.2-cp36-abi3-win32.whl", hash = "sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e", size = 27916, upload-time = "2022-05-01T18:05:56.45Z" }, + { url = "https://files.pythonhosted.org/packages/f5/37/7cd297ff571c4d86371ff024c0e008b37b59e895b28f69444a9b6f94ca1a/bcrypt-3.2.2-cp36-abi3-win_amd64.whl", hash = "sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129", size = 29581, upload-time = "2022-05-01T18:05:57.878Z" }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cryptography" +version = "46.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, + { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, + { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, + { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, + { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, + { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, + { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, + { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, + { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, + { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e2/a510aa736755bffa9d2f75029c229111a1d02f8ecd5de03078f4c18d91a3/cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217", size = 7158012, upload-time = "2025-10-15T23:17:19.982Z" }, + { url = "https://files.pythonhosted.org/packages/73/dc/9aa866fbdbb95b02e7f9d086f1fccfeebf8953509b87e3f28fff927ff8a0/cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5", size = 4288728, upload-time = "2025-10-15T23:17:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/c5/fd/bc1daf8230eaa075184cbbf5f8cd00ba9db4fd32d63fb83da4671b72ed8a/cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715", size = 4435078, upload-time = "2025-10-15T23:17:23.042Z" }, + { url = "https://files.pythonhosted.org/packages/82/98/d3bd5407ce4c60017f8ff9e63ffee4200ab3e23fe05b765cab805a7db008/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54", size = 4293460, upload-time = "2025-10-15T23:17:24.885Z" }, + { url = "https://files.pythonhosted.org/packages/26/e9/e23e7900983c2b8af7a08098db406cf989d7f09caea7897e347598d4cd5b/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459", size = 3995237, upload-time = "2025-10-15T23:17:26.449Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/af68c509d4a138cfe299d0d7ddb14afba15233223ebd933b4bbdbc7155d3/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422", size = 4967344, upload-time = "2025-10-15T23:17:28.06Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e3/8643d077c53868b681af077edf6b3cb58288b5423610f21c62aadcbe99f4/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7", size = 4466564, upload-time = "2025-10-15T23:17:29.665Z" }, + { url = "https://files.pythonhosted.org/packages/0e/43/c1e8726fa59c236ff477ff2b5dc071e54b21e5a1e51aa2cee1676f1c986f/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044", size = 4292415, upload-time = "2025-10-15T23:17:31.686Z" }, + { url = "https://files.pythonhosted.org/packages/42/f9/2f8fefdb1aee8a8e3256a0568cffc4e6d517b256a2fe97a029b3f1b9fe7e/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665", size = 4931457, upload-time = "2025-10-15T23:17:33.478Z" }, + { url = "https://files.pythonhosted.org/packages/79/30/9b54127a9a778ccd6d27c3da7563e9f2d341826075ceab89ae3b41bf5be2/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3", size = 4466074, upload-time = "2025-10-15T23:17:35.158Z" }, + { url = "https://files.pythonhosted.org/packages/ac/68/b4f4a10928e26c941b1b6a179143af9f4d27d88fe84a6a3c53592d2e76bf/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20", size = 4420569, upload-time = "2025-10-15T23:17:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/a3/49/3746dab4c0d1979888f125226357d3262a6dd40e114ac29e3d2abdf1ec55/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de", size = 4681941, upload-time = "2025-10-15T23:17:39.236Z" }, + { url = "https://files.pythonhosted.org/packages/fd/30/27654c1dbaf7e4a3531fa1fc77986d04aefa4d6d78259a62c9dc13d7ad36/cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914", size = 3022339, upload-time = "2025-10-15T23:17:40.888Z" }, + { url = "https://files.pythonhosted.org/packages/f6/30/640f34ccd4d2a1bc88367b54b926b781b5a018d65f404d409aba76a84b1c/cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db", size = 3494315, upload-time = "2025-10-15T23:17:42.769Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8b/88cc7e3bd0a8e7b861f26981f7b820e1f46aa9d26cc482d0feba0ecb4919/cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21", size = 2919331, upload-time = "2025-10-15T23:17:44.468Z" }, + { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, + { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, + { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, + { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, + { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, + { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, + { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, + { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, + { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, + { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, +] + +[[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 = "dotenv" +version = "0.9.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dotenv" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/b7/545d2c10c1fc15e48653c91efde329a790f2eecfbbf2bd16003b5db2bab0/dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9", size = 1892, upload-time = "2025-02-19T22:15:01.647Z" }, +] + +[[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.127.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0c/02/2cbbecf6551e0c1a06f9b9765eb8f7ae126362fbba43babbb11b0e3b7db3/fastapi-0.127.0.tar.gz", hash = "sha256:5a9246e03dcd1fdb19f1396db30894867c1d630f5107dc167dcbc5ed1ea7d259", size = 369269, upload-time = "2025-12-21T16:47:16.393Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/fa/6a27e2ef789eb03060abb43b952a7f0bd39e6feaa3805362b48785bcedc5/fastapi-0.127.0-py3-none-any.whl", hash = "sha256:725aa2bb904e2eff8031557cf4b9b77459bfedd63cae8427634744fd199f6a49", size = 112055, upload-time = "2025-12-21T16:47:14.757Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "email-validator" }, + { name = "fastapi-cli", extra = ["standard"] }, + { name = "httpx" }, + { name = "jinja2" }, + { name = "pydantic-extra-types" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[[package]] +name = "fastapi-cli" +version = "0.0.20" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "rich-toolkit" }, + { name = "typer" }, + { name = "uvicorn", extra = ["standard"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d3/ca/d90fb3bfbcbd6e56c77afd9d114dd6ce8955d8bb90094399d1c70e659e40/fastapi_cli-0.0.20.tar.gz", hash = "sha256:d17c2634f7b96b6b560bc16b0035ed047d523c912011395f49f00a421692bc3a", size = 19786, upload-time = "2025-12-22T17:13:33.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/89/5c4eef60524d0fd704eb0706885b82cd5623a43396b94e4a5b17d3a3f516/fastapi_cli-0.0.20-py3-none-any.whl", hash = "sha256:e58b6a0038c0b1532b7a0af690656093dee666201b6b19d3c87175b358e9f783", size = 12390, upload-time = "2025-12-22T17:13:31.708Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "fastapi-cloud-cli" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[[package]] +name = "fastapi-cloud-cli" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastar" }, + { name = "httpx" }, + { name = "pydantic", extra = ["email"] }, + { name = "rich-toolkit" }, + { name = "rignore" }, + { name = "sentry-sdk" }, + { name = "typer" }, + { name = "uvicorn", extra = ["standard"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/5d/3b33438de35521fab4968b232caa9a4bd568a5078f2b2dfb7bb8a4528603/fastapi_cloud_cli-0.8.0.tar.gz", hash = "sha256:cf07c502528bfd9e6b184776659f05d9212811d76bbec9fbb6bf34bed4c7456f", size = 30257, upload-time = "2025-12-23T12:08:33.904Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/8e/abb95ef59e91bb5adaa2d18fbf9ea70fd524010bb03f406a2dd2a4775ef9/fastapi_cloud_cli-0.8.0-py3-none-any.whl", hash = "sha256:e9f40bee671d985fd25d7a5409b56d4f103777bf8a0c6d746ea5fbf97a8186d9", size = 22306, upload-time = "2025-12-23T12:08:32.68Z" }, +] + +[[package]] +name = "fastar" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524, upload-time = "2025-11-26T02:36:00.72Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/a5/79ecba3646e22d03eef1a66fb7fc156567213e2e4ab9faab3bbd4489e483/fastar-0.8.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a3253a06845462ca2196024c7a18f5c0ba4de1532ab1c4bad23a40b332a06a6a", size = 706112, upload-time = "2025-11-26T02:34:39.237Z" }, + { url = "https://files.pythonhosted.org/packages/0a/03/4f883bce878218a8676c2d7ca09b50c856a5470bb3b7f63baf9521ea6995/fastar-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5cbeb3ebfa0980c68ff8b126295cc6b208ccd81b638aebc5a723d810a7a0e5d2", size = 628954, upload-time = "2025-11-26T02:34:23.705Z" }, + { url = "https://files.pythonhosted.org/packages/4f/f1/892e471f156b03d10ba48ace9384f5a896702a54506137462545f38e40b8/fastar-0.8.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1c0d5956b917daac77d333d48b3f0f3ff927b8039d5b32d8125462782369f761", size = 868685, upload-time = "2025-11-26T02:33:53.077Z" }, + { url = "https://files.pythonhosted.org/packages/39/ba/e24915045852e30014ec6840446975c03f4234d1c9270394b51d3ad18394/fastar-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27b404db2b786b65912927ce7f3790964a4bcbde42cdd13091b82a89cd655e1c", size = 765044, upload-time = "2025-11-26T02:32:48.187Z" }, + { url = "https://files.pythonhosted.org/packages/14/2c/1aa11ac21a99984864c2fca4994e094319ff3a2046e7a0343c39317bd5b9/fastar-0.8.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0902fc89dcf1e7f07b8563032a4159fe2b835e4c16942c76fd63451d0e5f76a3", size = 764322, upload-time = "2025-11-26T02:33:03.859Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f0/4b91902af39fe2d3bae7c85c6d789586b9fbcf618d7fdb3d37323915906d/fastar-0.8.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:069347e2f0f7a8b99bbac8cd1bc0e06c7b4a31dc964fc60d84b95eab3d869dc1", size = 931016, upload-time = "2025-11-26T02:33:19.902Z" }, + { url = "https://files.pythonhosted.org/packages/c9/97/8fc43a5a9c0a2dc195730f6f7a0f367d171282cd8be2511d0e87c6d2dad0/fastar-0.8.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd135306f6bfe9a835918280e0eb440b70ab303e0187d90ab51ca86e143f70d", size = 821308, upload-time = "2025-11-26T02:33:34.664Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e9/058615b63a7fd27965e8c5966f393ed0c169f7ff5012e1674f21684de3ba/fastar-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d06d6897f43c27154b5f2d0eb930a43a81b7eec73f6f0b0114814d4a10ab38", size = 821171, upload-time = "2025-11-26T02:34:08.498Z" }, + { url = "https://files.pythonhosted.org/packages/ca/cf/69e16a17961570a755c37ffb5b5aa7610d2e77807625f537989da66f2a9d/fastar-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a922f8439231fa0c32b15e8d70ff6d415619b9d40492029dabbc14a0c53b5f18", size = 986227, upload-time = "2025-11-26T02:34:55.06Z" }, + { url = "https://files.pythonhosted.org/packages/fb/83/2100192372e59b56f4ace37d7d9cabda511afd71b5febad1643d1c334271/fastar-0.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a739abd51eb766384b4caff83050888e80cd75bbcfec61e6d1e64875f94e4a40", size = 1039395, upload-time = "2025-11-26T02:35:12.166Z" }, + { url = "https://files.pythonhosted.org/packages/75/15/cdd03aca972f55872efbb7cf7540c3fa7b97a75d626303a3ea46932163dc/fastar-0.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5a65f419d808b23ac89d5cd1b13a2f340f15bc5d1d9af79f39fdb77bba48ff1b", size = 1044766, upload-time = "2025-11-26T02:35:29.62Z" }, + { url = "https://files.pythonhosted.org/packages/3d/29/945e69e4e2652329ace545999334ec31f1431fbae3abb0105587e11af2ae/fastar-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7bb2ae6c0cce58f0db1c9f20495e7557cca2c1ee9c69bbd90eafd54f139171c5", size = 994740, upload-time = "2025-11-26T02:35:47.887Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5d/dbfe28f8cd1eb484bba0c62e5259b2cf6fea229d6ef43e05c06b5a78c034/fastar-0.8.0-cp313-cp313-win32.whl", hash = "sha256:b28753e0d18a643272597cb16d39f1053842aa43131ad3e260c03a2417d38401", size = 455990, upload-time = "2025-11-26T02:36:28.502Z" }, + { url = "https://files.pythonhosted.org/packages/e1/01/e965740bd36e60ef4c5aa2cbe42b6c4eb1dc3551009238a97c2e5e96bd23/fastar-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:620e5d737dce8321d49a5ebb7997f1fd0047cde3512082c27dc66d6ac8c1927a", size = 490227, upload-time = "2025-11-26T02:36:14.363Z" }, + { url = "https://files.pythonhosted.org/packages/dd/10/c99202719b83e5249f26902ae53a05aea67d840eeb242019322f20fc171c/fastar-0.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:c4c4bd08df563120cd33e854fe0a93b81579e8571b11f9b7da9e84c37da2d6b6", size = 461078, upload-time = "2025-11-26T02:36:04.94Z" }, + { url = "https://files.pythonhosted.org/packages/96/4a/9573b87a0ef07580ed111e7230259aec31bb33ca3667963ebee77022ec61/fastar-0.8.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:50b36ce654ba44b0e13fae607ae17ee6e1597b69f71df1bee64bb8328d881dfc", size = 706041, upload-time = "2025-11-26T02:34:40.638Z" }, + { url = "https://files.pythonhosted.org/packages/4a/19/f95444a1d4f375333af49300aa75ee93afa3335c0e40fda528e460ed859c/fastar-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:63a892762683d7ab00df0227d5ea9677c62ff2cde9b875e666c0be569ed940f3", size = 628617, upload-time = "2025-11-26T02:34:24.893Z" }, + { url = "https://files.pythonhosted.org/packages/b3/c9/b51481b38b7e3f16ef2b9e233b1a3623386c939d745d6e41bbd389eaae30/fastar-0.8.0-cp314-cp314-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4ae6a145c1bff592644bde13f2115e0239f4b7babaf506d14e7d208483cf01a5", size = 869299, upload-time = "2025-11-26T02:33:54.274Z" }, + { url = "https://files.pythonhosted.org/packages/bf/02/3ba1267ee5ba7314e29c431cf82eaa68586f2c40cdfa08be3632b7d07619/fastar-0.8.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ae0ff7c0a1c7e1428404b81faee8aebef466bfd0be25bfe4dabf5d535c68741", size = 764667, upload-time = "2025-11-26T02:32:49.606Z" }, + { url = "https://files.pythonhosted.org/packages/1b/84/bf33530fd015b5d7c2cc69e0bce4a38d736754a6955487005aab1af6adcd/fastar-0.8.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dbfd87dbd217b45c898b2dbcd0169aae534b2c1c5cbe3119510881f6a5ac8ef5", size = 763993, upload-time = "2025-11-26T02:33:05.782Z" }, + { url = "https://files.pythonhosted.org/packages/da/e0/9564d24e7cea6321a8d921c6d2a457044a476ef197aa4708e179d3d97f0d/fastar-0.8.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5abd99fcba83ef28c8fe6ae2927edc79053db43a0457a962ed85c9bf150d37", size = 930153, upload-time = "2025-11-26T02:33:21.53Z" }, + { url = "https://files.pythonhosted.org/packages/35/b1/6f57fcd8d6e192cfebf97e58eb27751640ad93784c857b79039e84387b51/fastar-0.8.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91d4c685620c3a9d6b5ae091dbabab4f98b20049b7ecc7976e19cc9016c0d5d6", size = 821177, upload-time = "2025-11-26T02:33:35.839Z" }, + { url = "https://files.pythonhosted.org/packages/b3/78/9e004ea9f3aa7466f5ddb6f9518780e1d2f0ed3ca55f093632982598bace/fastar-0.8.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f77c2f2cad76e9dc7b6701297adb1eba87d0485944b416fc2ccf5516c01219a3", size = 820652, upload-time = "2025-11-26T02:34:09.776Z" }, + { url = "https://files.pythonhosted.org/packages/42/95/b604ed536544005c9f1aee7c4c74b00150db3d8d535cd8232dc20f947063/fastar-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e7f07c4a3dada7757a8fc430a5b4a29e6ef696d2212747213f57086ffd970316", size = 985961, upload-time = "2025-11-26T02:34:56.401Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7b/fa9d4d96a5d494bdb8699363bb9de8178c0c21a02e1d89cd6f913d127018/fastar-0.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:90c0c3fe55105c0aed8a83135dbdeb31e683455dbd326a1c48fa44c378b85616", size = 1039316, upload-time = "2025-11-26T02:35:13.807Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f9/8462789243bc3f33e8401378ec6d54de4e20cfa60c96a0e15e3e9d1389bb/fastar-0.8.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fb9ee51e5bffe0dab3d3126d3a4fac8d8f7235cedcb4b8e74936087ce1c157f3", size = 1045028, upload-time = "2025-11-26T02:35:31.079Z" }, + { url = "https://files.pythonhosted.org/packages/a5/71/9abb128777e616127194b509e98fcda3db797d76288c1a8c23dd22afc14f/fastar-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e380b1e8d30317f52406c43b11e98d11e1d68723bbd031e18049ea3497b59a6d", size = 994677, upload-time = "2025-11-26T02:35:49.391Z" }, + { url = "https://files.pythonhosted.org/packages/de/c1/b81b3f194853d7ad232a67a1d768f5f51a016f165cfb56cb31b31bbc6177/fastar-0.8.0-cp314-cp314-win32.whl", hash = "sha256:1c4ffc06e9c4a8ca498c07e094670d8d8c0d25b17ca6465b9774da44ea997ab1", size = 456687, upload-time = "2025-11-26T02:36:30.205Z" }, + { url = "https://files.pythonhosted.org/packages/cb/87/9e0cd4768a98181d56f0cdbab2363404cc15deb93f4aad3b99cd2761bbaa/fastar-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:5517a8ad4726267c57a3e0e2a44430b782e00b230bf51c55b5728e758bb3a692", size = 490578, upload-time = "2025-11-26T02:36:16.218Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1e/580a76cf91847654f2ad6520e956e93218f778540975bc4190d363f709e2/fastar-0.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:58030551046ff4a8616931e52a36c83545ff05996db5beb6e0cd2b7e748aa309", size = 461473, upload-time = "2025-11-26T02:36:06.373Z" }, + { url = "https://files.pythonhosted.org/packages/58/4c/bdb5c6efe934f68708529c8c9d4055ebef5c4be370621966438f658b29bd/fastar-0.8.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:1e7d29b6bfecb29db126a08baf3c04a5ab667f6cea2b7067d3e623a67729c4a6", size = 705570, upload-time = "2025-11-26T02:34:42.01Z" }, + { url = "https://files.pythonhosted.org/packages/6d/78/f01ac7e71d5a37621bd13598a26e948a12b85ca8042f7ee1a0a8c9f59cda/fastar-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:05eb7b96940f9526b485f1d0b02393839f0f61cac4b1f60024984f8b326d2640", size = 627761, upload-time = "2025-11-26T02:34:26.152Z" }, + { url = "https://files.pythonhosted.org/packages/06/45/6df0ecda86ea9d2e95053c1a655d153dee55fc121b6e13ea6d1e246a50b6/fastar-0.8.0-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:619352d8ac011794e2345c462189dc02ba634750d23cd9d86a9267dd71b1f278", size = 869414, upload-time = "2025-11-26T02:33:55.618Z" }, + { url = "https://files.pythonhosted.org/packages/b2/72/486421f5a8c0c377cc82e7a50c8a8ea899a6ec2aa72bde8f09fb667a2dc8/fastar-0.8.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74ebfecef3fe6d7a90355fac1402fd30636988332a1d33f3e80019a10782bb24", size = 763863, upload-time = "2025-11-26T02:32:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/39f654dbb41a3867fb1f2c8081c014d8f1d32ea10585d84cacbef0b32995/fastar-0.8.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2975aca5a639e26a3ab0d23b4b0628d6dd6d521146c3c11486d782be621a35aa", size = 763065, upload-time = "2025-11-26T02:33:07.274Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bd/c011a34fb3534c4c3301f7c87c4ffd7e47f6113c904c092ddc8a59a303ea/fastar-0.8.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afc438eaed8ff0dcdd9308268be5cb38c1db7e94c3ccca7c498ca13a4a4535a3", size = 930530, upload-time = "2025-11-26T02:33:23.117Z" }, + { url = "https://files.pythonhosted.org/packages/55/9d/aa6e887a7033c571b1064429222bbe09adc9a3c1e04f3d1788ba5838ebd5/fastar-0.8.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ced0a5399cc0a84a858ef0a31ca2d0c24d3bbec4bcda506a9192d8119f3590a", size = 820572, upload-time = "2025-11-26T02:33:37.542Z" }, + { url = "https://files.pythonhosted.org/packages/ad/9c/7a3a2278a1052e1a5d98646de7c095a00cffd2492b3b84ce730e2f1cd93a/fastar-0.8.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec9b23da8c4c039da3fe2e358973c66976a0c8508aa06d6626b4403cb5666c19", size = 820649, upload-time = "2025-11-26T02:34:11.108Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/d38edc1f4438cd047e56137c26d94783ffade42e1b3bde620ccf17b771ef/fastar-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:dfba078fcd53478032fd0ceed56960ec6b7ff0511cfc013a8a3a4307e3a7bac4", size = 985653, upload-time = "2025-11-26T02:34:57.884Z" }, + { url = "https://files.pythonhosted.org/packages/69/d9/2147d0c19757e165cd62d41cec3f7b38fad2ad68ab784978b5f81716c7ea/fastar-0.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ade56c94c14be356d295fecb47a3fcd473dd43a8803ead2e2b5b9e58feb6dcfa", size = 1038140, upload-time = "2025-11-26T02:35:15.778Z" }, + { url = "https://files.pythonhosted.org/packages/7f/1d/ec4c717ffb8a308871e9602ec3197d957e238dc0227127ac573ec9bca952/fastar-0.8.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e48d938f9366db5e59441728f70b7f6c1ccfab7eff84f96f9b7e689b07786c52", size = 1045195, upload-time = "2025-11-26T02:35:32.865Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/637334dc8c8f3bb391388b064ae13f0ad9402bc5a6c3e77b8887d0c31921/fastar-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:79c441dc1482ff51a54fb3f57ae6f7bb3d2cff88fa2cc5d196c519f8aab64a56", size = 994686, upload-time = "2025-11-26T02:35:51.392Z" }, + { url = "https://files.pythonhosted.org/packages/c9/e2/dfa19a4b260b8ab3581b7484dcb80c09b25324f4daa6b6ae1c7640d1607a/fastar-0.8.0-cp314-cp314t-win32.whl", hash = "sha256:187f61dc739afe45ac8e47ed7fd1adc45d52eac110cf27d579155720507d6fbe", size = 455767, upload-time = "2025-11-26T02:36:34.758Z" }, + { url = "https://files.pythonhosted.org/packages/51/47/df65c72afc1297797b255f90c4778b5d6f1f0f80282a134d5ab610310ed9/fastar-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:40e9d763cf8bf85ce2fa256e010aa795c0fe3d3bd1326d5c3084e6ce7857127e", size = 489971, upload-time = "2025-11-26T02:36:22.081Z" }, + { url = "https://files.pythonhosted.org/packages/85/11/0aa8455af26f0ae89e42be67f3a874255ee5d7f0f026fc86e8d56f76b428/fastar-0.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e59673307b6a08210987059a2bdea2614fe26e3335d0e5d1a3d95f49a05b1418", size = 460467, upload-time = "2025-11-26T02:36:07.978Z" }, +] + +[[package]] +name = "frontend" +version = "0.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiofiles" }, + { name = "itsdangerous" }, + { name = "starlette" }, + { name = "uvicorn" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/8d/0caf67efc5ab7caa2f1e90f8fcadd6cf84c25f16826f55f1a0d3eee997c0/frontend-0.0.3.tar.gz", hash = "sha256:cdb5e76a0082b9cd3fa8331dbe44c86f007ab6d07c540551078f60318cd2e019", size = 15649, upload-time = "2020-04-15T12:21:37.993Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/02/a9c4713b26ae11464ac334b59504ef6fe66e2c323ee44520ca1cd6dc4929/frontend-0.0.3-py3-none-any.whl", hash = "sha256:9b36d7092892271431cd693eaca14767acbdbb67f6f6f38dc3e0ff15618c7109", size = 32633, upload-time = "2020-04-15T12:21:36.242Z" }, +] + +[[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/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 = "greenlet" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/2f/28592176381b9ab2cafa12829ba7b472d177f3acc35d8fbcf3673d966fff/greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", size = 275140, upload-time = "2025-12-04T14:23:01.282Z" }, + { url = "https://files.pythonhosted.org/packages/2c/80/fbe937bf81e9fca98c981fe499e59a3f45df2a04da0baa5c2be0dca0d329/greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", size = 599219, upload-time = "2025-12-04T14:50:08.309Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ff/7c985128f0514271b8268476af89aee6866df5eec04ac17dcfbc676213df/greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", size = 610211, upload-time = "2025-12-04T14:57:43.968Z" }, + { url = "https://files.pythonhosted.org/packages/79/07/c47a82d881319ec18a4510bb30463ed6891f2ad2c1901ed5ec23d3de351f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", size = 624311, upload-time = "2025-12-04T15:07:14.697Z" }, + { url = "https://files.pythonhosted.org/packages/fd/8e/424b8c6e78bd9837d14ff7df01a9829fc883ba2ab4ea787d4f848435f23f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", size = 612833, upload-time = "2025-12-04T14:26:03.669Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ba/56699ff9b7c76ca12f1cdc27a886d0f81f2189c3455ff9f65246780f713d/greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", size = 1567256, upload-time = "2025-12-04T15:04:25.276Z" }, + { url = "https://files.pythonhosted.org/packages/1e/37/f31136132967982d698c71a281a8901daf1a8fbab935dce7c0cf15f942cc/greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", size = 1636483, upload-time = "2025-12-04T14:27:30.804Z" }, + { url = "https://files.pythonhosted.org/packages/7e/71/ba21c3fb8c5dce83b8c01f458a42e99ffdb1963aeec08fff5a18588d8fd7/greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38", size = 301833, upload-time = "2025-12-04T14:32:23.929Z" }, + { url = "https://files.pythonhosted.org/packages/d7/7c/f0a6d0ede2c7bf092d00bc83ad5bafb7e6ec9b4aab2fbdfa6f134dc73327/greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", size = 275671, upload-time = "2025-12-04T14:23:05.267Z" }, + { url = "https://files.pythonhosted.org/packages/44/06/dac639ae1a50f5969d82d2e3dd9767d30d6dbdbab0e1a54010c8fe90263c/greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", size = 646360, upload-time = "2025-12-04T14:50:10.026Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/0fb76fe6c5369fba9bf98529ada6f4c3a1adf19e406a47332245ef0eb357/greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", size = 658160, upload-time = "2025-12-04T14:57:45.41Z" }, + { url = "https://files.pythonhosted.org/packages/93/79/d2c70cae6e823fac36c3bbc9077962105052b7ef81db2f01ec3b9bf17e2b/greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", size = 671388, upload-time = "2025-12-04T15:07:15.789Z" }, + { url = "https://files.pythonhosted.org/packages/b8/14/bab308fc2c1b5228c3224ec2bf928ce2e4d21d8046c161e44a2012b5203e/greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", size = 660166, upload-time = "2025-12-04T14:26:05.099Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d2/91465d39164eaa0085177f61983d80ffe746c5a1860f009811d498e7259c/greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", size = 1615193, upload-time = "2025-12-04T15:04:27.041Z" }, + { url = "https://files.pythonhosted.org/packages/42/1b/83d110a37044b92423084d52d5d5a3b3a73cafb51b547e6d7366ff62eff1/greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", size = 1683653, upload-time = "2025-12-04T14:27:32.366Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/9030e6f9aa8fd7808e9c31ba4c38f87c4f8ec324ee67431d181fe396d705/greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170", size = 305387, upload-time = "2025-12-04T14:26:51.063Z" }, + { url = "https://files.pythonhosted.org/packages/a0/66/bd6317bc5932accf351fc19f177ffba53712a202f9df10587da8df257c7e/greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", size = 282638, upload-time = "2025-12-04T14:25:20.941Z" }, + { url = "https://files.pythonhosted.org/packages/30/cf/cc81cb030b40e738d6e69502ccbd0dd1bced0588e958f9e757945de24404/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", size = 651145, upload-time = "2025-12-04T14:50:11.039Z" }, + { url = "https://files.pythonhosted.org/packages/9c/ea/1020037b5ecfe95ca7df8d8549959baceb8186031da83d5ecceff8b08cd2/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", size = 654236, upload-time = "2025-12-04T14:57:47.007Z" }, + { url = "https://files.pythonhosted.org/packages/69/cc/1e4bae2e45ca2fa55299f4e85854606a78ecc37fead20d69322f96000504/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", size = 662506, upload-time = "2025-12-04T15:07:16.906Z" }, + { url = "https://files.pythonhosted.org/packages/57/b9/f8025d71a6085c441a7eaff0fd928bbb275a6633773667023d19179fe815/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", size = 653783, upload-time = "2025-12-04T14:26:06.225Z" }, + { url = "https://files.pythonhosted.org/packages/f6/c7/876a8c7a7485d5d6b5c6821201d542ef28be645aa024cfe1145b35c120c1/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", size = 1614857, upload-time = "2025-12-04T15:04:28.484Z" }, + { url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034, upload-time = "2025-12-04T14:27:33.531Z" }, +] + +[[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 = "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/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 = "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 = "isodate" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705, upload-time = "2024-10-08T23:04:11.5Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320, upload-time = "2024-10-08T23:04:09.501Z" }, +] + +[[package]] +name = "itsdangerous" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, +] + +[[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.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294, upload-time = "2025-11-09T20:49:23.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/a6/97209693b177716e22576ee1161674d1d58029eb178e01866a0422b69224/jiter-0.12.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6cc49d5130a14b732e0612bc76ae8db3b49898732223ef8b7599aa8d9810683e", size = 313658, upload-time = "2025-11-09T20:47:44.424Z" }, + { url = "https://files.pythonhosted.org/packages/06/4d/125c5c1537c7d8ee73ad3d530a442d6c619714b95027143f1b61c0b4dfe0/jiter-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37f27a32ce36364d2fa4f7fdc507279db604d27d239ea2e044c8f148410defe1", size = 318605, upload-time = "2025-11-09T20:47:45.973Z" }, + { url = "https://files.pythonhosted.org/packages/99/bf/a840b89847885064c41a5f52de6e312e91fa84a520848ee56c97e4fa0205/jiter-0.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbc0944aa3d4b4773e348cda635252824a78f4ba44328e042ef1ff3f6080d1cf", size = 349803, upload-time = "2025-11-09T20:47:47.535Z" }, + { url = "https://files.pythonhosted.org/packages/8a/88/e63441c28e0db50e305ae23e19c1d8fae012d78ed55365da392c1f34b09c/jiter-0.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da25c62d4ee1ffbacb97fac6dfe4dcd6759ebdc9015991e92a6eae5816287f44", size = 365120, upload-time = "2025-11-09T20:47:49.284Z" }, + { url = "https://files.pythonhosted.org/packages/0a/7c/49b02714af4343970eb8aca63396bc1c82fa01197dbb1e9b0d274b550d4e/jiter-0.12.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:048485c654b838140b007390b8182ba9774621103bd4d77c9c3f6f117474ba45", size = 479918, upload-time = "2025-11-09T20:47:50.807Z" }, + { url = "https://files.pythonhosted.org/packages/69/ba/0a809817fdd5a1db80490b9150645f3aae16afad166960bcd562be194f3b/jiter-0.12.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:635e737fbb7315bef0037c19b88b799143d2d7d3507e61a76751025226b3ac87", size = 379008, upload-time = "2025-11-09T20:47:52.211Z" }, + { url = "https://files.pythonhosted.org/packages/5f/c3/c9fc0232e736c8877d9e6d83d6eeb0ba4e90c6c073835cc2e8f73fdeef51/jiter-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e017c417b1ebda911bd13b1e40612704b1f5420e30695112efdbed8a4b389ed", size = 361785, upload-time = "2025-11-09T20:47:53.512Z" }, + { url = "https://files.pythonhosted.org/packages/96/61/61f69b7e442e97ca6cd53086ddc1cf59fb830549bc72c0a293713a60c525/jiter-0.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:89b0bfb8b2bf2351fba36bb211ef8bfceba73ef58e7f0c68fb67b5a2795ca2f9", size = 386108, upload-time = "2025-11-09T20:47:54.893Z" }, + { url = "https://files.pythonhosted.org/packages/e9/2e/76bb3332f28550c8f1eba3bf6e5efe211efda0ddbbaf24976bc7078d42a5/jiter-0.12.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:f5aa5427a629a824a543672778c9ce0c5e556550d1569bb6ea28a85015287626", size = 519937, upload-time = "2025-11-09T20:47:56.253Z" }, + { url = "https://files.pythonhosted.org/packages/84/d6/fa96efa87dc8bff2094fb947f51f66368fa56d8d4fc9e77b25d7fbb23375/jiter-0.12.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed53b3d6acbcb0fd0b90f20c7cb3b24c357fe82a3518934d4edfa8c6898e498c", size = 510853, upload-time = "2025-11-09T20:47:58.32Z" }, + { url = "https://files.pythonhosted.org/packages/8a/28/93f67fdb4d5904a708119a6ab58a8f1ec226ff10a94a282e0215402a8462/jiter-0.12.0-cp313-cp313-win32.whl", hash = "sha256:4747de73d6b8c78f2e253a2787930f4fffc68da7fa319739f57437f95963c4de", size = 204699, upload-time = "2025-11-09T20:47:59.686Z" }, + { url = "https://files.pythonhosted.org/packages/c4/1f/30b0eb087045a0abe2a5c9c0c0c8da110875a1d3be83afd4a9a4e548be3c/jiter-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e25012eb0c456fcc13354255d0338cd5397cce26c77b2832b3c4e2e255ea5d9a", size = 204258, upload-time = "2025-11-09T20:48:01.01Z" }, + { url = "https://files.pythonhosted.org/packages/2c/f4/2b4daf99b96bce6fc47971890b14b2a36aef88d7beb9f057fafa032c6141/jiter-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:c97b92c54fe6110138c872add030a1f99aea2401ddcdaa21edf74705a646dd60", size = 185503, upload-time = "2025-11-09T20:48:02.35Z" }, + { url = "https://files.pythonhosted.org/packages/39/ca/67bb15a7061d6fe20b9b2a2fd783e296a1e0f93468252c093481a2f00efa/jiter-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53839b35a38f56b8be26a7851a48b89bc47e5d88e900929df10ed93b95fea3d6", size = 317965, upload-time = "2025-11-09T20:48:03.783Z" }, + { url = "https://files.pythonhosted.org/packages/18/af/1788031cd22e29c3b14bc6ca80b16a39a0b10e611367ffd480c06a259831/jiter-0.12.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94f669548e55c91ab47fef8bddd9c954dab1938644e715ea49d7e117015110a4", size = 345831, upload-time = "2025-11-09T20:48:05.55Z" }, + { url = "https://files.pythonhosted.org/packages/05/17/710bf8472d1dff0d3caf4ced6031060091c1320f84ee7d5dcbed1f352417/jiter-0.12.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:351d54f2b09a41600ffea43d081522d792e81dcfb915f6d2d242744c1cc48beb", size = 361272, upload-time = "2025-11-09T20:48:06.951Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f1/1dcc4618b59761fef92d10bcbb0b038b5160be653b003651566a185f1a5c/jiter-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2a5e90604620f94bf62264e7c2c038704d38217b7465b863896c6d7c902b06c7", size = 204604, upload-time = "2025-11-09T20:48:08.328Z" }, + { url = "https://files.pythonhosted.org/packages/d9/32/63cb1d9f1c5c6632a783c0052cde9ef7ba82688f7065e2f0d5f10a7e3edb/jiter-0.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:88ef757017e78d2860f96250f9393b7b577b06a956ad102c29c8237554380db3", size = 185628, upload-time = "2025-11-09T20:48:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/a8/99/45c9f0dbe4a1416b2b9a8a6d1236459540f43d7fb8883cff769a8db0612d/jiter-0.12.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c46d927acd09c67a9fb1416df45c5a04c27e83aae969267e98fba35b74e99525", size = 312478, upload-time = "2025-11-09T20:48:10.898Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a7/54ae75613ba9e0f55fcb0bc5d1f807823b5167cc944e9333ff322e9f07dd/jiter-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:774ff60b27a84a85b27b88cd5583899c59940bcc126caca97eb2a9df6aa00c49", size = 318706, upload-time = "2025-11-09T20:48:12.266Z" }, + { url = "https://files.pythonhosted.org/packages/59/31/2aa241ad2c10774baf6c37f8b8e1f39c07db358f1329f4eb40eba179c2a2/jiter-0.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5433fab222fb072237df3f637d01b81f040a07dcac1cb4a5c75c7aa9ed0bef1", size = 351894, upload-time = "2025-11-09T20:48:13.673Z" }, + { url = "https://files.pythonhosted.org/packages/54/4f/0f2759522719133a9042781b18cc94e335b6d290f5e2d3e6899d6af933e3/jiter-0.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8c593c6e71c07866ec6bfb790e202a833eeec885022296aff6b9e0b92d6a70e", size = 365714, upload-time = "2025-11-09T20:48:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6f/806b895f476582c62a2f52c453151edd8a0fde5411b0497baaa41018e878/jiter-0.12.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90d32894d4c6877a87ae00c6b915b609406819dce8bc0d4e962e4de2784e567e", size = 478989, upload-time = "2025-11-09T20:48:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/86/6c/012d894dc6e1033acd8db2b8346add33e413ec1c7c002598915278a37f79/jiter-0.12.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:798e46eed9eb10c3adbbacbd3bdb5ecd4cf7064e453d00dbef08802dae6937ff", size = 378615, upload-time = "2025-11-09T20:48:18.614Z" }, + { url = "https://files.pythonhosted.org/packages/87/30/d718d599f6700163e28e2c71c0bbaf6dace692e7df2592fd793ac9276717/jiter-0.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f1368f0a6719ea80013a4eb90ba72e75d7ea67cfc7846db2ca504f3df0169a", size = 364745, upload-time = "2025-11-09T20:48:20.117Z" }, + { url = "https://files.pythonhosted.org/packages/8f/85/315b45ce4b6ddc7d7fceca24068543b02bdc8782942f4ee49d652e2cc89f/jiter-0.12.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65f04a9d0b4406f7e51279710b27484af411896246200e461d80d3ba0caa901a", size = 386502, upload-time = "2025-11-09T20:48:21.543Z" }, + { url = "https://files.pythonhosted.org/packages/74/0b/ce0434fb40c5b24b368fe81b17074d2840748b4952256bab451b72290a49/jiter-0.12.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:fd990541982a24281d12b67a335e44f117e4c6cbad3c3b75c7dea68bf4ce3a67", size = 519845, upload-time = "2025-11-09T20:48:22.964Z" }, + { url = "https://files.pythonhosted.org/packages/e8/a3/7a7a4488ba052767846b9c916d208b3ed114e3eb670ee984e4c565b9cf0d/jiter-0.12.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:b111b0e9152fa7df870ecaebb0bd30240d9f7fff1f2003bcb4ed0f519941820b", size = 510701, upload-time = "2025-11-09T20:48:24.483Z" }, + { url = "https://files.pythonhosted.org/packages/c3/16/052ffbf9d0467b70af24e30f91e0579e13ded0c17bb4a8eb2aed3cb60131/jiter-0.12.0-cp314-cp314-win32.whl", hash = "sha256:a78befb9cc0a45b5a5a0d537b06f8544c2ebb60d19d02c41ff15da28a9e22d42", size = 205029, upload-time = "2025-11-09T20:48:25.749Z" }, + { url = "https://files.pythonhosted.org/packages/e4/18/3cf1f3f0ccc789f76b9a754bdb7a6977e5d1d671ee97a9e14f7eb728d80e/jiter-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:e1fe01c082f6aafbe5c8faf0ff074f38dfb911d53f07ec333ca03f8f6226debf", size = 204960, upload-time = "2025-11-09T20:48:27.415Z" }, + { url = "https://files.pythonhosted.org/packages/02/68/736821e52ecfdeeb0f024b8ab01b5a229f6b9293bbdb444c27efade50b0f/jiter-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:d72f3b5a432a4c546ea4bedc84cce0c3404874f1d1676260b9c7f048a9855451", size = 185529, upload-time = "2025-11-09T20:48:29.125Z" }, + { url = "https://files.pythonhosted.org/packages/30/61/12ed8ee7a643cce29ac97c2281f9ce3956eb76b037e88d290f4ed0d41480/jiter-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e6ded41aeba3603f9728ed2b6196e4df875348ab97b28fc8afff115ed42ba7a7", size = 318974, upload-time = "2025-11-09T20:48:30.87Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c6/f3041ede6d0ed5e0e79ff0de4c8f14f401bbf196f2ef3971cdbe5fd08d1d/jiter-0.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a947920902420a6ada6ad51892082521978e9dd44a802663b001436e4b771684", size = 345932, upload-time = "2025-11-09T20:48:32.658Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5d/4d94835889edd01ad0e2dbfc05f7bdfaed46292e7b504a6ac7839aa00edb/jiter-0.12.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:add5e227e0554d3a52cf390a7635edaffdf4f8fce4fdbcef3cc2055bb396a30c", size = 367243, upload-time = "2025-11-09T20:48:34.093Z" }, + { url = "https://files.pythonhosted.org/packages/fd/76/0051b0ac2816253a99d27baf3dda198663aff882fa6ea7deeb94046da24e/jiter-0.12.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9b1cda8fcb736250d7e8711d4580ebf004a46771432be0ae4796944b5dfa5d", size = 479315, upload-time = "2025-11-09T20:48:35.507Z" }, + { url = "https://files.pythonhosted.org/packages/70/ae/83f793acd68e5cb24e483f44f482a1a15601848b9b6f199dacb970098f77/jiter-0.12.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb12a2223fe0135c7ff1356a143d57f95bbf1f4a66584f1fc74df21d86b993", size = 380714, upload-time = "2025-11-09T20:48:40.014Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/4808a88338ad2c228b1126b93fcd8ba145e919e886fe910d578230dabe3b/jiter-0.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c596cc0f4cb574877550ce4ecd51f8037469146addd676d7c1a30ebe6391923f", size = 365168, upload-time = "2025-11-09T20:48:41.462Z" }, + { url = "https://files.pythonhosted.org/packages/0c/d4/04619a9e8095b42aef436b5aeb4c0282b4ff1b27d1db1508df9f5dc82750/jiter-0.12.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ab4c823b216a4aeab3fdbf579c5843165756bd9ad87cc6b1c65919c4715f783", size = 387893, upload-time = "2025-11-09T20:48:42.921Z" }, + { url = "https://files.pythonhosted.org/packages/17/ea/d3c7e62e4546fdc39197fa4a4315a563a89b95b6d54c0d25373842a59cbe/jiter-0.12.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e427eee51149edf962203ff8db75a7514ab89be5cb623fb9cea1f20b54f1107b", size = 520828, upload-time = "2025-11-09T20:48:44.278Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0b/c6d3562a03fd767e31cb119d9041ea7958c3c80cb3d753eafb19b3b18349/jiter-0.12.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:edb868841f84c111255ba5e80339d386d937ec1fdce419518ce1bd9370fac5b6", size = 511009, upload-time = "2025-11-09T20:48:45.726Z" }, + { url = "https://files.pythonhosted.org/packages/aa/51/2cb4468b3448a8385ebcd15059d325c9ce67df4e2758d133ab9442b19834/jiter-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8bbcfe2791dfdb7c5e48baf646d37a6a3dcb5a97a032017741dea9f817dca183", size = 205110, upload-time = "2025-11-09T20:48:47.033Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c5/ae5ec83dec9c2d1af805fd5fe8f74ebded9c8670c5210ec7820ce0dbeb1e/jiter-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2fa940963bf02e1d8226027ef461e36af472dea85d36054ff835aeed944dd873", size = 205223, upload-time = "2025-11-09T20:48:49.076Z" }, + { url = "https://files.pythonhosted.org/packages/97/9a/3c5391907277f0e55195550cf3fa8e293ae9ee0c00fb402fec1e38c0c82f/jiter-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:506c9708dd29b27288f9f8f1140c3cb0e3d8ddb045956d7757b1fa0e0f39a473", size = 185564, upload-time = "2025-11-09T20:48:50.376Z" }, +] + +[[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 = "langchain" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/12/3a74c22abdfddd877dfc2ee666d516f9132877fcd25eb4dd694835c59c79/langchain-1.2.0.tar.gz", hash = "sha256:a087d1e2b2969819e29a91a6d5f98302aafe31bd49ba377ecee3bf5a5dcfe14a", size = 536126, upload-time = "2025-12-15T14:51:42.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/00/4e3fa0d90f5a5c376ccb8ca983d0f0f7287783dfac48702e18f01d24673b/langchain-1.2.0-py3-none-any.whl", hash = "sha256:82f0d17aa4fbb11560b30e1e7d4aeb75e3ad71ce09b85c90ab208b181a24ffac", size = 102828, upload-time = "2025-12-15T14:51:40.802Z" }, +] + +[[package]] +name = "langchain-core" +version = "1.2.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpatch" }, + { name = "langsmith" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "uuid-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/86/bd678d69341ae4178bc8dfa04024d63636e5d580ff03d4502c8bc2262917/langchain_core-1.2.5.tar.gz", hash = "sha256:d674f6df42f07e846859b9d3afe547cad333d6bf9763e92c88eb4f8aaedcd3cc", size = 820445, upload-time = "2025-12-22T23:45:32.041Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/bd/9df897cbc98290bf71140104ee5b9777cf5291afb80333aa7da5a497339b/langchain_core-1.2.5-py3-none-any.whl", hash = "sha256:3255944ef4e21b2551facb319bfc426057a40247c0a05de5bd6f2fc021fbfa34", size = 484851, upload-time = "2025-12-22T23:45:30.525Z" }, +] + +[[package]] +name = "langchain-openai" +version = "1.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "openai" }, + { name = "tiktoken" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/67/228dc28b4498ea16422577013b5bb4ba35a1b99f8be975d6747c7a9f7e6a/langchain_openai-1.1.6.tar.gz", hash = "sha256:e306612654330ae36fb6bbe36db91c98534312afade19e140c3061fe4208dac8", size = 1038310, upload-time = "2025-12-18T17:58:52.84Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/5b/1f6521df83c1a8e8d3f52351883b59683e179c0aa1bec75d0a77a394c9e7/langchain_openai-1.1.6-py3-none-any.whl", hash = "sha256:c42d04a67a85cee1d994afe400800d2b09ebf714721345f0b651eb06a02c3948", size = 84701, upload-time = "2025-12-18T17:58:51.527Z" }, +] + +[[package]] +name = "langfuse" +version = "2.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "backoff" }, + { name = "httpx" }, + { name = "idna" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/09/98b6245b833beaf797cfc7ba97917dcc19f34209b8ff56a55a43a458420e/langfuse-2.33.0.tar.gz", hash = "sha256:3ca2ef8539a8f28cb80135f4b46b80d5585ce183f8e2035f318be296d09d7d88", size = 87438, upload-time = "2024-05-21T15:55:18.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/9e/112aa6b3a246cfe14d92323de7f3d59fb8b4cf7d8f1e1eebfa3d0e07e35f/langfuse-2.33.0-py3-none-any.whl", hash = "sha256:362e3078c5a891df0b7ba3c9ce82f046d1f0274eab3d55337e443fff526f18ad", size = 162440, upload-time = "2024-05-21T15:55:14.894Z" }, +] + +[[package]] +name = "langgraph" +version = "1.0.5" +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/7d/47/28f4d4d33d88f69de26f7a54065961ac0c662cec2479b36a2db081ef5cb6/langgraph-1.0.5.tar.gz", hash = "sha256:7f6ae59622386b60fe9fa0ad4c53f42016b668455ed604329e7dc7904adbf3f8", size = 493969, upload-time = "2025-12-12T23:05:48.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/1b/e318ee76e42d28f515d87356ac5bd7a7acc8bad3b8f54ee377bef62e1cbf/langgraph-1.0.5-py3-none-any.whl", hash = "sha256:b4cfd173dca3c389735b47228ad8b295e6f7b3df779aba3a1e0c23871f81281e", size = 157056, upload-time = "2025-12-12T23:05:46.499Z" }, +] + +[[package]] +name = "langgraph-checkpoint" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "ormsgpack" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/07/2b1c042fa87d40cf2db5ca27dc4e8dd86f9a0436a10aa4361a8982718ae7/langgraph_checkpoint-3.0.1.tar.gz", hash = "sha256:59222f875f85186a22c494aedc65c4e985a3df27e696e5016ba0b98a5ed2cee0", size = 137785, upload-time = "2025-11-04T21:55:47.774Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl", hash = "sha256:9b04a8d0edc0474ce4eaf30c5d731cee38f11ddff50a6177eead95b5c4e4220b", size = 46249, upload-time = "2025-11-04T21:55:46.472Z" }, +] + +[[package]] +name = "langgraph-prebuilt" +version = "1.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/f9/54f8891b32159e4542236817aea2ee83de0de18bce28e9bdba08c7f93001/langgraph_prebuilt-1.0.5.tar.gz", hash = "sha256:85802675ad778cc7240fd02d47db1e0b59c0c86d8369447d77ce47623845db2d", size = 144453, upload-time = "2025-11-20T16:47:39.23Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/5e/aeba4a5b39fe6e874e0dd003a82da71c7153e671312671a8dacc5cb7c1af/langgraph_prebuilt-1.0.5-py3-none-any.whl", hash = "sha256:22369563e1848862ace53fbc11b027c28dd04a9ac39314633bb95f2a7e258496", size = 35072, upload-time = "2025-11-20T16:47:38.187Z" }, +] + +[[package]] +name = "langgraph-sdk" +version = "0.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/d3/b6be0b0aba2a53a8920a2b0b4328a83121ec03eea9952e576d06a4182f6f/langgraph_sdk-0.3.1.tar.gz", hash = "sha256:f6dadfd2444eeff3e01405a9005c95fb3a028d4bd954ebec80ea6150084f92bb", size = 130312, upload-time = "2025-12-18T22:11:47.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/fe/0c1c9c01a154eba62b20b02fabe811fd94a2b810061ae9e4d8462b8cf85a/langgraph_sdk-0.3.1-py3-none-any.whl", hash = "sha256:0b856923bfd20bf3441ce9d03bef488aa333fb610e972618799a9d584436acad", size = 66517, upload-time = "2025-12-18T22:11:46.625Z" }, +] + +[[package]] +name = "langsmith" +version = "0.5.1" +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 = "uuid-utils" }, + { name = "zstandard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/92/967ba83ec40448f46e23f231731b1564207af5ffba32aecef4e1f2f9f83f/langsmith-0.5.1.tar.gz", hash = "sha256:6a10b38cb4ce58941b7f1dbdf41a461868605dd0162bf05d17690f2e4b6e50e7", size = 871631, upload-time = "2025-12-24T19:50:24.823Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/67/1720b01e58d3487a44c780a86aabad95d9eaaf6b2fa8d0718c98f0eca18d/langsmith-0.5.1-py3-none-any.whl", hash = "sha256:70aa2a4c75add3f723c3bbac80dbb8adc575077834d3a733ee1ec133206ff351", size = 275527, upload-time = "2025-12-24T19:50:22.808Z" }, +] + +[[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 = "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/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 = "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 = "msal" +version = "1.34.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cf/0e/c857c46d653e104019a84f22d4494f2119b4fe9f896c92b4b864b3b045cc/msal-1.34.0.tar.gz", hash = "sha256:76ba83b716ea5a6d75b0279c0ac353a0e05b820ca1f6682c0eb7f45190c43c2f", size = 153961, upload-time = "2025-09-22T23:05:48.989Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/dc/18d48843499e278538890dc709e9ee3dea8375f8be8e82682851df1b48b5/msal-1.34.0-py3-none-any.whl", hash = "sha256:f669b1644e4950115da7a176441b0e13ec2975c29528d8b9e81316023676d6e1", size = 116987, upload-time = "2025-09-22T23:05:47.294Z" }, +] + +[[package]] +name = "msal-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "msal" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/99/5d239b6156eddf761a636bded1118414d161bd6b7b37a9335549ed159396/msal_extensions-1.3.1.tar.gz", hash = "sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4", size = 23315, upload-time = "2025-03-14T23:51:03.902Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/75/bd9b7bb966668920f06b200e84454c8f3566b102183bc55c5473d96cb2b9/msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca", size = 20583, upload-time = "2025-03-14T23:51:03.016Z" }, +] + +[[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/d2/86/33272a544eeb36d66e4d9a920602d1a2f57d4ebea4ef3cdfe5a912574c95/multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6", size = 76135, upload-time = "2025-10-06T14:49:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/1c/eb97db117a1ebe46d457a3d235a7b9d2e6dcab174f42d1b67663dd9e5371/multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159", size = 45117, upload-time = "2025-10-06T14:49:55.82Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d8/6c3442322e41fb1dd4de8bd67bfd11cd72352ac131f6368315617de752f1/multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca", size = 43472, upload-time = "2025-10-06T14:49:57.048Z" }, + { url = "https://files.pythonhosted.org/packages/75/3f/e2639e80325af0b6c6febdf8e57cc07043ff15f57fa1ef808f4ccb5ac4cd/multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8", size = 249342, upload-time = "2025-10-06T14:49:58.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cc/84e0585f805cbeaa9cbdaa95f9a3d6aed745b9d25700623ac89a6ecff400/multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60", size = 257082, upload-time = "2025-10-06T14:49:59.89Z" }, + { url = "https://files.pythonhosted.org/packages/b0/9c/ac851c107c92289acbbf5cfb485694084690c1b17e555f44952c26ddc5bd/multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4", size = 240704, upload-time = "2025-10-06T14:50:01.485Z" }, + { url = "https://files.pythonhosted.org/packages/50/cc/5f93e99427248c09da95b62d64b25748a5f5c98c7c2ab09825a1d6af0e15/multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f", size = 266355, upload-time = "2025-10-06T14:50:02.955Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0c/2ec1d883ceb79c6f7f6d7ad90c919c898f5d1c6ea96d322751420211e072/multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf", size = 267259, upload-time = "2025-10-06T14:50:04.446Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2d/f0b184fa88d6630aa267680bdb8623fb69cb0d024b8c6f0d23f9a0f406d3/multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32", size = 254903, upload-time = "2025-10-06T14:50:05.98Z" }, + { url = "https://files.pythonhosted.org/packages/06/c9/11ea263ad0df7dfabcad404feb3c0dd40b131bc7f232d5537f2fb1356951/multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036", size = 252365, upload-time = "2025-10-06T14:50:07.511Z" }, + { url = "https://files.pythonhosted.org/packages/41/88/d714b86ee2c17d6e09850c70c9d310abac3d808ab49dfa16b43aba9d53fd/multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec", size = 250062, upload-time = "2025-10-06T14:50:09.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/fe/ad407bb9e818c2b31383f6131ca19ea7e35ce93cf1310fce69f12e89de75/multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e", size = 249683, upload-time = "2025-10-06T14:50:10.714Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/a89abdb0229e533fb925e7c6e5c40201c2873efebc9abaf14046a4536ee6/multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64", size = 261254, upload-time = "2025-10-06T14:50:12.28Z" }, + { url = "https://files.pythonhosted.org/packages/8d/aa/0e2b27bd88b40a4fb8dc53dd74eecac70edaa4c1dd0707eb2164da3675b3/multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd", size = 257967, upload-time = "2025-10-06T14:50:14.16Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8e/0c67b7120d5d5f6d874ed85a085f9dc770a7f9d8813e80f44a9fec820bb7/multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288", size = 250085, upload-time = "2025-10-06T14:50:15.639Z" }, + { url = "https://files.pythonhosted.org/packages/ba/55/b73e1d624ea4b8fd4dd07a3bb70f6e4c7c6c5d9d640a41c6ffe5cdbd2a55/multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17", size = 41713, upload-time = "2025-10-06T14:50:17.066Z" }, + { url = "https://files.pythonhosted.org/packages/32/31/75c59e7d3b4205075b4c183fa4ca398a2daf2303ddf616b04ae6ef55cffe/multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390", size = 45915, upload-time = "2025-10-06T14:50:18.264Z" }, + { url = "https://files.pythonhosted.org/packages/31/2a/8987831e811f1184c22bc2e45844934385363ee61c0a2dcfa8f71b87e608/multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e", size = 43077, upload-time = "2025-10-06T14:50:19.853Z" }, + { url = "https://files.pythonhosted.org/packages/e8/68/7b3a5170a382a340147337b300b9eb25a9ddb573bcdfff19c0fa3f31ffba/multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00", size = 83114, upload-time = "2025-10-06T14:50:21.223Z" }, + { url = "https://files.pythonhosted.org/packages/55/5c/3fa2d07c84df4e302060f555bbf539310980362236ad49f50eeb0a1c1eb9/multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb", size = 48442, upload-time = "2025-10-06T14:50:22.871Z" }, + { url = "https://files.pythonhosted.org/packages/fc/56/67212d33239797f9bd91962bb899d72bb0f4c35a8652dcdb8ed049bef878/multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b", size = 46885, upload-time = "2025-10-06T14:50:24.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/d1/908f896224290350721597a61a69cd19b89ad8ee0ae1f38b3f5cd12ea2ac/multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c", size = 242588, upload-time = "2025-10-06T14:50:25.716Z" }, + { url = "https://files.pythonhosted.org/packages/ab/67/8604288bbd68680eee0ab568fdcb56171d8b23a01bcd5cb0c8fedf6e5d99/multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1", size = 249966, upload-time = "2025-10-06T14:50:28.192Z" }, + { url = "https://files.pythonhosted.org/packages/20/33/9228d76339f1ba51e3efef7da3ebd91964d3006217aae13211653193c3ff/multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b", size = 228618, upload-time = "2025-10-06T14:50:29.82Z" }, + { url = "https://files.pythonhosted.org/packages/f8/2d/25d9b566d10cab1c42b3b9e5b11ef79c9111eaf4463b8c257a3bd89e0ead/multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5", size = 257539, upload-time = "2025-10-06T14:50:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b1/8d1a965e6637fc33de3c0d8f414485c2b7e4af00f42cab3d84e7b955c222/multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad", size = 256345, upload-time = "2025-10-06T14:50:33.26Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/06b5a8adbdeedada6f4fb8d8f193d44a347223b11939b42953eeb6530b6b/multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c", size = 247934, upload-time = "2025-10-06T14:50:34.808Z" }, + { url = "https://files.pythonhosted.org/packages/8f/31/b2491b5fe167ca044c6eb4b8f2c9f3b8a00b24c432c365358eadac5d7625/multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5", size = 245243, upload-time = "2025-10-06T14:50:36.436Z" }, + { url = "https://files.pythonhosted.org/packages/61/1a/982913957cb90406c8c94f53001abd9eafc271cb3e70ff6371590bec478e/multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10", size = 235878, upload-time = "2025-10-06T14:50:37.953Z" }, + { url = "https://files.pythonhosted.org/packages/be/c0/21435d804c1a1cf7a2608593f4d19bca5bcbd7a81a70b253fdd1c12af9c0/multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754", size = 243452, upload-time = "2025-10-06T14:50:39.574Z" }, + { url = "https://files.pythonhosted.org/packages/54/0a/4349d540d4a883863191be6eb9a928846d4ec0ea007d3dcd36323bb058ac/multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c", size = 252312, upload-time = "2025-10-06T14:50:41.612Z" }, + { url = "https://files.pythonhosted.org/packages/26/64/d5416038dbda1488daf16b676e4dbfd9674dde10a0cc8f4fc2b502d8125d/multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762", size = 246935, upload-time = "2025-10-06T14:50:43.972Z" }, + { url = "https://files.pythonhosted.org/packages/9f/8c/8290c50d14e49f35e0bd4abc25e1bc7711149ca9588ab7d04f886cdf03d9/multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6", size = 243385, upload-time = "2025-10-06T14:50:45.648Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777, upload-time = "2025-10-06T14:50:47.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104, upload-time = "2025-10-06T14:50:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503, upload-time = "2025-10-06T14:50:50.16Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128, upload-time = "2025-10-06T14:50:51.92Z" }, + { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410, upload-time = "2025-10-06T14:50:53.275Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205, upload-time = "2025-10-06T14:50:54.911Z" }, + { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084, upload-time = "2025-10-06T14:50:56.369Z" }, + { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667, upload-time = "2025-10-06T14:50:57.991Z" }, + { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590, upload-time = "2025-10-06T14:50:59.589Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112, upload-time = "2025-10-06T14:51:01.183Z" }, + { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194, upload-time = "2025-10-06T14:51:02.794Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510, upload-time = "2025-10-06T14:51:04.724Z" }, + { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395, upload-time = "2025-10-06T14:51:06.306Z" }, + { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520, upload-time = "2025-10-06T14:51:08.091Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479, upload-time = "2025-10-06T14:51:10.365Z" }, + { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903, upload-time = "2025-10-06T14:51:12.466Z" }, + { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333, upload-time = "2025-10-06T14:51:14.48Z" }, + { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411, upload-time = "2025-10-06T14:51:16.072Z" }, + { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940, upload-time = "2025-10-06T14:51:17.544Z" }, + { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087, upload-time = "2025-10-06T14:51:18.875Z" }, + { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368, upload-time = "2025-10-06T14:51:20.225Z" }, + { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326, upload-time = "2025-10-06T14:51:21.588Z" }, + { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065, upload-time = "2025-10-06T14:51:22.93Z" }, + { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475, upload-time = "2025-10-06T14:51:24.352Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324, upload-time = "2025-10-06T14:51:25.822Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877, upload-time = "2025-10-06T14:51:27.604Z" }, + { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824, upload-time = "2025-10-06T14:51:29.664Z" }, + { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558, upload-time = "2025-10-06T14:51:31.684Z" }, + { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339, upload-time = "2025-10-06T14:51:33.699Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895, upload-time = "2025-10-06T14:51:36.189Z" }, + { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862, upload-time = "2025-10-06T14:51:41.291Z" }, + { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376, upload-time = "2025-10-06T14:51:43.55Z" }, + { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272, upload-time = "2025-10-06T14:51:45.265Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774, upload-time = "2025-10-06T14:51:46.836Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731, upload-time = "2025-10-06T14:51:48.541Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193, upload-time = "2025-10-06T14:51:50.355Z" }, + { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023, upload-time = "2025-10-06T14:51:51.883Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507, upload-time = "2025-10-06T14:51:53.672Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804, upload-time = "2025-10-06T14:51:55.415Z" }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a4/7a/6a3d14e205d292b738db449d0de649b373a59edb0d0b4493821d0a3e8718/numpy-2.4.0.tar.gz", hash = "sha256:6e504f7b16118198f138ef31ba24d985b124c2c469fe8467007cf30fd992f934", size = 20685720, upload-time = "2025-12-20T16:18:19.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/0d/853fd96372eda07c824d24adf02e8bc92bb3731b43a9b2a39161c3667cc4/numpy-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a152d86a3ae00ba5f47b3acf3b827509fd0b6cb7d3259665e63dafbad22a75ea", size = 16649088, upload-time = "2025-12-20T16:16:31.421Z" }, + { url = "https://files.pythonhosted.org/packages/e3/37/cc636f1f2a9f585434e20a3e6e63422f70bfe4f7f6698e941db52ea1ac9a/numpy-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:39b19251dec4de8ff8496cd0806cbe27bf0684f765abb1f4809554de93785f2d", size = 12364065, upload-time = "2025-12-20T16:16:33.491Z" }, + { url = "https://files.pythonhosted.org/packages/ed/69/0b78f37ca3690969beee54103ce5f6021709134e8020767e93ba691a72f1/numpy-2.4.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:009bd0ea12d3c784b6639a8457537016ce5172109e585338e11334f6a7bb88ee", size = 5192640, upload-time = "2025-12-20T16:16:35.636Z" }, + { url = "https://files.pythonhosted.org/packages/1d/2a/08569f8252abf590294dbb09a430543ec8f8cc710383abfb3e75cc73aeda/numpy-2.4.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5fe44e277225fd3dff6882d86d3d447205d43532c3627313d17e754fb3905a0e", size = 6541556, upload-time = "2025-12-20T16:16:37.276Z" }, + { url = "https://files.pythonhosted.org/packages/93/e9/a949885a4e177493d61519377952186b6cbfdf1d6002764c664ba28349b5/numpy-2.4.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f935c4493eda9069851058fa0d9e39dbf6286be690066509305e52912714dbb2", size = 14396562, upload-time = "2025-12-20T16:16:38.953Z" }, + { url = "https://files.pythonhosted.org/packages/99/98/9d4ad53b0e9ef901c2ef1d550d2136f5ac42d3fd2988390a6def32e23e48/numpy-2.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cfa5f29a695cb7438965e6c3e8d06e0416060cf0d709c1b1c1653a939bf5c2a", size = 16351719, upload-time = "2025-12-20T16:16:41.503Z" }, + { url = "https://files.pythonhosted.org/packages/28/de/5f3711a38341d6e8dd619f6353251a0cdd07f3d6d101a8fd46f4ef87f895/numpy-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba0cb30acd3ef11c94dc27fbfba68940652492bc107075e7ffe23057f9425681", size = 16176053, upload-time = "2025-12-20T16:16:44.552Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5b/2a3753dc43916501b4183532e7ace862e13211042bceafa253afb5c71272/numpy-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:60e8c196cd82cbbd4f130b5290007e13e6de3eca79f0d4d38014769d96a7c475", size = 18277859, upload-time = "2025-12-20T16:16:47.174Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c5/a18bcdd07a941db3076ef489d036ab16d2bfc2eae0cf27e5a26e29189434/numpy-2.4.0-cp313-cp313-win32.whl", hash = "sha256:5f48cb3e88fbc294dc90e215d86fbaf1c852c63dbdb6c3a3e63f45c4b57f7344", size = 5953849, upload-time = "2025-12-20T16:16:49.554Z" }, + { url = "https://files.pythonhosted.org/packages/4f/f1/719010ff8061da6e8a26e1980cf090412d4f5f8060b31f0c45d77dd67a01/numpy-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:a899699294f28f7be8992853c0c60741f16ff199205e2e6cdca155762cbaa59d", size = 12302840, upload-time = "2025-12-20T16:16:51.227Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5a/b3d259083ed8b4d335270c76966cb6cf14a5d1b69e1a608994ac57a659e6/numpy-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:9198f447e1dc5647d07c9a6bbe2063cc0132728cc7175b39dbc796da5b54920d", size = 10308509, upload-time = "2025-12-20T16:16:53.313Z" }, + { url = "https://files.pythonhosted.org/packages/31/01/95edcffd1bb6c0633df4e808130545c4f07383ab629ac7e316fb44fff677/numpy-2.4.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74623f2ab5cc3f7c886add4f735d1031a1d2be4a4ae63c0546cfd74e7a31ddf6", size = 12491815, upload-time = "2025-12-20T16:16:55.496Z" }, + { url = "https://files.pythonhosted.org/packages/59/ea/5644b8baa92cc1c7163b4b4458c8679852733fa74ca49c942cfa82ded4e0/numpy-2.4.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:0804a8e4ab070d1d35496e65ffd3cf8114c136a2b81f61dfab0de4b218aacfd5", size = 5320321, upload-time = "2025-12-20T16:16:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/26/4e/e10938106d70bc21319bd6a86ae726da37edc802ce35a3a71ecdf1fdfe7f/numpy-2.4.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:02a2038eb27f9443a8b266a66911e926566b5a6ffd1a689b588f7f35b81e7dc3", size = 6641635, upload-time = "2025-12-20T16:16:59.379Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8d/a8828e3eaf5c0b4ab116924df82f24ce3416fa38d0674d8f708ddc6c8aac/numpy-2.4.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1889b3a3f47a7b5bee16bc25a2145bd7cb91897f815ce3499db64c7458b6d91d", size = 14456053, upload-time = "2025-12-20T16:17:01.768Z" }, + { url = "https://files.pythonhosted.org/packages/68/a1/17d97609d87d4520aa5ae2dcfb32305654550ac6a35effb946d303e594ce/numpy-2.4.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85eef4cb5625c47ee6425c58a3502555e10f45ee973da878ac8248ad58c136f3", size = 16401702, upload-time = "2025-12-20T16:17:04.235Z" }, + { url = "https://files.pythonhosted.org/packages/18/32/0f13c1b2d22bea1118356b8b963195446f3af124ed7a5adfa8fdecb1b6ca/numpy-2.4.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6dc8b7e2f4eb184b37655195f421836cfae6f58197b67e3ffc501f1333d993fa", size = 16242493, upload-time = "2025-12-20T16:17:06.856Z" }, + { url = "https://files.pythonhosted.org/packages/ae/23/48f21e3d309fbc137c068a1475358cbd3a901b3987dcfc97a029ab3068e2/numpy-2.4.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:44aba2f0cafd287871a495fb3163408b0bd25bbce135c6f621534a07f4f7875c", size = 18324222, upload-time = "2025-12-20T16:17:09.392Z" }, + { url = "https://files.pythonhosted.org/packages/ac/52/41f3d71296a3dcaa4f456aaa3c6fc8e745b43d0552b6bde56571bb4b4a0f/numpy-2.4.0-cp313-cp313t-win32.whl", hash = "sha256:20c115517513831860c573996e395707aa9fb691eb179200125c250e895fcd93", size = 6076216, upload-time = "2025-12-20T16:17:11.437Z" }, + { url = "https://files.pythonhosted.org/packages/35/ff/46fbfe60ab0710d2a2b16995f708750307d30eccbb4c38371ea9e986866e/numpy-2.4.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b48e35f4ab6f6a7597c46e301126ceba4c44cd3280e3750f85db48b082624fa4", size = 12444263, upload-time = "2025-12-20T16:17:13.182Z" }, + { url = "https://files.pythonhosted.org/packages/a3/e3/9189ab319c01d2ed556c932ccf55064c5d75bb5850d1df7a482ce0badead/numpy-2.4.0-cp313-cp313t-win_arm64.whl", hash = "sha256:4d1cfce39e511069b11e67cd0bd78ceff31443b7c9e5c04db73c7a19f572967c", size = 10378265, upload-time = "2025-12-20T16:17:15.211Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ed/52eac27de39d5e5a6c9aadabe672bc06f55e24a3d9010cd1183948055d76/numpy-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c95eb6db2884917d86cde0b4d4cf31adf485c8ec36bf8696dd66fa70de96f36b", size = 16647476, upload-time = "2025-12-20T16:17:17.671Z" }, + { url = "https://files.pythonhosted.org/packages/77/c0/990ce1b7fcd4e09aeaa574e2a0a839589e4b08b2ca68070f1acb1fea6736/numpy-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:65167da969cd1ec3a1df31cb221ca3a19a8aaa25370ecb17d428415e93c1935e", size = 12374563, upload-time = "2025-12-20T16:17:20.216Z" }, + { url = "https://files.pythonhosted.org/packages/37/7c/8c5e389c6ae8f5fd2277a988600d79e9625db3fff011a2d87ac80b881a4c/numpy-2.4.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3de19cfecd1465d0dcf8a5b5ea8b3155b42ed0b639dba4b71e323d74f2a3be5e", size = 5203107, upload-time = "2025-12-20T16:17:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/e6/94/ca5b3bd6a8a70a5eec9a0b8dd7f980c1eff4b8a54970a9a7fef248ef564f/numpy-2.4.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6c05483c3136ac4c91b4e81903cb53a8707d316f488124d0398499a4f8e8ef51", size = 6538067, upload-time = "2025-12-20T16:17:24.001Z" }, + { url = "https://files.pythonhosted.org/packages/79/43/993eb7bb5be6761dde2b3a3a594d689cec83398e3f58f4758010f3b85727/numpy-2.4.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36667db4d6c1cea79c8930ab72fadfb4060feb4bfe724141cd4bd064d2e5f8ce", size = 14411926, upload-time = "2025-12-20T16:17:25.822Z" }, + { url = "https://files.pythonhosted.org/packages/03/75/d4c43b61de473912496317a854dac54f1efec3eeb158438da6884b70bb90/numpy-2.4.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9a818668b674047fd88c4cddada7ab8f1c298812783e8328e956b78dc4807f9f", size = 16354295, upload-time = "2025-12-20T16:17:28.308Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0a/b54615b47ee8736a6461a4bb6749128dd3435c5a759d5663f11f0e9af4ac/numpy-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1ee32359fb7543b7b7bd0b2f46294db27e29e7bbdf70541e81b190836cd83ded", size = 16190242, upload-time = "2025-12-20T16:17:30.993Z" }, + { url = "https://files.pythonhosted.org/packages/98/ce/ea207769aacad6246525ec6c6bbd66a2bf56c72443dc10e2f90feed29290/numpy-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e493962256a38f58283de033d8af176c5c91c084ea30f15834f7545451c42059", size = 18280875, upload-time = "2025-12-20T16:17:33.327Z" }, + { url = "https://files.pythonhosted.org/packages/17/ef/ec409437aa962ea372ed601c519a2b141701683ff028f894b7466f0ab42b/numpy-2.4.0-cp314-cp314-win32.whl", hash = "sha256:6bbaebf0d11567fa8926215ae731e1d58e6ec28a8a25235b8a47405d301332db", size = 6002530, upload-time = "2025-12-20T16:17:35.729Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4a/5cb94c787a3ed1ac65e1271b968686521169a7b3ec0b6544bb3ca32960b0/numpy-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:3d857f55e7fdf7c38ab96c4558c95b97d1c685be6b05c249f5fdafcbd6f9899e", size = 12435890, upload-time = "2025-12-20T16:17:37.599Z" }, + { url = "https://files.pythonhosted.org/packages/48/a0/04b89db963af9de1104975e2544f30de89adbf75b9e75f7dd2599be12c79/numpy-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:bb50ce5fb202a26fd5404620e7ef820ad1ab3558b444cb0b55beb7ef66cd2d63", size = 10591892, upload-time = "2025-12-20T16:17:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/53/e5/d74b5ccf6712c06c7a545025a6a71bfa03bdc7e0568b405b0d655232fd92/numpy-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:355354388cba60f2132df297e2d53053d4063f79077b67b481d21276d61fc4df", size = 12494312, upload-time = "2025-12-20T16:17:41.714Z" }, + { url = "https://files.pythonhosted.org/packages/c2/08/3ca9cc2ddf54dfee7ae9a6479c071092a228c68aef08252aa08dac2af002/numpy-2.4.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:1d8f9fde5f6dc1b6fc34df8162f3b3079365468703fee7f31d4e0cc8c63baed9", size = 5322862, upload-time = "2025-12-20T16:17:44.145Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/0bb63a68394c0c1e52670cfff2e309afa41edbe11b3327d9af29e4383f34/numpy-2.4.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e0434aa22c821f44eeb4c650b81c7fbdd8c0122c6c4b5a576a76d5a35625ecd9", size = 6644986, upload-time = "2025-12-20T16:17:46.203Z" }, + { url = "https://files.pythonhosted.org/packages/06/8f/9264d9bdbcf8236af2823623fe2f3981d740fc3461e2787e231d97c38c28/numpy-2.4.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40483b2f2d3ba7aad426443767ff5632ec3156ef09742b96913787d13c336471", size = 14457958, upload-time = "2025-12-20T16:17:48.017Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d9/f9a69ae564bbc7236a35aa883319364ef5fd41f72aa320cc1cbe66148fe2/numpy-2.4.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6a7664ddd9746e20b7325351fe1a8408d0a2bf9c63b5e898290ddc8f09544", size = 16398394, upload-time = "2025-12-20T16:17:50.409Z" }, + { url = "https://files.pythonhosted.org/packages/34/c7/39241501408dde7f885d241a98caba5421061a2c6d2b2197ac5e3aa842d8/numpy-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ecb0019d44f4cdb50b676c5d0cb4b1eae8e15d1ed3d3e6639f986fc92b2ec52c", size = 16241044, upload-time = "2025-12-20T16:17:52.661Z" }, + { url = "https://files.pythonhosted.org/packages/7c/95/cae7effd90e065a95e59fe710eeee05d7328ed169776dfdd9f789e032125/numpy-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d0ffd9e2e4441c96a9c91ec1783285d80bf835b677853fc2770a89d50c1e48ac", size = 18321772, upload-time = "2025-12-20T16:17:54.947Z" }, + { url = "https://files.pythonhosted.org/packages/96/df/3c6c279accd2bfb968a76298e5b276310bd55d243df4fa8ac5816d79347d/numpy-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:77f0d13fa87036d7553bf81f0e1fe3ce68d14c9976c9851744e4d3e91127e95f", size = 6148320, upload-time = "2025-12-20T16:17:57.249Z" }, + { url = "https://files.pythonhosted.org/packages/92/8d/f23033cce252e7a75cae853d17f582e86534c46404dea1c8ee094a9d6d84/numpy-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b1f5b45829ac1848893f0ddf5cb326110604d6df96cdc255b0bf9edd154104d4", size = 12623460, upload-time = "2025-12-20T16:17:58.963Z" }, + { url = "https://files.pythonhosted.org/packages/a4/4f/1f8475907d1a7c4ef9020edf7f39ea2422ec896849245f00688e4b268a71/numpy-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:23a3e9d1a6f360267e8fbb38ba5db355a6a7e9be71d7fce7ab3125e88bb646c8", size = 10661799, upload-time = "2025-12-20T16:18:01.078Z" }, +] + +[[package]] +name = "openai" +version = "2.14.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/d8/b1/12fe1c196bea326261718eb037307c1c1fe1dedc2d2d4de777df822e6238/openai-2.14.0.tar.gz", hash = "sha256:419357bedde9402d23bf8f2ee372fca1985a73348debba94bddff06f19459952", size = 626938, upload-time = "2025-12-19T03:28:45.742Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/4b/7c1a00c2c3fbd004253937f7520f692a9650767aa73894d7a34f0d65d3f4/openai-2.14.0-py3-none-any.whl", hash = "sha256:7ea40aca4ffc4c4a776e77679021b47eec1160e341f42ae086ba949c9dcc9183", size = 1067558, upload-time = "2025-12-19T03:28:43.727Z" }, +] + +[[package]] +name = "orjson" +version = "3.11.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/43/61a77040ce59f1569edf38f0b9faadc90c8cf7e9bec2e0df51d0132c6bb7/orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629", size = 245271, upload-time = "2025-12-06T15:54:40.878Z" }, + { url = "https://files.pythonhosted.org/packages/55/f9/0f79be617388227866d50edd2fd320cb8fb94dc1501184bb1620981a0aba/orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3", size = 129422, upload-time = "2025-12-06T15:54:42.403Z" }, + { url = "https://files.pythonhosted.org/packages/77/42/f1bf1549b432d4a78bfa95735b79b5dac75b65b5bb815bba86ad406ead0a/orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39", size = 132060, upload-time = "2025-12-06T15:54:43.531Z" }, + { url = "https://files.pythonhosted.org/packages/25/49/825aa6b929f1a6ed244c78acd7b22c1481fd7e5fda047dc8bf4c1a807eb6/orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f", size = 130391, upload-time = "2025-12-06T15:54:45.059Z" }, + { url = "https://files.pythonhosted.org/packages/42/ec/de55391858b49e16e1aa8f0bbbb7e5997b7345d8e984a2dec3746d13065b/orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51", size = 135964, upload-time = "2025-12-06T15:54:46.576Z" }, + { url = "https://files.pythonhosted.org/packages/1c/40/820bc63121d2d28818556a2d0a09384a9f0262407cf9fa305e091a8048df/orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8", size = 139817, upload-time = "2025-12-06T15:54:48.084Z" }, + { url = "https://files.pythonhosted.org/packages/09/c7/3a445ca9a84a0d59d26365fd8898ff52bdfcdcb825bcc6519830371d2364/orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706", size = 137336, upload-time = "2025-12-06T15:54:49.426Z" }, + { url = "https://files.pythonhosted.org/packages/9a/b3/dc0d3771f2e5d1f13368f56b339c6782f955c6a20b50465a91acb79fe961/orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f", size = 138993, upload-time = "2025-12-06T15:54:50.939Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a2/65267e959de6abe23444659b6e19c888f242bf7725ff927e2292776f6b89/orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863", size = 141070, upload-time = "2025-12-06T15:54:52.414Z" }, + { url = "https://files.pythonhosted.org/packages/63/c9/da44a321b288727a322c6ab17e1754195708786a04f4f9d2220a5076a649/orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228", size = 413505, upload-time = "2025-12-06T15:54:53.67Z" }, + { url = "https://files.pythonhosted.org/packages/7f/17/68dc14fa7000eefb3d4d6d7326a190c99bb65e319f02747ef3ebf2452f12/orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2", size = 151342, upload-time = "2025-12-06T15:54:55.113Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c5/ccee774b67225bed630a57478529fc026eda33d94fe4c0eac8fe58d4aa52/orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05", size = 141823, upload-time = "2025-12-06T15:54:56.331Z" }, + { url = "https://files.pythonhosted.org/packages/67/80/5d00e4155d0cd7390ae2087130637671da713959bb558db9bac5e6f6b042/orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef", size = 135236, upload-time = "2025-12-06T15:54:57.507Z" }, + { url = "https://files.pythonhosted.org/packages/95/fe/792cc06a84808dbdc20ac6eab6811c53091b42f8e51ecebf14b540e9cfe4/orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583", size = 133167, upload-time = "2025-12-06T15:54:58.71Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/d158bd8b50e3b1cfdcf406a7e463f6ffe3f0d167b99634717acdaf5e299f/orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287", size = 126712, upload-time = "2025-12-06T15:54:59.892Z" }, + { url = "https://files.pythonhosted.org/packages/c2/60/77d7b839e317ead7bb225d55bb50f7ea75f47afc489c81199befc5435b50/orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0", size = 245252, upload-time = "2025-12-06T15:55:01.127Z" }, + { url = "https://files.pythonhosted.org/packages/f1/aa/d4639163b400f8044cef0fb9aa51b0337be0da3a27187a20d1166e742370/orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81", size = 129419, upload-time = "2025-12-06T15:55:02.723Z" }, + { url = "https://files.pythonhosted.org/packages/30/94/9eabf94f2e11c671111139edf5ec410d2f21e6feee717804f7e8872d883f/orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f", size = 132050, upload-time = "2025-12-06T15:55:03.918Z" }, + { url = "https://files.pythonhosted.org/packages/3d/c8/ca10f5c5322f341ea9a9f1097e140be17a88f88d1cfdd29df522970d9744/orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e", size = 130370, upload-time = "2025-12-06T15:55:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/25/d4/e96824476d361ee2edd5c6290ceb8d7edf88d81148a6ce172fc00278ca7f/orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7", size = 136012, upload-time = "2025-12-06T15:55:06.402Z" }, + { url = "https://files.pythonhosted.org/packages/85/8e/9bc3423308c425c588903f2d103cfcfe2539e07a25d6522900645a6f257f/orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb", size = 139809, upload-time = "2025-12-06T15:55:07.656Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3c/b404e94e0b02a232b957c54643ce68d0268dacb67ac33ffdee24008c8b27/orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4", size = 137332, upload-time = "2025-12-06T15:55:08.961Z" }, + { url = "https://files.pythonhosted.org/packages/51/30/cc2d69d5ce0ad9b84811cdf4a0cd5362ac27205a921da524ff42f26d65e0/orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad", size = 138983, upload-time = "2025-12-06T15:55:10.595Z" }, + { url = "https://files.pythonhosted.org/packages/0e/87/de3223944a3e297d4707d2fe3b1ffb71437550e165eaf0ca8bbe43ccbcb1/orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829", size = 141069, upload-time = "2025-12-06T15:55:11.832Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/81d5087ae74be33bcae3ff2d80f5ccaa4a8fedc6d39bf65a427a95b8977f/orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac", size = 413491, upload-time = "2025-12-06T15:55:13.314Z" }, + { url = "https://files.pythonhosted.org/packages/d0/6f/f6058c21e2fc1efaf918986dbc2da5cd38044f1a2d4b7b91ad17c4acf786/orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d", size = 151375, upload-time = "2025-12-06T15:55:14.715Z" }, + { url = "https://files.pythonhosted.org/packages/54/92/c6921f17d45e110892899a7a563a925b2273d929959ce2ad89e2525b885b/orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439", size = 141850, upload-time = "2025-12-06T15:55:15.94Z" }, + { url = "https://files.pythonhosted.org/packages/88/86/cdecb0140a05e1a477b81f24739da93b25070ee01ce7f7242f44a6437594/orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499", size = 135278, upload-time = "2025-12-06T15:55:17.202Z" }, + { url = "https://files.pythonhosted.org/packages/e4/97/b638d69b1e947d24f6109216997e38922d54dcdcdb1b11c18d7efd2d3c59/orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310", size = 133170, upload-time = "2025-12-06T15:55:18.468Z" }, + { url = "https://files.pythonhosted.org/packages/8f/dd/f4fff4a6fe601b4f8f3ba3aa6da8ac33d17d124491a3b804c662a70e1636/orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5", size = 126713, upload-time = "2025-12-06T15:55:19.738Z" }, +] + +[[package]] +name = "ormsgpack" +version = "1.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/96/34c40d621996c2f377a18decbd3c59f031dde73c3ba47d1e1e8f29a05aaa/ormsgpack-1.12.1.tar.gz", hash = "sha256:a3877fde1e4f27a39f92681a0aab6385af3a41d0c25375d33590ae20410ea2ac", size = 39476, upload-time = "2025-12-14T07:57:43.248Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/42/f110dfe7cf23a52a82e23eb23d9a6a76ae495447d474686dfa758f3d71d6/ormsgpack-1.12.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9663d6b3ecc917c063d61a99169ce196a80f3852e541ae404206836749459279", size = 376746, upload-time = "2025-12-14T07:57:17.699Z" }, + { url = "https://files.pythonhosted.org/packages/11/76/b386e508a8ae207daec240201a81adb26467bf99b163560724e86bd9ff33/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32e85cfbaf01a94a92520e7fe7851cfcfe21a5698299c28ab86194895f9b9233", size = 202489, upload-time = "2025-12-14T07:57:18.807Z" }, + { url = "https://files.pythonhosted.org/packages/ea/0e/5db7a63f387149024572daa3d9512fe8fb14bf4efa0722d6d491bed280e7/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dabfd2c24b59c7c69870a5ecee480dfae914a42a0c2e7c9d971cf531e2ba471a", size = 210757, upload-time = "2025-12-14T07:57:19.893Z" }, + { url = "https://files.pythonhosted.org/packages/64/79/3a9899e57cb57430bd766fc1b4c9ad410cb2ba6070bc8cf6301e7d385768/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bbf2b64afeded34ccd8e25402e4bca038757913931fa0d693078d75563f6f9", size = 211518, upload-time = "2025-12-14T07:57:20.972Z" }, + { url = "https://files.pythonhosted.org/packages/d7/cd/4f41710ae9fe50d7fcbe476793b3c487746d0e1cc194cc0fee42ff6d989b/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9959a71dde1bd0ced84af17facc06a8afada495a34e9cb1bad8e9b20d4c59cef", size = 386251, upload-time = "2025-12-14T07:57:22.099Z" }, + { url = "https://files.pythonhosted.org/packages/bf/54/ba0c97d6231b1f01daafaa520c8cce1e1b7fceaae6fdc1c763925874a7de/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:e9be0e3b62d758f21f5b20e0e06b3a240ec546c4a327bf771f5825462aa74714", size = 479607, upload-time = "2025-12-14T07:57:23.525Z" }, + { url = "https://files.pythonhosted.org/packages/18/75/19a9a97a462776d525baf41cfb7072734528775f0a3d5fbfab3aa7756b9b/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a29d49ab7fdd77ea787818e60cb4ef491708105b9c4c9b0f919201625eb036b5", size = 388062, upload-time = "2025-12-14T07:57:24.616Z" }, + { url = "https://files.pythonhosted.org/packages/a8/6a/ec26e3f44e9632ecd2f43638b7b37b500eaea5d79cab984ad0b94be14f82/ormsgpack-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:c418390b47a1d367e803f6c187f77e4d67c7ae07ba962e3a4a019001f4b0291a", size = 116195, upload-time = "2025-12-14T07:57:25.626Z" }, + { url = "https://files.pythonhosted.org/packages/7d/64/bfa5f4a34d0f15c6aba1b73e73f7441a66d635bd03249d334a4796b7a924/ormsgpack-1.12.1-cp313-cp313-win_arm64.whl", hash = "sha256:cfa22c91cffc10a7fbd43729baff2de7d9c28cef2509085a704168ae31f02568", size = 109986, upload-time = "2025-12-14T07:57:26.569Z" }, + { url = "https://files.pythonhosted.org/packages/87/0e/78e5697164e3223b9b216c13e99f1acbc1ee9833490d68842b13da8ba883/ormsgpack-1.12.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b93c91efb1a70751a1902a5b43b27bd8fd38e0ca0365cf2cde2716423c15c3a6", size = 376758, upload-time = "2025-12-14T07:57:27.641Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/3a3cbb64703263d7bbaed7effa3ce78cb9add360a60aa7c544d7df28b641/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf0ea0389167b5fa8d2933dd3f33e887ec4ba68f89c25214d7eec4afd746d22", size = 202487, upload-time = "2025-12-14T07:57:29.051Z" }, + { url = "https://files.pythonhosted.org/packages/d7/2c/807ebe2b77995599bbb1dec8c3f450d5d7dddee14ce3e1e71dc60e2e2a74/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4c29af837f35af3375070689e781161e7cf019eb2f7cd641734ae45cd001c0d", size = 210853, upload-time = "2025-12-14T07:57:30.508Z" }, + { url = "https://files.pythonhosted.org/packages/25/57/2cdfc354e3ad8e847628f511f4d238799d90e9e090941e50b9d5ba955ae2/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336fc65aa0fe65896a3dabaae31e332a0a98b4a00ad7b0afde21a7505fd23ff3", size = 211545, upload-time = "2025-12-14T07:57:31.585Z" }, + { url = "https://files.pythonhosted.org/packages/76/1d/c6fda560e4a8ff865b3aec8a86f7c95ab53f4532193a6ae4ab9db35f85aa/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:940f60aabfefe71dd6b82cb33f4ff10b2e7f5fcfa5f103cdb0a23b6aae4c713c", size = 386333, upload-time = "2025-12-14T07:57:32.957Z" }, + { url = "https://files.pythonhosted.org/packages/fc/3e/715081b36fceb8b497c68b87d384e1cc6d9c9c130ce3b435634d3d785b86/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:596ad9e1b6d4c95595c54aaf49b1392609ca68f562ce06f4f74a5bc4053bcda4", size = 479701, upload-time = "2025-12-14T07:57:34.686Z" }, + { url = "https://files.pythonhosted.org/packages/6d/cf/01ad04def42b3970fc1a302c07f4b46339edf62ef9650247097260471f40/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:575210e8fcbc7b0375026ba040a5eef223e9f66a4453d9623fc23282ae09c3c8", size = 388148, upload-time = "2025-12-14T07:57:35.771Z" }, + { url = "https://files.pythonhosted.org/packages/15/91/1fff2fc2b5943c740028f339154e7103c8f2edf1a881d9fbba2ce11c3b1d/ormsgpack-1.12.1-cp314-cp314-win_amd64.whl", hash = "sha256:647daa3718572280893456be44c60aea6690b7f2edc54c55648ee66e8f06550f", size = 116201, upload-time = "2025-12-14T07:57:36.763Z" }, + { url = "https://files.pythonhosted.org/packages/ed/66/142b542aed3f96002c7d1c33507ca6e1e0d0a42b9253ab27ef7ed5793bd9/ormsgpack-1.12.1-cp314-cp314-win_arm64.whl", hash = "sha256:a8b3ab762a6deaf1b6490ab46dda0c51528cf8037e0246c40875c6fe9e37b699", size = 110029, upload-time = "2025-12-14T07:57:37.703Z" }, + { url = "https://files.pythonhosted.org/packages/38/b3/ef4494438c90359e1547eaed3c5ec46e2c431d59a3de2af4e70ebd594c49/ormsgpack-1.12.1-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:12087214e436c1f6c28491949571abea759a63111908c4f7266586d78144d7a8", size = 376777, upload-time = "2025-12-14T07:57:38.795Z" }, + { url = "https://files.pythonhosted.org/packages/05/a0/1149a7163f8b0dfbc64bf9099b6f16d102ad3b03bcc11afee198d751da2d/ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6d54c14cf86ef13f10ccade94d1e7de146aa9b17d371e18b16e95f329393b7", size = 202490, upload-time = "2025-12-14T07:57:40.168Z" }, + { url = "https://files.pythonhosted.org/packages/68/82/f2ec5e758d6a7106645cca9bb7137d98bce5d363789fa94075be6572057c/ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f3584d07882b7ea2a1a589f795a3af97fe4c2932b739408e6d1d9d286cad862", size = 211733, upload-time = "2025-12-14T07:57:42.253Z" }, +] + +[[package]] +name = "packaging" +version = "23.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, +] + +[[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/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]] +name = "pdf2image" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/d8/b280f01045555dc257b8153c00dee3bc75830f91a744cd5f84ef3a0a64b1/pdf2image-1.17.0.tar.gz", hash = "sha256:eaa959bc116b420dd7ec415fcae49b98100dda3dd18cd2fdfa86d09f112f6d57", size = 12811, upload-time = "2024-01-07T20:33:01.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/33/61766ae033518957f877ab246f87ca30a85b778ebaad65b7f74fa7e52988/pdf2image-1.17.0-py3-none-any.whl", hash = "sha256:ecdd58d7afb810dffe21ef2b1bbc057ef434dabbac6c33778a38a3f7744a27e2", size = 11618, upload-time = "2024-01-07T20:32:59.957Z" }, +] + +[[package]] +name = "pillow" +version = "12.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/f2/de993bb2d21b33a98d031ecf6a978e4b61da207bef02f7b43093774c480d/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643", size = 4045493, upload-time = "2025-10-15T18:22:25.758Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b6/bc8d0c4c9f6f111a783d045310945deb769b806d7574764234ffd50bc5ea/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4", size = 4120461, upload-time = "2025-10-15T18:22:27.286Z" }, + { url = "https://files.pythonhosted.org/packages/5d/57/d60d343709366a353dc56adb4ee1e7d8a2cc34e3fbc22905f4167cfec119/pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399", size = 3576912, upload-time = "2025-10-15T18:22:28.751Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a4/a0a31467e3f83b94d37568294b01d22b43ae3c5d85f2811769b9c66389dd/pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5", size = 5249132, upload-time = "2025-10-15T18:22:30.641Z" }, + { url = "https://files.pythonhosted.org/packages/83/06/48eab21dd561de2914242711434c0c0eb992ed08ff3f6107a5f44527f5e9/pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b", size = 4650099, upload-time = "2025-10-15T18:22:32.73Z" }, + { url = "https://files.pythonhosted.org/packages/fc/bd/69ed99fd46a8dba7c1887156d3572fe4484e3f031405fcc5a92e31c04035/pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3", size = 6230808, upload-time = "2025-10-15T18:22:34.337Z" }, + { url = "https://files.pythonhosted.org/packages/ea/94/8fad659bcdbf86ed70099cb60ae40be6acca434bbc8c4c0d4ef356d7e0de/pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07", size = 8037804, upload-time = "2025-10-15T18:22:36.402Z" }, + { url = "https://files.pythonhosted.org/packages/20/39/c685d05c06deecfd4e2d1950e9a908aa2ca8bc4e6c3b12d93b9cafbd7837/pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e", size = 6345553, upload-time = "2025-10-15T18:22:38.066Z" }, + { url = "https://files.pythonhosted.org/packages/38/57/755dbd06530a27a5ed74f8cb0a7a44a21722ebf318edbe67ddbd7fb28f88/pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344", size = 7037729, upload-time = "2025-10-15T18:22:39.769Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b6/7e94f4c41d238615674d06ed677c14883103dce1c52e4af16f000338cfd7/pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27", size = 6459789, upload-time = "2025-10-15T18:22:41.437Z" }, + { url = "https://files.pythonhosted.org/packages/9c/14/4448bb0b5e0f22dd865290536d20ec8a23b64e2d04280b89139f09a36bb6/pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79", size = 7130917, upload-time = "2025-10-15T18:22:43.152Z" }, + { url = "https://files.pythonhosted.org/packages/dd/ca/16c6926cc1c015845745d5c16c9358e24282f1e588237a4c36d2b30f182f/pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098", size = 6302391, upload-time = "2025-10-15T18:22:44.753Z" }, + { url = "https://files.pythonhosted.org/packages/6d/2a/dd43dcfd6dae9b6a49ee28a8eedb98c7d5ff2de94a5d834565164667b97b/pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905", size = 7007477, upload-time = "2025-10-15T18:22:46.838Z" }, + { url = "https://files.pythonhosted.org/packages/77/f0/72ea067f4b5ae5ead653053212af05ce3705807906ba3f3e8f58ddf617e6/pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a", size = 2435918, upload-time = "2025-10-15T18:22:48.399Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5e/9046b423735c21f0487ea6cb5b10f89ea8f8dfbe32576fe052b5ba9d4e5b/pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3", size = 5251406, upload-time = "2025-10-15T18:22:49.905Z" }, + { url = "https://files.pythonhosted.org/packages/12/66/982ceebcdb13c97270ef7a56c3969635b4ee7cd45227fa707c94719229c5/pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced", size = 4653218, upload-time = "2025-10-15T18:22:51.587Z" }, + { url = "https://files.pythonhosted.org/packages/16/b3/81e625524688c31859450119bf12674619429cab3119eec0e30a7a1029cb/pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b", size = 6266564, upload-time = "2025-10-15T18:22:53.215Z" }, + { url = "https://files.pythonhosted.org/packages/98/59/dfb38f2a41240d2408096e1a76c671d0a105a4a8471b1871c6902719450c/pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d", size = 8069260, upload-time = "2025-10-15T18:22:54.933Z" }, + { url = "https://files.pythonhosted.org/packages/dc/3d/378dbea5cd1874b94c312425ca77b0f47776c78e0df2df751b820c8c1d6c/pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a", size = 6379248, upload-time = "2025-10-15T18:22:56.605Z" }, + { url = "https://files.pythonhosted.org/packages/84/b0/d525ef47d71590f1621510327acec75ae58c721dc071b17d8d652ca494d8/pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe", size = 7066043, upload-time = "2025-10-15T18:22:58.53Z" }, + { url = "https://files.pythonhosted.org/packages/61/2c/aced60e9cf9d0cde341d54bf7932c9ffc33ddb4a1595798b3a5150c7ec4e/pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee", size = 6490915, upload-time = "2025-10-15T18:23:00.582Z" }, + { url = "https://files.pythonhosted.org/packages/ef/26/69dcb9b91f4e59f8f34b2332a4a0a951b44f547c4ed39d3e4dcfcff48f89/pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef", size = 7157998, upload-time = "2025-10-15T18:23:02.627Z" }, + { url = "https://files.pythonhosted.org/packages/61/2b/726235842220ca95fa441ddf55dd2382b52ab5b8d9c0596fe6b3f23dafe8/pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9", size = 6306201, upload-time = "2025-10-15T18:23:04.709Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3d/2afaf4e840b2df71344ababf2f8edd75a705ce500e5dc1e7227808312ae1/pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b", size = 7013165, upload-time = "2025-10-15T18:23:06.46Z" }, + { url = "https://files.pythonhosted.org/packages/6f/75/3fa09aa5cf6ed04bee3fa575798ddf1ce0bace8edb47249c798077a81f7f/pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47", size = 2437834, upload-time = "2025-10-15T18:23:08.194Z" }, + { url = "https://files.pythonhosted.org/packages/54/2a/9a8c6ba2c2c07b71bec92cf63e03370ca5e5f5c5b119b742bcc0cde3f9c5/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9", size = 4045531, upload-time = "2025-10-15T18:23:10.121Z" }, + { url = "https://files.pythonhosted.org/packages/84/54/836fdbf1bfb3d66a59f0189ff0b9f5f666cee09c6188309300df04ad71fa/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2", size = 4120554, upload-time = "2025-10-15T18:23:12.14Z" }, + { url = "https://files.pythonhosted.org/packages/0d/cd/16aec9f0da4793e98e6b54778a5fbce4f375c6646fe662e80600b8797379/pillow-12.0.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a", size = 3576812, upload-time = "2025-10-15T18:23:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b7/13957fda356dc46339298b351cae0d327704986337c3c69bb54628c88155/pillow-12.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b", size = 5252689, upload-time = "2025-10-15T18:23:15.562Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f5/eae31a306341d8f331f43edb2e9122c7661b975433de5e447939ae61c5da/pillow-12.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad", size = 4650186, upload-time = "2025-10-15T18:23:17.379Z" }, + { url = "https://files.pythonhosted.org/packages/86/62/2a88339aa40c4c77e79108facbd307d6091e2c0eb5b8d3cf4977cfca2fe6/pillow-12.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01", size = 6230308, upload-time = "2025-10-15T18:23:18.971Z" }, + { url = "https://files.pythonhosted.org/packages/c7/33/5425a8992bcb32d1cb9fa3dd39a89e613d09a22f2c8083b7bf43c455f760/pillow-12.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c", size = 8039222, upload-time = "2025-10-15T18:23:20.909Z" }, + { url = "https://files.pythonhosted.org/packages/d8/61/3f5d3b35c5728f37953d3eec5b5f3e77111949523bd2dd7f31a851e50690/pillow-12.0.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e", size = 6346657, upload-time = "2025-10-15T18:23:23.077Z" }, + { url = "https://files.pythonhosted.org/packages/3a/be/ee90a3d79271227e0f0a33c453531efd6ed14b2e708596ba5dd9be948da3/pillow-12.0.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e", size = 7038482, upload-time = "2025-10-15T18:23:25.005Z" }, + { url = "https://files.pythonhosted.org/packages/44/34/a16b6a4d1ad727de390e9bd9f19f5f669e079e5826ec0f329010ddea492f/pillow-12.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9", size = 6461416, upload-time = "2025-10-15T18:23:27.009Z" }, + { url = "https://files.pythonhosted.org/packages/b6/39/1aa5850d2ade7d7ba9f54e4e4c17077244ff7a2d9e25998c38a29749eb3f/pillow-12.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab", size = 7131584, upload-time = "2025-10-15T18:23:29.752Z" }, + { url = "https://files.pythonhosted.org/packages/bf/db/4fae862f8fad0167073a7733973bfa955f47e2cac3dc3e3e6257d10fab4a/pillow-12.0.0-cp314-cp314-win32.whl", hash = "sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b", size = 6400621, upload-time = "2025-10-15T18:23:32.06Z" }, + { url = "https://files.pythonhosted.org/packages/2b/24/b350c31543fb0107ab2599464d7e28e6f856027aadda995022e695313d94/pillow-12.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b", size = 7142916, upload-time = "2025-10-15T18:23:34.71Z" }, + { url = "https://files.pythonhosted.org/packages/0f/9b/0ba5a6fd9351793996ef7487c4fdbde8d3f5f75dbedc093bb598648fddf0/pillow-12.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0", size = 2523836, upload-time = "2025-10-15T18:23:36.967Z" }, + { url = "https://files.pythonhosted.org/packages/f5/7a/ceee0840aebc579af529b523d530840338ecf63992395842e54edc805987/pillow-12.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6", size = 5255092, upload-time = "2025-10-15T18:23:38.573Z" }, + { url = "https://files.pythonhosted.org/packages/44/76/20776057b4bfd1aef4eeca992ebde0f53a4dce874f3ae693d0ec90a4f79b/pillow-12.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6", size = 4653158, upload-time = "2025-10-15T18:23:40.238Z" }, + { url = "https://files.pythonhosted.org/packages/82/3f/d9ff92ace07be8836b4e7e87e6a4c7a8318d47c2f1463ffcf121fc57d9cb/pillow-12.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1", size = 6267882, upload-time = "2025-10-15T18:23:42.434Z" }, + { url = "https://files.pythonhosted.org/packages/9f/7a/4f7ff87f00d3ad33ba21af78bfcd2f032107710baf8280e3722ceec28cda/pillow-12.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e", size = 8071001, upload-time = "2025-10-15T18:23:44.29Z" }, + { url = "https://files.pythonhosted.org/packages/75/87/fcea108944a52dad8cca0715ae6247e271eb80459364a98518f1e4f480c1/pillow-12.0.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca", size = 6380146, upload-time = "2025-10-15T18:23:46.065Z" }, + { url = "https://files.pythonhosted.org/packages/91/52/0d31b5e571ef5fd111d2978b84603fce26aba1b6092f28e941cb46570745/pillow-12.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925", size = 7067344, upload-time = "2025-10-15T18:23:47.898Z" }, + { url = "https://files.pythonhosted.org/packages/7b/f4/2dd3d721f875f928d48e83bb30a434dee75a2531bca839bb996bb0aa5a91/pillow-12.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8", size = 6491864, upload-time = "2025-10-15T18:23:49.607Z" }, + { url = "https://files.pythonhosted.org/packages/30/4b/667dfcf3d61fc309ba5a15b141845cece5915e39b99c1ceab0f34bf1d124/pillow-12.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4", size = 7158911, upload-time = "2025-10-15T18:23:51.351Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2f/16cabcc6426c32218ace36bf0d55955e813f2958afddbf1d391849fee9d1/pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52", size = 6408045, upload-time = "2025-10-15T18:23:53.177Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/e29aa0c9c666cf787628d3f0dcf379f4791fba79f4936d02f8b37165bdf8/pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a", size = 7148282, upload-time = "2025-10-15T18:23:55.316Z" }, + { url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630, upload-time = "2025-10-15T18:23:57.149Z" }, +] + +[[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/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 = "psycopg2" +version = "2.9.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/8d/9d12bc8677c24dad342ec777529bce705b3e785fa05d85122b5502b9ab55/psycopg2-2.9.11.tar.gz", hash = "sha256:964d31caf728e217c697ff77ea69c2ba0865fa41ec20bb00f0977e62fdcc52e3", size = 379598, upload-time = "2025-10-10T11:14:46.075Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5a/18c8cb13fc6908dc41a483d2c14d927a7a3f29883748747e8cb625da6587/psycopg2-2.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:8dc379166b5b7d5ea66dcebf433011dfc51a7bb8a5fc12367fa05668e5fc53c8", size = 2714048, upload-time = "2025-10-10T11:10:19.816Z" }, + { url = "https://files.pythonhosted.org/packages/47/08/737aa39c78d705a7ce58248d00eeba0e9fc36be488f9b672b88736fbb1f7/psycopg2-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:f10a48acba5fe6e312b891f290b4d2ca595fc9a06850fe53320beac353575578", size = 2803738, upload-time = "2025-10-10T11:10:23.196Z" }, +] + +[[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 = "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.5" +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/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[package.optional-dependencies] +email = [ + { name = "email-validator" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, +] + +[[package]] +name = "pydantic-extra-types" +version = "2.10.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/10/fb64987804cde41bcc39d9cd757cd5f2bb5d97b389d81aa70238b14b8a7e/pydantic_extra_types-2.10.6.tar.gz", hash = "sha256:c63d70bf684366e6bbe1f4ee3957952ebe6973d41e7802aea0b770d06b116aeb", size = 141858, upload-time = "2025-10-08T13:47:49.483Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/04/5c918669096da8d1c9ec7bb716bd72e755526103a61bc5e76a3e4fb23b53/pydantic_extra_types-2.10.6-py3-none-any.whl", hash = "sha256:6106c448316d30abf721b5b9fecc65e983ef2614399a24142d689c7546cc246a", size = 40949, upload-time = "2025-10-08T13:47:48.268Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, +] + +[[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 = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + +[package.optional-dependencies] +crypto = [ + { name = "cryptography" }, +] + +[[package]] +name = "pymupdf" +version = "1.26.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/d6/09b28f027b510838559f7748807192149c419b30cb90e6d5f0cf916dc9dc/pymupdf-1.26.7.tar.gz", hash = "sha256:71add8bdc8eb1aaa207c69a13400693f06ad9b927bea976f5d5ab9df0bb489c3", size = 84327033, upload-time = "2025-12-11T21:48:50.694Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/35/cd74cea1787b2247702ef8522186bdef32e9cb30a099e6bb864627ef6045/pymupdf-1.26.7-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:07085718dfdae5ab83b05eb5eb397f863bcc538fe05135318a01ea353e7a1353", size = 23179369, upload-time = "2025-12-11T21:47:21.587Z" }, + { url = "https://files.pythonhosted.org/packages/72/74/448b6172927c829c6a3fba80078d7b0a016ebbe2c9ee528821f5ea21677a/pymupdf-1.26.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:31aa9c8377ea1eea02934b92f4dcf79fb2abba0bf41f8a46d64c3e31546a3c02", size = 22470101, upload-time = "2025-12-11T21:47:37.105Z" }, + { url = "https://files.pythonhosted.org/packages/65/e7/47af26f3ac76be7ac3dd4d6cc7ee105948a8355d774e5ca39857bf91c11c/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e419b609996434a14a80fa060adec72c434a1cca6a511ec54db9841bc5d51b3c", size = 23502486, upload-time = "2025-12-12T09:51:25.824Z" }, + { url = "https://files.pythonhosted.org/packages/2a/6b/3de1714d734ff949be1e90a22375d0598d3540b22ae73eb85c2d7d1f36a9/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:69dfc78f206a96e5b3ac22741263ebab945fdf51f0dbe7c5757c3511b23d9d72", size = 24115727, upload-time = "2025-12-11T21:47:51.274Z" }, + { url = "https://files.pythonhosted.org/packages/62/9b/f86224847949577a523be2207315ae0fd3155b5d909cd66c274d095349a3/pymupdf-1.26.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1d5106f46e1ca0d64d46bd51892372a4f82076bdc14a9678d33d630702abca36", size = 24324386, upload-time = "2025-12-12T14:58:45.483Z" }, + { url = "https://files.pythonhosted.org/packages/85/8e/a117d39092ca645fde8b903f4a941d9aa75b370a67b4f1f435f56393dc5a/pymupdf-1.26.7-cp310-abi3-win32.whl", hash = "sha256:7c9645b6f5452629c747690190350213d3e5bbdb6b2eca227d82702b327f6eee", size = 17203888, upload-time = "2025-12-12T13:59:57.613Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c3/d0047678146c294469c33bae167c8ace337deafb736b0bf97b9bc481aa65/pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba", size = 18405952, upload-time = "2025-12-11T21:48:02.947Z" }, +] + +[[package]] +name = "pypdf" +version = "6.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/9b/db1056a54eda8cd44f9e5128e87e1142cb328295dad92bbec0d39f251641/pypdf-6.5.0.tar.gz", hash = "sha256:9e78950906380ae4f2ce1d9039e9008098ba6366a4d9c7423c4bdbd6e6683404", size = 5277655, upload-time = "2025-12-21T11:07:19.876Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/db/f2e7703791a1f32532618b82789ddddb7173b9e22d97e34cc11950d8e330/pypdf-6.5.0-py3-none-any.whl", hash = "sha256:9cef8002aaedeecf648dfd9ff1ce38f20ae8d88e2534fced6630038906440b25", size = 329560, upload-time = "2025-12-21T11:07:18.173Z" }, +] + +[[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 = "pytesseract" +version = "0.3.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/a6/7d679b83c285974a7cb94d739b461fa7e7a9b17a3abfd7bf6cbc5c2394b0/pytesseract-0.3.13.tar.gz", hash = "sha256:4bf5f880c99406f52a3cfc2633e42d9dc67615e69d8a509d74867d3baddb5db9", size = 17689, upload-time = "2024-08-16T02:33:56.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/33/8312d7ce74670c9d39a532b2c246a853861120486be9443eebf048043637/pytesseract-0.3.13-py3-none-any.whl", hash = "sha256:7a99c6c2ac598360693d83a416e36e0b33a67638bb9d77fdcac094a3589d4b34", size = 14705, upload-time = "2024-08-16T02:36:10.09Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, +] + +[[package]] +name = "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.21" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/78/96/804520d0850c7db98e5ccb70282e29208723f0964e88ffd9d0da2f52ea09/python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92", size = 37196, upload-time = "2025-12-17T09:24:22.446Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541, upload-time = "2025-12-17T09:24:21.153Z" }, +] + +[[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/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 = "regex" +version = "2025.11.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669, upload-time = "2025-11-03T21:34:22.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/a7/dda24ebd49da46a197436ad96378f17df30ceb40e52e859fc42cac45b850/regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4", size = 489081, upload-time = "2025-11-03T21:31:55.9Z" }, + { url = "https://files.pythonhosted.org/packages/19/22/af2dc751aacf88089836aa088a1a11c4f21a04707eb1b0478e8e8fb32847/regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76", size = 291123, upload-time = "2025-11-03T21:31:57.758Z" }, + { url = "https://files.pythonhosted.org/packages/a3/88/1a3ea5672f4b0a84802ee9891b86743438e7c04eb0b8f8c4e16a42375327/regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a", size = 288814, upload-time = "2025-11-03T21:32:01.12Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8c/f5987895bf42b8ddeea1b315c9fedcfe07cadee28b9c98cf50d00adcb14d/regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361", size = 798592, upload-time = "2025-11-03T21:32:03.006Z" }, + { url = "https://files.pythonhosted.org/packages/99/2a/6591ebeede78203fa77ee46a1c36649e02df9eaa77a033d1ccdf2fcd5d4e/regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160", size = 864122, upload-time = "2025-11-03T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/94/d6/be32a87cf28cf8ed064ff281cfbd49aefd90242a83e4b08b5a86b38e8eb4/regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe", size = 912272, upload-time = "2025-11-03T21:32:06.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/11/9bcef2d1445665b180ac7f230406ad80671f0fc2a6ffb93493b5dd8cd64c/regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850", size = 803497, upload-time = "2025-11-03T21:32:08.162Z" }, + { url = "https://files.pythonhosted.org/packages/e5/a7/da0dc273d57f560399aa16d8a68ae7f9b57679476fc7ace46501d455fe84/regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc", size = 787892, upload-time = "2025-11-03T21:32:09.769Z" }, + { url = "https://files.pythonhosted.org/packages/da/4b/732a0c5a9736a0b8d6d720d4945a2f1e6f38f87f48f3173559f53e8d5d82/regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9", size = 858462, upload-time = "2025-11-03T21:32:11.769Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f5/a2a03df27dc4c2d0c769220f5110ba8c4084b0bfa9ab0f9b4fcfa3d2b0fc/regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b", size = 850528, upload-time = "2025-11-03T21:32:13.906Z" }, + { url = "https://files.pythonhosted.org/packages/d6/09/e1cd5bee3841c7f6eb37d95ca91cdee7100b8f88b81e41c2ef426910891a/regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7", size = 789866, upload-time = "2025-11-03T21:32:15.748Z" }, + { url = "https://files.pythonhosted.org/packages/eb/51/702f5ea74e2a9c13d855a6a85b7f80c30f9e72a95493260193c07f3f8d74/regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c", size = 266189, upload-time = "2025-11-03T21:32:17.493Z" }, + { url = "https://files.pythonhosted.org/packages/8b/00/6e29bb314e271a743170e53649db0fdb8e8ff0b64b4f425f5602f4eb9014/regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5", size = 277054, upload-time = "2025-11-03T21:32:19.042Z" }, + { url = "https://files.pythonhosted.org/packages/25/f1/b156ff9f2ec9ac441710764dda95e4edaf5f36aca48246d1eea3f1fd96ec/regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467", size = 270325, upload-time = "2025-11-03T21:32:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/20/28/fd0c63357caefe5680b8ea052131acbd7f456893b69cc2a90cc3e0dc90d4/regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281", size = 491984, upload-time = "2025-11-03T21:32:23.466Z" }, + { url = "https://files.pythonhosted.org/packages/df/ec/7014c15626ab46b902b3bcc4b28a7bae46d8f281fc7ea9c95e22fcaaa917/regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39", size = 292673, upload-time = "2025-11-03T21:32:25.034Z" }, + { url = "https://files.pythonhosted.org/packages/23/ab/3b952ff7239f20d05f1f99e9e20188513905f218c81d52fb5e78d2bf7634/regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7", size = 291029, upload-time = "2025-11-03T21:32:26.528Z" }, + { url = "https://files.pythonhosted.org/packages/21/7e/3dc2749fc684f455f162dcafb8a187b559e2614f3826877d3844a131f37b/regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed", size = 807437, upload-time = "2025-11-03T21:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/1b/0b/d529a85ab349c6a25d1ca783235b6e3eedf187247eab536797021f7126c6/regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19", size = 873368, upload-time = "2025-11-03T21:32:30.4Z" }, + { url = "https://files.pythonhosted.org/packages/7d/18/2d868155f8c9e3e9d8f9e10c64e9a9f496bb8f7e037a88a8bed26b435af6/regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b", size = 914921, upload-time = "2025-11-03T21:32:32.123Z" }, + { url = "https://files.pythonhosted.org/packages/2d/71/9d72ff0f354fa783fe2ba913c8734c3b433b86406117a8db4ea2bf1c7a2f/regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a", size = 812708, upload-time = "2025-11-03T21:32:34.305Z" }, + { url = "https://files.pythonhosted.org/packages/e7/19/ce4bf7f5575c97f82b6e804ffb5c4e940c62609ab2a0d9538d47a7fdf7d4/regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6", size = 795472, upload-time = "2025-11-03T21:32:36.364Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/fd1063a176ffb7b2315f9a1b08d17b18118b28d9df163132615b835a26ee/regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce", size = 868341, upload-time = "2025-11-03T21:32:38.042Z" }, + { url = "https://files.pythonhosted.org/packages/12/43/103fb2e9811205e7386366501bc866a164a0430c79dd59eac886a2822950/regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd", size = 854666, upload-time = "2025-11-03T21:32:40.079Z" }, + { url = "https://files.pythonhosted.org/packages/7d/22/e392e53f3869b75804762c7c848bd2dd2abf2b70fb0e526f58724638bd35/regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2", size = 799473, upload-time = "2025-11-03T21:32:42.148Z" }, + { url = "https://files.pythonhosted.org/packages/4f/f9/8bd6b656592f925b6845fcbb4d57603a3ac2fb2373344ffa1ed70aa6820a/regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a", size = 268792, upload-time = "2025-11-03T21:32:44.13Z" }, + { url = "https://files.pythonhosted.org/packages/e5/87/0e7d603467775ff65cd2aeabf1b5b50cc1c3708556a8b849a2fa4dd1542b/regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c", size = 280214, upload-time = "2025-11-03T21:32:45.853Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d0/2afc6f8e94e2b64bfb738a7c2b6387ac1699f09f032d363ed9447fd2bb57/regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e", size = 271469, upload-time = "2025-11-03T21:32:48.026Z" }, + { url = "https://files.pythonhosted.org/packages/31/e9/f6e13de7e0983837f7b6d238ad9458800a874bf37c264f7923e63409944c/regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6", size = 489089, upload-time = "2025-11-03T21:32:50.027Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5c/261f4a262f1fa65141c1b74b255988bd2fa020cc599e53b080667d591cfc/regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4", size = 291059, upload-time = "2025-11-03T21:32:51.682Z" }, + { url = "https://files.pythonhosted.org/packages/8e/57/f14eeb7f072b0e9a5a090d1712741fd8f214ec193dba773cf5410108bb7d/regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73", size = 288900, upload-time = "2025-11-03T21:32:53.569Z" }, + { url = "https://files.pythonhosted.org/packages/3c/6b/1d650c45e99a9b327586739d926a1cd4e94666b1bd4af90428b36af66dc7/regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f", size = 799010, upload-time = "2025-11-03T21:32:55.222Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/d66dcbc6b628ce4e3f7f0cbbb84603aa2fc0ffc878babc857726b8aab2e9/regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d", size = 864893, upload-time = "2025-11-03T21:32:57.239Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2d/f238229f1caba7ac87a6c4153d79947fb0261415827ae0f77c304260c7d3/regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be", size = 911522, upload-time = "2025-11-03T21:32:59.274Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3d/22a4eaba214a917c80e04f6025d26143690f0419511e0116508e24b11c9b/regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db", size = 803272, upload-time = "2025-11-03T21:33:01.393Z" }, + { url = "https://files.pythonhosted.org/packages/84/b1/03188f634a409353a84b5ef49754b97dbcc0c0f6fd6c8ede505a8960a0a4/regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62", size = 787958, upload-time = "2025-11-03T21:33:03.379Z" }, + { url = "https://files.pythonhosted.org/packages/99/6a/27d072f7fbf6fadd59c64d210305e1ff865cc3b78b526fd147db768c553b/regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f", size = 859289, upload-time = "2025-11-03T21:33:05.374Z" }, + { url = "https://files.pythonhosted.org/packages/9a/70/1b3878f648e0b6abe023172dacb02157e685564853cc363d9961bcccde4e/regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02", size = 850026, upload-time = "2025-11-03T21:33:07.131Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d5/68e25559b526b8baab8e66839304ede68ff6727237a47727d240006bd0ff/regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed", size = 789499, upload-time = "2025-11-03T21:33:09.141Z" }, + { url = "https://files.pythonhosted.org/packages/fc/df/43971264857140a350910d4e33df725e8c94dd9dee8d2e4729fa0d63d49e/regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4", size = 271604, upload-time = "2025-11-03T21:33:10.9Z" }, + { url = "https://files.pythonhosted.org/packages/01/6f/9711b57dc6894a55faf80a4c1b5aa4f8649805cb9c7aef46f7d27e2b9206/regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad", size = 280320, upload-time = "2025-11-03T21:33:12.572Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7e/f6eaa207d4377481f5e1775cdeb5a443b5a59b392d0065f3417d31d80f87/regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f", size = 273372, upload-time = "2025-11-03T21:33:14.219Z" }, + { url = "https://files.pythonhosted.org/packages/c3/06/49b198550ee0f5e4184271cee87ba4dfd9692c91ec55289e6282f0f86ccf/regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc", size = 491985, upload-time = "2025-11-03T21:33:16.555Z" }, + { url = "https://files.pythonhosted.org/packages/ce/bf/abdafade008f0b1c9da10d934034cb670432d6cf6cbe38bbb53a1cfd6cf8/regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49", size = 292669, upload-time = "2025-11-03T21:33:18.32Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ef/0c357bb8edbd2ad8e273fcb9e1761bc37b8acbc6e1be050bebd6475f19c1/regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536", size = 291030, upload-time = "2025-11-03T21:33:20.048Z" }, + { url = "https://files.pythonhosted.org/packages/79/06/edbb67257596649b8fb088d6aeacbcb248ac195714b18a65e018bf4c0b50/regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95", size = 807674, upload-time = "2025-11-03T21:33:21.797Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d9/ad4deccfce0ea336296bd087f1a191543bb99ee1c53093dcd4c64d951d00/regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009", size = 873451, upload-time = "2025-11-03T21:33:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/13/75/a55a4724c56ef13e3e04acaab29df26582f6978c000ac9cd6810ad1f341f/regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9", size = 914980, upload-time = "2025-11-03T21:33:25.999Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/a1657ee15bd9116f70d4a530c736983eed997b361e20ecd8f5ca3759d5c5/regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d", size = 812852, upload-time = "2025-11-03T21:33:27.852Z" }, + { url = "https://files.pythonhosted.org/packages/b8/6f/f7516dde5506a588a561d296b2d0044839de06035bb486b326065b4c101e/regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6", size = 795566, upload-time = "2025-11-03T21:33:32.364Z" }, + { url = "https://files.pythonhosted.org/packages/d9/dd/3d10b9e170cc16fb34cb2cef91513cf3df65f440b3366030631b2984a264/regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154", size = 868463, upload-time = "2025-11-03T21:33:34.459Z" }, + { url = "https://files.pythonhosted.org/packages/f5/8e/935e6beff1695aa9085ff83195daccd72acc82c81793df480f34569330de/regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267", size = 854694, upload-time = "2025-11-03T21:33:36.793Z" }, + { url = "https://files.pythonhosted.org/packages/92/12/10650181a040978b2f5720a6a74d44f841371a3d984c2083fc1752e4acf6/regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379", size = 799691, upload-time = "2025-11-03T21:33:39.079Z" }, + { url = "https://files.pythonhosted.org/packages/67/90/8f37138181c9a7690e7e4cb388debbd389342db3c7381d636d2875940752/regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38", size = 274583, upload-time = "2025-11-03T21:33:41.302Z" }, + { url = "https://files.pythonhosted.org/packages/8f/cd/867f5ec442d56beb56f5f854f40abcfc75e11d10b11fdb1869dd39c63aaf/regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de", size = 284286, upload-time = "2025-11-03T21:33:43.324Z" }, + { url = "https://files.pythonhosted.org/packages/20/31/32c0c4610cbc070362bf1d2e4ea86d1ea29014d400a6d6c2486fcfd57766/regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801", size = 274741, upload-time = "2025-11-03T21:33:45.557Z" }, +] + +[[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-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 = "rich-toolkit" +version = "0.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/97/09/3f9b8d9daaf235195c626f21e03604c05b987404ee3bcacee0c1f67f2a8e/rich_toolkit-0.17.1.tar.gz", hash = "sha256:5af54df8d1dd9c8530e462e1bdcaed625c9b49f5a55b035aa0ba1c17bdb87c9a", size = 187925, upload-time = "2025-12-17T10:49:22.583Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/7b/15e55fa8a76d0d41bf34d965af78acdaf80a315907adb30de8b63c272694/rich_toolkit-0.17.1-py3-none-any.whl", hash = "sha256:96d24bb921ecd225ffce7c526a9149e74006410c05e6d405bd74ffd54d5631ed", size = 31412, upload-time = "2025-12-17T10:49:21.793Z" }, +] + +[[package]] +name = "rignore" +version = "0.7.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/8a/a4078f6e14932ac7edb171149c481de29969d96ddee3ece5dc4c26f9e0c3/rignore-0.7.6-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2bdab1d31ec9b4fb1331980ee49ea051c0d7f7bb6baa28b3125ef03cdc48fdaf", size = 883057, upload-time = "2025-11-05T20:42:42.741Z" }, + { url = "https://files.pythonhosted.org/packages/f9/8f/f8daacd177db4bf7c2223bab41e630c52711f8af9ed279be2058d2fe4982/rignore-0.7.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:90f0a00ce0c866c275bf888271f1dc0d2140f29b82fcf33cdbda1e1a6af01010", size = 820150, upload-time = "2025-11-05T20:42:26.545Z" }, + { url = "https://files.pythonhosted.org/packages/36/31/b65b837e39c3f7064c426754714ac633b66b8c2290978af9d7f513e14aa9/rignore-0.7.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ad295537041dc2ed4b540fb1a3906bd9ede6ccdad3fe79770cd89e04e3c73c", size = 897406, upload-time = "2025-11-05T20:40:53.854Z" }, + { url = "https://files.pythonhosted.org/packages/ca/58/1970ce006c427e202ac7c081435719a076c478f07b3a23f469227788dc23/rignore-0.7.6-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f782dbd3a65a5ac85adfff69e5c6b101285ef3f845c3a3cae56a54bebf9fe116", size = 874050, upload-time = "2025-11-05T20:41:08.922Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/eb45db9f90137329072a732273be0d383cb7d7f50ddc8e0bceea34c1dfdf/rignore-0.7.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65cece3b36e5b0826d946494734c0e6aaf5a0337e18ff55b071438efe13d559e", size = 1167835, upload-time = "2025-11-05T20:41:24.997Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f1/6f1d72ddca41a64eed569680587a1236633587cc9f78136477ae69e2c88a/rignore-0.7.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7e4bb66c13cd7602dc8931822c02dfbbd5252015c750ac5d6152b186f0a8be0", size = 941945, upload-time = "2025-11-05T20:41:40.628Z" }, + { url = "https://files.pythonhosted.org/packages/48/6f/2f178af1c1a276a065f563ec1e11e7a9e23d4996fd0465516afce4b5c636/rignore-0.7.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297e500c15766e196f68aaaa70e8b6db85fa23fdc075b880d8231fdfba738cd7", size = 959067, upload-time = "2025-11-05T20:42:11.09Z" }, + { url = "https://files.pythonhosted.org/packages/5b/db/423a81c4c1e173877c7f9b5767dcaf1ab50484a94f60a0b2ed78be3fa765/rignore-0.7.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a07084211a8d35e1a5b1d32b9661a5ed20669970b369df0cf77da3adea3405de", size = 984438, upload-time = "2025-11-05T20:41:55.443Z" }, + { url = "https://files.pythonhosted.org/packages/31/eb/c4f92cc3f2825d501d3c46a244a671eb737fc1bcf7b05a3ecd34abb3e0d7/rignore-0.7.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:181eb2a975a22256a1441a9d2f15eb1292839ea3f05606620bd9e1938302cf79", size = 1078365, upload-time = "2025-11-05T21:40:15.148Z" }, + { url = "https://files.pythonhosted.org/packages/26/09/99442f02794bd7441bfc8ed1c7319e890449b816a7493b2db0e30af39095/rignore-0.7.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7bbcdc52b5bf9f054b34ce4af5269df5d863d9c2456243338bc193c28022bd7b", size = 1139066, upload-time = "2025-11-05T21:40:32.771Z" }, + { url = "https://files.pythonhosted.org/packages/2c/88/bcfc21e520bba975410e9419450f4b90a2ac8236b9a80fd8130e87d098af/rignore-0.7.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f2e027a6da21a7c8c0d87553c24ca5cc4364def18d146057862c23a96546238e", size = 1118036, upload-time = "2025-11-05T21:40:49.646Z" }, + { url = "https://files.pythonhosted.org/packages/e2/25/d37215e4562cda5c13312636393aea0bafe38d54d4e0517520a4cc0753ec/rignore-0.7.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee4a18b82cbbc648e4aac1510066682fe62beb5dc88e2c67c53a83954e541360", size = 1127550, upload-time = "2025-11-05T21:41:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/dc/76/a264ab38bfa1620ec12a8ff1c07778da89e16d8c0f3450b0333020d3d6dc/rignore-0.7.6-cp313-cp313-win32.whl", hash = "sha256:a7d7148b6e5e95035d4390396895adc384d37ff4e06781a36fe573bba7c283e5", size = 646097, upload-time = "2025-11-05T21:41:53.201Z" }, + { url = "https://files.pythonhosted.org/packages/62/44/3c31b8983c29ea8832b6082ddb1d07b90379c2d993bd20fce4487b71b4f4/rignore-0.7.6-cp313-cp313-win_amd64.whl", hash = "sha256:b037c4b15a64dced08fc12310ee844ec2284c4c5c1ca77bc37d0a04f7bff386e", size = 726170, upload-time = "2025-11-05T21:41:38.131Z" }, + { url = "https://files.pythonhosted.org/packages/aa/41/e26a075cab83debe41a42661262f606166157df84e0e02e2d904d134c0d8/rignore-0.7.6-cp313-cp313-win_arm64.whl", hash = "sha256:e47443de9b12fe569889bdbe020abe0e0b667516ee2ab435443f6d0869bd2804", size = 656184, upload-time = "2025-11-05T21:41:27.396Z" }, + { url = "https://files.pythonhosted.org/packages/9a/b9/1f5bd82b87e5550cd843ceb3768b4a8ef274eb63f29333cf2f29644b3d75/rignore-0.7.6-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:8e41be9fa8f2f47239ded8920cc283699a052ac4c371f77f5ac017ebeed75732", size = 882632, upload-time = "2025-11-05T20:42:44.063Z" }, + { url = "https://files.pythonhosted.org/packages/e9/6b/07714a3efe4a8048864e8a5b7db311ba51b921e15268b17defaebf56d3db/rignore-0.7.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6dc1e171e52cefa6c20e60c05394a71165663b48bca6c7666dee4f778f2a7d90", size = 820760, upload-time = "2025-11-05T20:42:27.885Z" }, + { url = "https://files.pythonhosted.org/packages/ac/0f/348c829ea2d8d596e856371b14b9092f8a5dfbb62674ec9b3f67e4939a9d/rignore-0.7.6-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce2268837c3600f82ab8db58f5834009dc638ee17103582960da668963bebc5", size = 899044, upload-time = "2025-11-05T20:40:55.336Z" }, + { url = "https://files.pythonhosted.org/packages/f0/30/2e1841a19b4dd23878d73edd5d82e998a83d5ed9570a89675f140ca8b2ad/rignore-0.7.6-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:690a3e1b54bfe77e89c4bacb13f046e642f8baadafc61d68f5a726f324a76ab6", size = 874144, upload-time = "2025-11-05T20:41:10.195Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bf/0ce9beb2e5f64c30e3580bef09f5829236889f01511a125f98b83169b993/rignore-0.7.6-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09d12ac7a0b6210c07bcd145007117ebd8abe99c8eeb383e9e4673910c2754b2", size = 1168062, upload-time = "2025-11-05T20:41:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/b9/8b/571c178414eb4014969865317da8a02ce4cf5241a41676ef91a59aab24de/rignore-0.7.6-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a2b2b74a8c60203b08452479b90e5ce3dbe96a916214bc9eb2e5af0b6a9beb0", size = 942542, upload-time = "2025-11-05T20:41:41.838Z" }, + { url = "https://files.pythonhosted.org/packages/19/62/7a3cf601d5a45137a7e2b89d10c05b5b86499190c4b7ca5c3c47d79ee519/rignore-0.7.6-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fc5a531ef02131e44359419a366bfac57f773ea58f5278c2cdd915f7d10ea94", size = 958739, upload-time = "2025-11-05T20:42:12.463Z" }, + { url = "https://files.pythonhosted.org/packages/5f/1f/4261f6a0d7caf2058a5cde2f5045f565ab91aa7badc972b57d19ce58b14e/rignore-0.7.6-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7a1f77d9c4cd7e76229e252614d963442686bfe12c787a49f4fe481df49e7a9", size = 984138, upload-time = "2025-11-05T20:41:56.775Z" }, + { url = "https://files.pythonhosted.org/packages/2b/bf/628dfe19c75e8ce1f45f7c248f5148b17dfa89a817f8e3552ab74c3ae812/rignore-0.7.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ead81f728682ba72b5b1c3d5846b011d3e0174da978de87c61645f2ed36659a7", size = 1079299, upload-time = "2025-11-05T21:40:16.639Z" }, + { url = "https://files.pythonhosted.org/packages/af/a5/be29c50f5c0c25c637ed32db8758fdf5b901a99e08b608971cda8afb293b/rignore-0.7.6-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:12ffd50f520c22ffdabed8cd8bfb567d9ac165b2b854d3e679f4bcaef11a9441", size = 1139618, upload-time = "2025-11-05T21:40:34.507Z" }, + { url = "https://files.pythonhosted.org/packages/2a/40/3c46cd7ce4fa05c20b525fd60f599165e820af66e66f2c371cd50644558f/rignore-0.7.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:e5a16890fbe3c894f8ca34b0fcacc2c200398d4d46ae654e03bc9b3dbf2a0a72", size = 1117626, upload-time = "2025-11-05T21:40:51.494Z" }, + { url = "https://files.pythonhosted.org/packages/8c/b9/aea926f263b8a29a23c75c2e0d8447965eb1879d3feb53cfcf84db67ed58/rignore-0.7.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3abab3bf99e8a77488ef6c7c9a799fac22224c28fe9f25cc21aa7cc2b72bfc0b", size = 1128144, upload-time = "2025-11-05T21:41:09.169Z" }, + { url = "https://files.pythonhosted.org/packages/a4/f6/0d6242f8d0df7f2ecbe91679fefc1f75e7cd2072cb4f497abaab3f0f8523/rignore-0.7.6-cp314-cp314-win32.whl", hash = "sha256:eeef421c1782953c4375aa32f06ecae470c1285c6381eee2a30d2e02a5633001", size = 646385, upload-time = "2025-11-05T21:41:55.105Z" }, + { url = "https://files.pythonhosted.org/packages/d5/38/c0dcd7b10064f084343d6af26fe9414e46e9619c5f3224b5272e8e5d9956/rignore-0.7.6-cp314-cp314-win_amd64.whl", hash = "sha256:6aeed503b3b3d5af939b21d72a82521701a4bd3b89cd761da1e7dc78621af304", size = 725738, upload-time = "2025-11-05T21:41:39.736Z" }, + { url = "https://files.pythonhosted.org/packages/d9/7a/290f868296c1ece914d565757ab363b04730a728b544beb567ceb3b2d96f/rignore-0.7.6-cp314-cp314-win_arm64.whl", hash = "sha256:104f215b60b3c984c386c3e747d6ab4376d5656478694e22c7bd2f788ddd8304", size = 656008, upload-time = "2025-11-05T21:41:29.028Z" }, + { url = "https://files.pythonhosted.org/packages/ca/d2/3c74e3cd81fe8ea08a8dcd2d755c09ac2e8ad8fe409508904557b58383d3/rignore-0.7.6-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bb24a5b947656dd94cb9e41c4bc8b23cec0c435b58be0d74a874f63c259549e8", size = 882835, upload-time = "2025-11-05T20:42:45.443Z" }, + { url = "https://files.pythonhosted.org/packages/77/61/a772a34b6b63154877433ac2d048364815b24c2dd308f76b212c408101a2/rignore-0.7.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b1e33c9501cefe24b70a1eafd9821acfd0ebf0b35c3a379430a14df089993e3", size = 820301, upload-time = "2025-11-05T20:42:29.226Z" }, + { url = "https://files.pythonhosted.org/packages/71/30/054880b09c0b1b61d17eeb15279d8bf729c0ba52b36c3ada52fb827cbb3c/rignore-0.7.6-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bec3994665a44454df86deb762061e05cd4b61e3772f5b07d1882a8a0d2748d5", size = 897611, upload-time = "2025-11-05T20:40:56.475Z" }, + { url = "https://files.pythonhosted.org/packages/1e/40/b2d1c169f833d69931bf232600eaa3c7998ba4f9a402e43a822dad2ea9f2/rignore-0.7.6-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26cba2edfe3cff1dfa72bddf65d316ddebf182f011f2f61538705d6dbaf54986", size = 873875, upload-time = "2025-11-05T20:41:11.561Z" }, + { url = "https://files.pythonhosted.org/packages/55/59/ca5ae93d83a1a60e44b21d87deb48b177a8db1b85e82fc8a9abb24a8986d/rignore-0.7.6-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffa86694fec604c613696cb91e43892aa22e1fec5f9870e48f111c603e5ec4e9", size = 1167245, upload-time = "2025-11-05T20:41:28.29Z" }, + { url = "https://files.pythonhosted.org/packages/a5/52/cf3dce392ba2af806cba265aad6bcd9c48bb2a6cb5eee448d3319f6e505b/rignore-0.7.6-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48efe2ed95aa8104145004afb15cdfa02bea5cdde8b0344afeb0434f0d989aa2", size = 941750, upload-time = "2025-11-05T20:41:43.111Z" }, + { url = "https://files.pythonhosted.org/packages/ec/be/3f344c6218d779395e785091d05396dfd8b625f6aafbe502746fcd880af2/rignore-0.7.6-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dcae43eb44b7f2457fef7cc87f103f9a0013017a6f4e62182c565e924948f21", size = 958896, upload-time = "2025-11-05T20:42:13.784Z" }, + { url = "https://files.pythonhosted.org/packages/c9/34/d3fa71938aed7d00dcad87f0f9bcb02ad66c85d6ffc83ba31078ce53646a/rignore-0.7.6-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2cd649a7091c0dad2f11ef65630d30c698d505cbe8660dd395268e7c099cc99f", size = 983992, upload-time = "2025-11-05T20:41:58.022Z" }, + { url = "https://files.pythonhosted.org/packages/24/a4/52a697158e9920705bdbd0748d59fa63e0f3233fb92e9df9a71afbead6ca/rignore-0.7.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42de84b0289d478d30ceb7ae59023f7b0527786a9a5b490830e080f0e4ea5aeb", size = 1078181, upload-time = "2025-11-05T21:40:18.151Z" }, + { url = "https://files.pythonhosted.org/packages/ac/65/aa76dbcdabf3787a6f0fd61b5cc8ed1e88580590556d6c0207960d2384bb/rignore-0.7.6-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:875a617e57b53b4acbc5a91de418233849711c02e29cc1f4f9febb2f928af013", size = 1139232, upload-time = "2025-11-05T21:40:35.966Z" }, + { url = "https://files.pythonhosted.org/packages/08/44/31b31a49b3233c6842acc1c0731aa1e7fb322a7170612acf30327f700b44/rignore-0.7.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8703998902771e96e49968105207719f22926e4431b108450f3f430b4e268b7c", size = 1117349, upload-time = "2025-11-05T21:40:53.013Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ae/1b199a2302c19c658cf74e5ee1427605234e8c91787cfba0015f2ace145b/rignore-0.7.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:602ef33f3e1b04c1e9a10a3c03f8bc3cef2d2383dcc250d309be42b49923cabc", size = 1127702, upload-time = "2025-11-05T21:41:10.881Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d3/18210222b37e87e36357f7b300b7d98c6dd62b133771e71ae27acba83a4f/rignore-0.7.6-cp314-cp314t-win32.whl", hash = "sha256:c1d8f117f7da0a4a96a8daef3da75bc090e3792d30b8b12cfadc240c631353f9", size = 647033, upload-time = "2025-11-05T21:42:00.095Z" }, + { url = "https://files.pythonhosted.org/packages/3e/87/033eebfbee3ec7d92b3bb1717d8f68c88e6fc7de54537040f3b3a405726f/rignore-0.7.6-cp314-cp314t-win_amd64.whl", hash = "sha256:ca36e59408bec81de75d307c568c2d0d410fb880b1769be43611472c61e85c96", size = 725647, upload-time = "2025-11-05T21:41:44.449Z" }, + { url = "https://files.pythonhosted.org/packages/79/62/b88e5879512c55b8ee979c666ee6902adc4ed05007226de266410ae27965/rignore-0.7.6-cp314-cp314t-win_arm64.whl", hash = "sha256:b83adabeb3e8cf662cabe1931b83e165b88c526fa6af6b3aa90429686e474896", size = 656035, upload-time = "2025-11-05T21:41:31.13Z" }, +] + +[[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 = "sentry-sdk" +version = "2.48.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/f0/0e9dc590513d5e742d7799e2038df3a05167cba084c6ca4f3cdd75b55164/sentry_sdk-2.48.0.tar.gz", hash = "sha256:5213190977ff7fdff8a58b722fb807f8d5524a80488626ebeda1b5676c0c1473", size = 384828, upload-time = "2025-12-16T14:55:41.722Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/19/8d77f9992e5cbfcaa9133c3bf63b4fbbb051248802e1e803fed5c552fbb2/sentry_sdk-2.48.0-py2.py3-none-any.whl", hash = "sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172", size = 414555, upload-time = "2025-12-16T14:55:40.152Z" }, +] + +[[package]] +name = "service-explorer-backend" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "aiohttp" }, + { name = "asyncpg" }, + { name = "azure-identity" }, + { name = "azure-storage-blob" }, + { name = "bcrypt" }, + { name = "dotenv" }, + { name = "fastapi", extra = ["standard"] }, + { name = "frontend" }, + { name = "langchain" }, + { name = "langchain-openai" }, + { name = "langfuse" }, + { name = "pandas" }, + { name = "passlib" }, + { name = "pdf2image" }, + { name = "psycopg2" }, + { name = "pymupdf" }, + { name = "pypdf" }, + { name = "pypdf2" }, + { name = "pytesseract" }, + { name = "python-jose", extra = ["cryptography"] }, + { name = "pytz" }, + { name = "sqlalchemy" }, + { name = "uvicorn" }, +] + +[package.metadata] +requires-dist = [ + { name = "aiohttp", specifier = ">=3.13.2" }, + { name = "asyncpg", specifier = ">=0.31.0" }, + { name = "azure-identity", specifier = ">=1.25.1" }, + { name = "azure-storage-blob", specifier = ">=12.20.0" }, + { name = "bcrypt", specifier = "==3.2.2" }, + { name = "dotenv", specifier = ">=0.9.9" }, + { name = "fastapi", extras = ["standard"], specifier = ">=0.127.0" }, + { name = "frontend", specifier = ">=0.0.3" }, + { name = "langchain", specifier = ">=1.2.0" }, + { name = "langchain-openai", specifier = ">=1.1.6" }, + { name = "langfuse", specifier = "==2.33.0" }, + { name = "pandas", specifier = ">=2.3.3" }, + { name = "passlib", specifier = "==1.7.4" }, + { name = "pdf2image", specifier = ">=1.17.0" }, + { name = "psycopg2", specifier = ">=2.9.11" }, + { name = "pymupdf", specifier = ">=1.26.7" }, + { name = "pypdf", specifier = ">=6.5.0" }, + { name = "pypdf2", specifier = ">=3.0.1" }, + { name = "pytesseract", specifier = ">=0.3.13" }, + { name = "python-jose", extras = ["cryptography"], specifier = ">=3.5.0" }, + { name = "pytz", specifier = ">=2025.2" }, + { name = "sqlalchemy", specifier = ">=2.0.45" }, + { name = "uvicorn", specifier = ">=0.40.0" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.45" +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/be/f9/5e4491e5ccf42f5d9cfc663741d261b3e6e1683ae7812114e7636409fcc6/sqlalchemy-2.0.45.tar.gz", hash = "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88", size = 9869912, upload-time = "2025-12-09T21:05:16.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/c8/7cc5221b47a54edc72a0140a1efa56e0a2730eefa4058d7ed0b4c4357ff8/sqlalchemy-2.0.45-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe187fc31a54d7fd90352f34e8c008cf3ad5d064d08fedd3de2e8df83eb4a1cf", size = 3277082, upload-time = "2025-12-09T22:11:06.167Z" }, + { url = "https://files.pythonhosted.org/packages/0e/50/80a8d080ac7d3d321e5e5d420c9a522b0aa770ec7013ea91f9a8b7d36e4a/sqlalchemy-2.0.45-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:672c45cae53ba88e0dad74b9027dddd09ef6f441e927786b05bec75d949fbb2e", size = 3293131, upload-time = "2025-12-09T22:13:52.626Z" }, + { url = "https://files.pythonhosted.org/packages/da/4c/13dab31266fc9904f7609a5dc308a2432a066141d65b857760c3bef97e69/sqlalchemy-2.0.45-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:470daea2c1ce73910f08caf10575676a37159a6d16c4da33d0033546bddebc9b", size = 3225389, upload-time = "2025-12-09T22:11:08.093Z" }, + { url = "https://files.pythonhosted.org/packages/74/04/891b5c2e9f83589de202e7abaf24cd4e4fa59e1837d64d528829ad6cc107/sqlalchemy-2.0.45-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9c6378449e0940476577047150fd09e242529b761dc887c9808a9a937fe990c8", size = 3266054, upload-time = "2025-12-09T22:13:54.262Z" }, + { url = "https://files.pythonhosted.org/packages/f1/24/fc59e7f71b0948cdd4cff7a286210e86b0443ef1d18a23b0d83b87e4b1f7/sqlalchemy-2.0.45-cp313-cp313-win32.whl", hash = "sha256:4b6bec67ca45bc166c8729910bd2a87f1c0407ee955df110d78948f5b5827e8a", size = 2110299, upload-time = "2025-12-09T21:39:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c5/d17113020b2d43073412aeca09b60d2009442420372123b8d49cc253f8b8/sqlalchemy-2.0.45-cp313-cp313-win_amd64.whl", hash = "sha256:afbf47dc4de31fa38fd491f3705cac5307d21d4bb828a4f020ee59af412744ee", size = 2136264, upload-time = "2025-12-09T21:39:36.801Z" }, + { url = "https://files.pythonhosted.org/packages/3d/8d/bb40a5d10e7a5f2195f235c0b2f2c79b0bf6e8f00c0c223130a4fbd2db09/sqlalchemy-2.0.45-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83d7009f40ce619d483d26ac1b757dfe3167b39921379a8bd1b596cf02dab4a6", size = 3521998, upload-time = "2025-12-09T22:13:28.622Z" }, + { url = "https://files.pythonhosted.org/packages/75/a5/346128b0464886f036c039ea287b7332a410aa2d3fb0bb5d404cb8861635/sqlalchemy-2.0.45-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d8a2ca754e5415cde2b656c27900b19d50ba076aa05ce66e2207623d3fe41f5a", size = 3473434, upload-time = "2025-12-09T22:13:30.188Z" }, + { url = "https://files.pythonhosted.org/packages/cc/64/4e1913772646b060b025d3fc52ce91a58967fe58957df32b455de5a12b4f/sqlalchemy-2.0.45-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f46ec744e7f51275582e6a24326e10c49fbdd3fc99103e01376841213028774", size = 3272404, upload-time = "2025-12-09T22:11:09.662Z" }, + { url = "https://files.pythonhosted.org/packages/b3/27/caf606ee924282fe4747ee4fd454b335a72a6e018f97eab5ff7f28199e16/sqlalchemy-2.0.45-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:883c600c345123c033c2f6caca18def08f1f7f4c3ebeb591a63b6fceffc95cce", size = 3277057, upload-time = "2025-12-09T22:13:56.213Z" }, + { url = "https://files.pythonhosted.org/packages/85/d0/3d64218c9724e91f3d1574d12eb7ff8f19f937643815d8daf792046d88ab/sqlalchemy-2.0.45-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2c0b74aa79e2deade948fe8593654c8ef4228c44ba862bb7c9585c8e0db90f33", size = 3222279, upload-time = "2025-12-09T22:11:11.1Z" }, + { url = "https://files.pythonhosted.org/packages/24/10/dd7688a81c5bc7690c2a3764d55a238c524cd1a5a19487928844cb247695/sqlalchemy-2.0.45-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a420169cef179d4c9064365f42d779f1e5895ad26ca0c8b4c0233920973db74", size = 3244508, upload-time = "2025-12-09T22:13:57.932Z" }, + { url = "https://files.pythonhosted.org/packages/aa/41/db75756ca49f777e029968d9c9fee338c7907c563267740c6d310a8e3f60/sqlalchemy-2.0.45-cp314-cp314-win32.whl", hash = "sha256:e50dcb81a5dfe4b7b4a4aa8f338116d127cb209559124f3694c70d6cd072b68f", size = 2113204, upload-time = "2025-12-09T21:39:38.365Z" }, + { url = "https://files.pythonhosted.org/packages/89/a2/0e1590e9adb292b1d576dbcf67ff7df8cf55e56e78d2c927686d01080f4b/sqlalchemy-2.0.45-cp314-cp314-win_amd64.whl", hash = "sha256:4748601c8ea959e37e03d13dcda4a44837afcd1b21338e637f7c935b8da06177", size = 2138785, upload-time = "2025-12-09T21:39:39.503Z" }, + { url = "https://files.pythonhosted.org/packages/42/39/f05f0ed54d451156bbed0e23eb0516bcad7cbb9f18b3bf219c786371b3f0/sqlalchemy-2.0.45-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd337d3526ec5298f67d6a30bbbe4ed7e5e68862f0bf6dd21d289f8d37b7d60b", size = 3522029, upload-time = "2025-12-09T22:13:32.09Z" }, + { url = "https://files.pythonhosted.org/packages/54/0f/d15398b98b65c2bce288d5ee3f7d0a81f77ab89d9456994d5c7cc8b2a9db/sqlalchemy-2.0.45-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9a62b446b7d86a3909abbcd1cd3cc550a832f99c2bc37c5b22e1925438b9367b", size = 3475142, upload-time = "2025-12-09T22:13:33.739Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672, upload-time = "2025-12-09T21:54:52.608Z" }, +] + +[[package]] +name = "starlette" +version = "0.50.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, +] + +[[package]] +name = "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 = "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/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 = "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 = "typer" +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/30/ff9ede605e3bd086b4dd842499814e128500621f7951ca1e5ce84bbf61b1/typer-0.21.0.tar.gz", hash = "sha256:c87c0d2b6eee3b49c5c64649ec92425492c14488096dfbc8a0c2799b2f6f9c53", size = 106781, upload-time = "2025-12-25T09:54:53.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/e4/5ebc1899d31d2b1601b32d21cfb4bba022ae6fce323d365f0448031b1660/typer-0.21.0-py3-none-any.whl", hash = "sha256:c79c01ca6b30af9fd48284058a7056ba0d3bf5cf10d0ff3d0c5b11b68c258ac6", size = 47109, upload-time = "2025-12-25T09:54:51.918Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" }, +] + +[[package]] +name = "uuid-utils" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/0e/512fb221e4970c2f75ca9dae412d320b7d9ddc9f2b15e04ea8e44710396c/uuid_utils-0.12.0.tar.gz", hash = "sha256:252bd3d311b5d6b7f5dfce7a5857e27bb4458f222586bb439463231e5a9cbd64", size = 20889, upload-time = "2025-12-01T17:29:55.494Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/43/de5cd49a57b6293b911b6a9a62fc03e55db9f964da7d5882d9edbee1e9d2/uuid_utils-0.12.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:3b9b30707659292f207b98f294b0e081f6d77e1fbc760ba5b41331a39045f514", size = 603197, upload-time = "2025-12-01T17:29:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/02/fa/5fd1d8c9234e44f0c223910808cde0de43bb69f7df1349e49b1afa7f2baa/uuid_utils-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:add3d820c7ec14ed37317375bea30249699c5d08ff4ae4dbee9fc9bce3bfbf65", size = 305168, upload-time = "2025-12-01T17:29:31.384Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c6/8633ac9942bf9dc97a897b5154e5dcffa58816ec4dd780b3b12b559ff05c/uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8fce83ecb3b16af29c7809669056c4b6e7cc912cab8c6d07361645de12dd79", size = 340580, upload-time = "2025-12-01T17:29:32.362Z" }, + { url = "https://files.pythonhosted.org/packages/f3/88/8a61307b04b4da1c576373003e6d857a04dade52ab035151d62cb84d5cb5/uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec921769afcb905035d785582b0791d02304a7850fbd6ce924c1a8976380dfc6", size = 346771, upload-time = "2025-12-01T17:29:33.708Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fb/aab2dcf94b991e62aa167457c7825b9b01055b884b888af926562864398c/uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f3b060330f5899a92d5c723547dc6a95adef42433e9748f14c66859a7396664", size = 474781, upload-time = "2025-12-01T17:29:35.237Z" }, + { url = "https://files.pythonhosted.org/packages/5a/7a/dbd5e49c91d6c86dba57158bbfa0e559e1ddf377bb46dcfd58aea4f0d567/uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:908dfef7f0bfcf98d406e5dc570c25d2f2473e49b376de41792b6e96c1d5d291", size = 343685, upload-time = "2025-12-01T17:29:36.677Z" }, + { url = "https://files.pythonhosted.org/packages/1a/19/8c4b1d9f450159733b8be421a4e1fb03533709b80ed3546800102d085572/uuid_utils-0.12.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c6a24148926bd0ca63e8a2dabf4cc9dc329a62325b3ad6578ecd60fbf926506", size = 366482, upload-time = "2025-12-01T17:29:37.979Z" }, + { url = "https://files.pythonhosted.org/packages/82/43/c79a6e45687647f80a159c8ba34346f287b065452cc419d07d2212d38420/uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:64a91e632669f059ef605f1771d28490b1d310c26198e46f754e8846dddf12f4", size = 523132, upload-time = "2025-12-01T17:29:39.293Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a2/b2d75a621260a40c438aa88593827dfea596d18316520a99e839f7a5fb9d/uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:93c082212470bb4603ca3975916c205a9d7ef1443c0acde8fbd1e0f5b36673c7", size = 614218, upload-time = "2025-12-01T17:29:40.315Z" }, + { url = "https://files.pythonhosted.org/packages/13/6b/ba071101626edd5a6dabf8525c9a1537ff3d885dbc210540574a03901fef/uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:431b1fb7283ba974811b22abd365f2726f8f821ab33f0f715be389640e18d039", size = 546241, upload-time = "2025-12-01T17:29:41.656Z" }, + { url = "https://files.pythonhosted.org/packages/01/12/9a942b81c0923268e6d85bf98d8f0a61fcbcd5e432fef94fdf4ce2ef8748/uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2ffd7838c40149100299fa37cbd8bab5ee382372e8e65a148002a37d380df7c8", size = 511842, upload-time = "2025-12-01T17:29:43.107Z" }, + { url = "https://files.pythonhosted.org/packages/a9/a7/c326f5163dd48b79368b87d8a05f5da4668dd228a3f5ca9d79d5fee2fc40/uuid_utils-0.12.0-cp39-abi3-win32.whl", hash = "sha256:487f17c0fee6cbc1d8b90fe811874174a9b1b5683bf2251549e302906a50fed3", size = 179088, upload-time = "2025-12-01T17:29:44.492Z" }, + { url = "https://files.pythonhosted.org/packages/38/92/41c8734dd97213ee1d5ae435cf4499705dc4f2751e3b957fd12376f61784/uuid_utils-0.12.0-cp39-abi3-win_amd64.whl", hash = "sha256:9598e7c9da40357ae8fffc5d6938b1a7017f09a1acbcc95e14af8c65d48c655a", size = 183003, upload-time = "2025-12-01T17:29:45.47Z" }, + { url = "https://files.pythonhosted.org/packages/c9/f9/52ab0359618987331a1f739af837d26168a4b16281c9c3ab46519940c628/uuid_utils-0.12.0-cp39-abi3-win_arm64.whl", hash = "sha256:c9bea7c5b2aa6f57937ebebeee4d4ef2baad10f86f1b97b58a3f6f34c14b4e84", size = 182975, upload-time = "2025-12-01T17:29:46.444Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, + { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, + { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" }, + { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/60249e9fd07b32c665192cec7af29e06c7cd96fa1d08b84f012a56a0b38e/uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25", size = 4292101, upload-time = "2025-10-16T22:16:49.318Z" }, + { url = "https://files.pythonhosted.org/packages/02/62/67d382dfcb25d0a98ce73c11ed1a6fba5037a1a1d533dcbb7cab033a2636/uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6", size = 4114158, upload-time = "2025-10-16T22:16:50.517Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/f1171b4a882a5d13c8b7576f348acfe6074d72eaf52cccef752f748d4a9f/uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079", size = 4177360, upload-time = "2025-10-16T22:16:52.646Z" }, + { url = "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289", size = 1454790, upload-time = "2025-10-16T22:16:54.355Z" }, + { url = "https://files.pythonhosted.org/packages/d4/31/0bb232318dd838cad3fa8fb0c68c8b40e1145b32025581975e18b11fab40/uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3", size = 796783, upload-time = "2025-10-16T22:16:55.906Z" }, + { url = "https://files.pythonhosted.org/packages/42/38/c9b09f3271a7a723a5de69f8e237ab8e7803183131bc57c890db0b6bb872/uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c", size = 4647548, upload-time = "2025-10-16T22:16:57.008Z" }, + { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" }, + { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, + { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, + { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, + { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, + { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, + { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, + { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, + { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, + { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, + { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, + { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, + { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, + { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, + { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" }, + { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" }, + { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" }, + { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" }, + { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" }, + { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" }, + { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" }, + { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" }, + { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" }, + { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" }, + { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" }, + { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, + { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, + { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, +] + +[[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/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 = "wrapt" +version = "1.17.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, + { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, + { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, + { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, + { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163, upload-time = "2025-08-12T05:52:40.965Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963, upload-time = "2025-08-12T05:52:20.326Z" }, + { url = "https://files.pythonhosted.org/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945, upload-time = "2025-08-12T05:52:21.581Z" }, + { url = "https://files.pythonhosted.org/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857, upload-time = "2025-08-12T05:52:43.043Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178, upload-time = "2025-08-12T05:53:12.605Z" }, + { url = "https://files.pythonhosted.org/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310, upload-time = "2025-08-12T05:53:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266, upload-time = "2025-08-12T05:52:56.531Z" }, + { url = "https://files.pythonhosted.org/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544, upload-time = "2025-08-12T05:51:51.109Z" }, + { url = "https://files.pythonhosted.org/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283, upload-time = "2025-08-12T05:51:39.912Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366, upload-time = "2025-08-12T05:52:00.693Z" }, + { url = "https://files.pythonhosted.org/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571, upload-time = "2025-08-12T05:52:44.521Z" }, + { url = "https://files.pythonhosted.org/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094, upload-time = "2025-08-12T05:52:22.618Z" }, + { url = "https://files.pythonhosted.org/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659, upload-time = "2025-08-12T05:52:24.057Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946, upload-time = "2025-08-12T05:52:45.976Z" }, + { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, + { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, + { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, +] + +[[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/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/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 = "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/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" }, +]