Compare commits

...

35 Commits

Author SHA1 Message Date
c686b292dc Update applications
Some checks failed
Linting / YAML Lint (push) Successful in 11s
Linting / Ansible Lint (push) Failing after 33s
Authelia: 4.39.16
Dozzle: 10.1.2
Gitea: 1.25.5
Outline: 1.6.1
2026-03-23 19:31:59 +03:00
fb87cf77b2 Update applications
Some checks failed
Linting / YAML Lint (push) Successful in 11s
Linting / Ansible Lint (push) Failing after 32s
2026-03-11 09:51:23 +03:00
4e467d0f9b Homepage: release homepage-nginx:531c1cd-1772885069 2026-03-07 15:04:32 +03:00
b44ec03b7b Homepage: release homepage-nginx:ec0ae72-1772876870 2026-03-07 12:47:54 +03:00
ebfcc1d3ab Homepage: release homepage-nginx:8beca48-1772876712 2026-03-07 12:45:16 +03:00
9183bbc58b Homepage: release homepage-nginx:8beca48-1772875094 2026-03-07 12:18:18 +03:00
6005cbaae8 Homepage: release homepage-nginx:7a02272-1772874721 2026-03-07 12:12:04 +03:00
b839b2787f Homepage: release homepage-nginx:7392ce4-1772873114 2026-03-07 11:45:17 +03:00
c714971595 Homepage: release homepage-nginx:9db0e5d-1772872682 2026-03-07 11:38:05 +03:00
7c02f5f22a Homepage: release homepage-nginx:9db0e5d-1772872520 2026-03-07 11:35:24 +03:00
c9440c8d50 Homepage: release homepage-nginx:0e571f3-1772872290 2026-03-07 11:31:33 +03:00
b5ebfeee39 Homepage: release homepage-nginx:0e571f3-1772872254 2026-03-07 11:31:01 +03:00
96f5e11bbc Homepage: release homepage-nginx:0e571f3-1772872217 2026-03-07 11:30:20 +03:00
c16131e773 Homepage: release homepage-nginx:0e571f3-1772872152 2026-03-07 11:29:15 +03:00
6350a1112d Add zellij
Some checks failed
Linting / YAML Lint (push) Successful in 11s
Linting / Ansible Lint (push) Failing after 35s
2026-03-04 20:17:35 +03:00
f3b888853e Remove old s3 connections for gramps and outline
Some checks failed
Linting / YAML Lint (push) Successful in 41s
Linting / Ansible Lint (push) Failing after 1m0s
2026-03-01 12:24:14 +03:00
2709547958 Dozzle: update to 10.0.5
Some checks failed
Linting / YAML Lint (push) Successful in 10s
Linting / Ansible Lint (push) Failing after 31s
2026-02-27 10:32:13 +03:00
988730c798 Memos: update to 0.26.2
Some checks failed
Linting / YAML Lint (push) Successful in 10s
Linting / Ansible Lint (push) Failing after 32s
2026-02-23 17:13:45 +03:00
ae3f925777 Remove Taskfile.yml 2026-02-22 20:55:24 +03:00
b13cc65a14 Improve pl task
Some checks failed
Linting / YAML Lint (push) Successful in 9s
Linting / Ansible Lint (push) Failing after 28s
2026-02-22 20:55:01 +03:00
b793b7806b Migrate from task to invoke 2026-02-22 18:41:29 +03:00
d6be9fbfb8 Add invoke as task runner, ruff and fix mypy errors 2026-02-22 18:33:59 +03:00
527ca62cb2 Remembos: update to 0.1.5
Some checks failed
Linting / YAML Lint (push) Successful in 10s
Linting / Ansible Lint (push) Failing after 31s
2026-02-22 12:36:24 +03:00
c492e6f697 Dozzle: update to 10.0.4 2026-02-22 12:36:05 +03:00
d46b44bc70 Transcriber: update speech kit api key
Some checks failed
Linting / YAML Lint (push) Successful in 9s
Linting / Ansible Lint (push) Failing after 28s
2026-02-18 10:52:02 +03:00
e0ffb8636d Dozzle: update to 10.0.2
Some checks failed
Linting / YAML Lint (push) Successful in 10s
Linting / Ansible Lint (push) Failing after 31s
2026-02-18 09:52:04 +03:00
5ccee8e0a1 Outline: update to 1.5.0 2026-02-18 09:51:43 +03:00
a66b5fdc3d Netdada: update to 2.9.0 2026-02-18 09:51:25 +03:00
dad43879b2 Remembos: update to 0.1.4
Some checks failed
Linting / YAML Lint (push) Successful in 10s
Linting / Ansible Lint (push) Failing after 32s
2026-02-13 10:22:26 +03:00
3880aefdfd Remembos: update to 0.1.1 2026-02-12 20:43:50 +03:00
254edf1e45 Remembos: install app 2026-02-12 20:27:10 +03:00
e427422253 Dozzle: update to 10.0.0
Some checks failed
Linting / YAML Lint (push) Successful in 11s
Linting / Ansible Lint (push) Failing after 31s
2026-02-11 09:35:42 +03:00
516497c8fd Memos: update to 0.26.1
Some checks failed
Linting / YAML Lint (push) Successful in 10s
Linting / Ansible Lint (push) Failing after 33s
2026-02-08 19:59:42 +03:00
670d830e03 Calibre: update to 0.6.26
Some checks failed
Linting / YAML Lint (push) Successful in 10s
Linting / Ansible Lint (push) Failing after 32s
2026-02-07 10:29:13 +03:00
b47826feb4 Memos: canary version with bug fixes 2026-02-07 10:28:43 +03:00
30 changed files with 901 additions and 320 deletions

1
CLAUDE.md Normal file
View File

@@ -0,0 +1 @@
@AGENTS.md

View File

@@ -1,85 +0,0 @@
# https://taskfile.dev
version: '3'
vars:
USER_ID:
sh: 'id -u'
GROUP_ID:
sh: 'id -g'
HOSTS_FILE: 'production.yml'
REMOTE_USER:
sh: 'yq .ungrouped.hosts.server.ansible_user {{.HOSTS_FILE}}'
REMOTE_HOST:
sh: 'yq .ungrouped.hosts.server.ansible_host {{.HOSTS_FILE}}'
AUTHELIA_DOCKER: 'docker run --rm -v $PWD:/data authelia/authelia:4.39.4 authelia'
tasks:
install-roles:
cmds:
- uv run ansible-galaxy role install --role-file requirements.yml --force
pl:
desc: 'Run playbooks with production inventory'
cmds:
- uv run ansible-playbook -i production.yml --diff {{.CLI_ARGS}}
ssh:
cmds:
- ssh {{.REMOTE_USER}}@{{.REMOTE_HOST}}
btop:
cmds:
- ssh {{.REMOTE_USER}}@{{.REMOTE_HOST}} -t btop
encrypt:
cmds:
- uv run ansible-vault encrypt {{.CLI_ARGS}}
decrypt:
cmds:
- uv run ansible-vault decrypt {{.CLI_ARGS}}
authelia-cli:
cmds:
- "{{.AUTHELIA_DOCKER}} {{.CLI_ARGS}}"
authelia-validate-config:
vars:
DEST_FILE: "temp/configuration.yml"
cmds:
- >
uv run ansible localhost
--module-name template
--args "src=files/authelia/configuration.template.yml dest={{.DEST_FILE}}"
--extra-vars "@vars/secrets.yml"
--extra-vars "@files/authelia/secrets.yml"
- defer: rm -f {{.DEST_FILE}}
- >
{{.AUTHELIA_DOCKER}}
validate-config --config /data/{{.DEST_FILE}}
authelia-gen-random-string:
summary: |
Generate random string.
Usage example:
task authelia-gen-random-string LEN=64
vars:
LEN: '{{ .LEN | default 10 }}'
cmds:
- >
{{.AUTHELIA_DOCKER}}
crypto rand --length {{.LEN}} --charset alphanumeric
authelia-gen-secret-and-hash:
vars:
LEN: '{{ .LEN | default 72 }}'
cmds:
- >
{{.AUTHELIA_DOCKER}}
crypto hash generate pbkdf2 --variant sha512 --random --random.length {{.LEN}} --random.charset rfc3986
format-py-files:
cmds:
- >-
docker run --rm -u {{.USER_ID}}:{{.GROUP_ID}} -v $PWD:/app -w /app pyfound/black:latest_release black .

View File

@@ -735,6 +735,10 @@ access_control:
subject: 'group:admins' subject: 'group:admins'
policy: 'two_factor' policy: 'two_factor'
- domain: 'remembos.vakhrushev.me'
subject: 'group:admins'
policy: 'two_factor'
- domain: 'rssbridge.vakhrushev.me' - domain: 'rssbridge.vakhrushev.me'
subject: 'group:admins' subject: 'group:admins'
policy: 'one_factor' policy: 'one_factor'

View File

@@ -2,7 +2,7 @@ services:
authelia_app: authelia_app:
container_name: 'authelia_app' container_name: 'authelia_app'
image: 'docker.io/authelia/authelia:4.39.14' image: 'docker.io/authelia/authelia:4.39.16'
user: '{{ owner_create_result.uid }}:{{ owner_create_result.group }}' user: '{{ owner_create_result.uid }}:{{ owner_create_result.group }}'
restart: 'unless-stopped' restart: 'unless-stopped'
networks: networks:

View File

@@ -4,6 +4,7 @@ Backup script for all applications
Automatically discovers and runs backup scripts for all users, Automatically discovers and runs backup scripts for all users,
then creates restic backups and sends notifications. then creates restic backups and sends notifications.
""" """
import itertools import itertools
import os import os
import sys import sys
@@ -153,7 +154,7 @@ class ResticStorage(Storage):
class Notifier(ABC): class Notifier(ABC):
def send(self, html_message: str): def send(self, html_message: str) -> None:
raise NotImplementedError() raise NotImplementedError()
@@ -174,7 +175,7 @@ class TelegramNotifier(Notifier):
f"Missing notification configuration values for backend {name}" f"Missing notification configuration values for backend {name}"
) )
def send(self, html_message: str): def send(self, html_message: str) -> None:
url = f"https://api.telegram.org/bot{self.telegram_bot_token}/sendMessage" url = f"https://api.telegram.org/bot{self.telegram_bot_token}/sendMessage"
data = { data = {
"chat_id": self.telegram_chat_id, "chat_id": self.telegram_chat_id,
@@ -358,10 +359,10 @@ class BackupManager:
) )
if self.warnings: if self.warnings:
message += f"\n\n⚠️ Предупреждения:\n" + "\n".join(self.warnings) message += "\n\n⚠️ Предупреждения:\n" + "\n".join(self.warnings)
if self.errors: if self.errors:
message += f"\n\n❌ Ошибки:\n" + "\n".join(self.errors) message += "\n\n❌ Ошибки:\n" + "\n".join(self.errors)
for notificator in self.notifiers: for notificator in self.notifiers:
try: try:
@@ -470,7 +471,7 @@ def initialize(config_path: Path) -> BackupManager:
) )
def main(): def main() -> None:
try: try:
backup_manager = initialize(CONFIG_PATH) backup_manager = initialize(CONFIG_PATH)
success = backup_manager.run_backup_process() success = backup_manager.run_backup_process()

View File

@@ -97,6 +97,19 @@ memos.vakhrushev.me {
} }
remembos.vakhrushev.me { remembos.vakhrushev.me {
tls anwinged@ya.ru
forward_auth authelia_app:9091 {
uri /api/authz/forward-auth
copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
}
reverse_proxy {
to remembos_app:8080
}
}
calibre.vakhrushev.me {
tls anwinged@ya.ru tls anwinged@ya.ru
reverse_proxy { reverse_proxy {

View File

@@ -1,7 +1,7 @@
services: services:
{{ service_name }}: {{ service_name }}:
image: caddy:2.10.2 image: caddy:2.11.2
restart: unless-stopped restart: unless-stopped
container_name: {{ service_name }} container_name: {{ service_name }}
ports: ports:

View File

@@ -1,7 +1,7 @@
services: services:
calibre_web_app: calibre_web_app:
image: lscr.io/linuxserver/calibre-web:0.6.25 image: lscr.io/linuxserver/calibre-web:0.6.26
container_name: calibre_web_app container_name: calibre_web_app
restart: unless-stopped restart: unless-stopped
networks: networks:

View File

@@ -1,7 +1,7 @@
services: services:
dozzle_app: dozzle_app:
image: amir20/dozzle:v9.0.3 image: amir20/dozzle:v10.1.2
container_name: dozzle_app container_name: dozzle_app
restart: unless-stopped restart: unless-stopped
volumes: volumes:

View File

@@ -1,7 +1,7 @@
services: services:
gitea_app: gitea_app:
image: gitea/gitea:1.25.4 image: gitea/gitea:1.25.5
restart: unless-stopped restart: unless-stopped
container_name: gitea_app container_name: gitea_app
ports: ports:

8
files/gramps/gramps_rename.py Executable file → Normal file
View File

@@ -9,7 +9,9 @@ def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Rename Gramps document files by appending extensions from a list." description="Rename Gramps document files by appending extensions from a list."
) )
parser.add_argument("directory", type=Path, help="Directory containing hashed files") parser.add_argument(
"directory", type=Path, help="Directory containing hashed files"
)
parser.add_argument("names_file", type=Path, help="Text file with target names") parser.add_argument("names_file", type=Path, help="Text file with target names")
return parser.parse_args() return parser.parse_args()
@@ -33,7 +35,9 @@ def rename_files(directory: Path, names: list[str]) -> None:
for name in names: for name in names:
hash_part, dot, _ = name.partition(".") hash_part, dot, _ = name.partition(".")
if not dot: if not dot:
print(f"Skipping invalid entry (missing extension): {name}", file=sys.stderr) print(
f"Skipping invalid entry (missing extension): {name}", file=sys.stderr
)
continue continue
source = directory / hash_part source = directory / hash_part

View File

@@ -4,7 +4,7 @@ import os
import argparse import argparse
def main(): def main() -> None:
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Retain specified number of files in a directory sorted by name, delete others." description="Retain specified number of files in a directory sorted by name, delete others."
) )

View File

@@ -3,7 +3,7 @@
services: services:
memos_app: memos_app:
image: neosmemo/memos:0.26.0 image: neosmemo/memos:0.26.2
container_name: memos_app container_name: memos_app
restart: unless-stopped restart: unless-stopped
user: "{{ owner_create_result.uid }}:{{ owner_create_result.group }}" user: "{{ owner_create_result.uid }}:{{ owner_create_result.group }}"

View File

@@ -1,7 +1,7 @@
services: services:
netdata: netdata:
image: netdata/netdata:v2.8.5 image: netdata/netdata:v2.9.0
container_name: netdata container_name: netdata
restart: unless-stopped restart: unless-stopped
cap_add: cap_add:

View File

@@ -3,7 +3,7 @@ services:
# See sample https://github.com/outline/outline/blob/main/.env.sample # See sample https://github.com/outline/outline/blob/main/.env.sample
outline_app: outline_app:
image: outlinewiki/outline:1.4.0 image: outlinewiki/outline:1.6.1
container_name: outline_app container_name: outline_app
user: "{{ owner_create_result.uid }}:{{ owner_create_result.group }}" user: "{{ owner_create_result.uid }}:{{ owner_create_result.group }}"
restart: unless-stopped restart: unless-stopped

View File

@@ -0,0 +1,125 @@
# =============================================================================
# Remembos — конфигурация
# =============================================================================
# Скопируйте этот файл в config.toml и заполните значения.
# =============================================================================
# Подключение к Memos
# =============================================================================
[memos]
# Адрес инстанса Memos, включая протокол.
# Пример: "https://memos.example.com"
url = "http://memos_app:5230"
# Токен доступа к API.
# Создаётся в Memos: Settings → Access Tokens.
token = "{{ remembos_memos_token }}"
# Публичный адрес Memos (для ссылок на оригинальные заметки).
# Если Memos и Remembos развёрнуты на одном сервере, внутренний адрес (url)
# может отличаться от публичного. Если не указан — используется url.
# Пример: "https://memos.example.com"
public_url = "https://memos.vakhrushev.me"
# =============================================================================
# База данных (SQLite)
# =============================================================================
[database]
# Путь к файлу базы данных SQLite.
# В ней хранится история показов и кэш запросов.
# Если файл не существует — будет создан автоматически.
path = "/data/remembos.db"
# =============================================================================
# Алгоритм поиска воспоминаний
# Подробное описание: spec/SEARCH.md
# =============================================================================
[search]
# Минимальное количество дней, прежде чем одна и та же заметка
# может быть показана повторно. Чем больше значение, тем реже
# будут повторяться воспоминания, но при малом количестве заметок
# это может привести к ситуации, когда нечего показать.
cooldown_days = 90
# Ослабленный cooldown: используется как fallback, если с основным
# cooldown не удалось найти ни одного кандидата.
relaxed_cooldown_days = 30
# Максимальное количество заметок, запрашиваемых у Memos за один запрос.
# Влияет на размер пула кандидатов внутри каждого уровня поиска.
page_size = 50
# Насколько далеко в прошлое искать воспоминания (в годах).
# Например, 10 означает поиск заметок за последние 10 лет.
max_years_back = 10
# Предпочитать более старые воспоминания при выборе из кандидатов.
# Если true — заметки из далёкого прошлого получают более высокий вес.
# Если false — все кандидаты внутри уровня равноценны.
prefer_older = true
# Веса уровней поиска (в процентах, сумма должна быть 100).
# Определяют вероятность выбора каждого уровня при поиске.
#
# Tier 1 — точная дата в прошлые годы (самое ценное совпадение)
# Tier 2 — тот же день месяца в прошлые месяцы
# Tier 3 — та же неделя (±3 дня) в прошлые годы
# Tier 4 — тот же месяц в прошлые годы
# Tier 5 — тот же квартал в прошлые годы
# Tier 6 — то же полугодие в прошлые годы
# Tier 7 — недавнее прошлое (от 2 до 6 месяцев назад)
[search.tier_weights]
tier1 = 35
tier2 = 15
tier3 = 15
tier4 = 12
tier5 = 10
tier6 = 5
tier7 = 8
# =============================================================================
# Telegram-бот
# =============================================================================
[telegram]
# Включить Telegram-бот для ежедневной отправки воспоминаний.
enabled = true
# Токен бота, полученный от @BotFather.
token = "{{ remembos_telegram_token }}"
# ID чата, в который бот отправляет воспоминания.
# Можно узнать через @userinfobot или из логов бота при первом сообщении.
chat_id = {{ remembos_telegram_chat_id }}
# Время ежедневной отправки воспоминания (формат HH:MM).
# Используется часовой пояс, указанный в параметре timezone.
send_at = "09:00"
# =============================================================================
# Веб-приложение
# =============================================================================
[web]
# Адрес и порт, на котором запускается веб-сервер.
listen = "0.0.0.0:8080"
# =============================================================================
# Общие настройки
# =============================================================================
[general]
# Часовой пояс для определения «сегодняшнего дня» и времени отправки.
# Формат — IANA (например, "Europe/Moscow", "Asia/Yekaterinburg").
timezone = "Europe/Moscow"
# Уровень логирования: debug, info, warn, error.
log_level = "info"
# Разрешить загрузку дополнительных воспоминаний (кнопка на веб-странице, /more в Telegram).
# Полезно для тестирования. Каждое загруженное воспоминание записывается в историю показов.
allow_load_more = true

View File

@@ -0,0 +1,22 @@
services:
remembos_app:
image: "{{ yc_container_registry_repository }}/remembos:v0.1.5"
container_name: remembos_app
restart: unless-stopped
user: "{{ owner_create_result.uid }}:{{ owner_create_result.group }}"
environment:
- PUID={{ owner_create_result.uid }}
- PGID={{ owner_create_result.group }}
networks:
- "web_proxy_network"
volumes:
- "{{ config_dir }}:/config:ro"
- "{{ data_dir }}:/data"
command:
- "--config"
- "/config/config.toml"
networks:
web_proxy_network:
external: true

View File

@@ -1,44 +1,44 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
33396537353265633634336630353330653337623861373731613734663938633837613437366537 64636264303339643062343231346262316463353562396635623734643763376163383361623135
3439383366633266623463366530626662346338393165630a663539313066663061353635666366 3065326434613532376662343761323339316234356363630a386563613639363332623137653365
61393437393131333166626165306563366661353338363138633239666566313330363331666537 30386363303332333566633737306335336162396366316133653837326264383966653762383037
3763356535396334380a386362383436363732353234333033613133383264643934306432313335 6466333038346436650a343238626637356532376133323464396666643061376363393466663838
34646164323664636532663835306230386633316539373564383163346663376666633564326134 37313235336563643361316339316661356639343933396161333335356332363933656530393634
30666135626637343963383766383836653135633739636261353666303666633566346562643962 34376632326135373864636232616163373738383165326338613037303364323530313766343038
63376165636434343066306539653637343736323437653465656436323533636237643333326438 34366538633062623064626131376261663032666663306339663361663665303866373833646261
35626239323530643066363533323039393237333338316135313838643464306161646635313062 32663931626266663064663066643866356532353363636365633139663930353764386436623539
36386565626435373333393566393831366538363864313737306565343162316536353539333864 66313061393564303737306261383632303063313032613033336130376563386139353835303531
63376264643566613266373665666363366662643262616634333132386535383731396462633430 65623864613639346238663434653361616563626639643437636638396230323232393065663839
32343738343039616139343833366661303430383766376139636434616565356161396433643035 34383737653064343433313364663532363635326165623361303536373136666130306266383237
37363165383935373937346464343738643430333764336264373931616332393964346566636638 61653939326137356139363535353666356265336536393763656136353661636336633231366132
39303434343461326464623363323937396663376335316237373166306134636432376435663033 62303065663233306130316435333364313039366362393762383463313035333034623730643931
34346436623435626363636237373965633139343661623135633764303862353465306235666563 63323035633838303530313361323966346437656366386430316631303637376431396261343166
66653764666635636462636434663264646665383236343166643133613966366334653030653262 31313734643831376633383065373436633136633261373838633662633433363363616162323233
38326437313939616332636638323033346139343732653933356239306132613665376163646164 34666564333637316266623439383934363862336238613436356531373834643262653463326634
30316663643666633334653133613764396165646533636534613931663138666366316235396466 64306530383338613161303138313038393433306430663331343033393832323532376261653838
61313964396264626339306135376635633133366433303033633363396132303938363638346333 33373463636533356134633030393965386131353034323734303934636462363863386231353534
66326466326134313535393831343262363862663065323135643630316431336531373833316363 65303739643338653265313864633632376461373766343536626464303332636332346531303165
64376338653366353031333836643137333736363534363164306331313337353663653961623665 64396363323465393736633937363435663662346136613636643265353830616563623838613632
64626562366637336637353433303261303964633236356162363139396339396136393237643935 65613565363139323431653463363461353666313464656664656331633263333766353666346138
34316266326561663834353762343766363933313463313263393063343562613933393361653861 37366561366262356239366133616266643032636239363238643237383663633433383365626238
38363635323231666438366536626435373365323733663139666534636564623666356436346539 61336632613763616439373730633532316362623663646365303336383531633438323837323939
63326436386436356636633637373738343032353664323736653939346234643165313461643833 32313962313264303435633736346565326438626238356361353264353666643165653535303336
35666439613136396264313033336539313537613238393262306365656238396464373936616538 31633137396465363035373137636162366165323130396631373865393638376335313838396138
64316365616464386638313331653030346330393665353539393834346135643434363736323135 37316263663535376664383764343030623138363137356465316664336564636166313163353566
37663433326439356663633162616435313061353662373766633731636439636266666466613363 30656636626163333138346639323465396531666664396231326136653430343061393234366266
39343930386534376330663230623832643933336235636166626534366664366562356165373764 35386534633131666166353938343066343830613133643833303338656165393439373038336638
63343432323864366162376263656565646661633536666336643030363039616666343063386165 34373436313931666234393530353536353866343330616133653563303764363962333361353639
37343238303034313832393538313632396261316232376635633732656663396631323261363433 61316365373565313865393364356361313063303333303063623435323336316534643937316466
38373738363833323934353739643538376237316535623035383965613965636337646537326537 30633664353131336531336332323862653566363635623965373238313965353434343733303239
64663837643632666334393634323264613139353332306263613165383733386662366333316139 34313836353233653333336130376532386265383762383163386264396231623938616162363861
63373839346265366166333331353231663763306163323063613138323835313831303666306561 64363938366665626666383033356566623765363737643565643964326135666566383866366563
39316666343761303464333535336361333462623363633333383363303134336139356436666165 39643532306134346562346665656431656366383564376135633536313965613738333535376137
62616364373030613837353939363636653537373965613531636130383266643637333233316137 31663566336664373436613866396434623133663361343564623535646462366636616236396661
39353866366239643265366162663031346439663234363935353138323739393337313835313062 34663866323835373438623533353833663261663736646335316564383339343363626264343630
33373263326565383735366364316461323930336437623834356132346633636364313732383661 65346434303763343763383337306463376235663361643037636231323139303239363532303439
66346634613762613037386238656334616430633037343066623463313035646339313638653137 34316133326639623035653532346130633263376531623130616239626433343131333064333632
65643166316664626236633332326136303235623934306462643636373437373630346435633835 35626531353562396462633639653534373537356666343266396565623137306232656633303335
66346364393236393563623032306631396561623263653236393939313333373635303365316638 35316432643633643139616264316636383364316432373533373535323762353035346434343166
66373037333565323733656331636337336665363038353635383531386366633632363031623430 39356266643137663365613832313765376462623032366332363563306536353736333461643930
31356461663438653736316464363231303938653932613561633139316361633461626361383132 38633666333330323433373532313030316130346464616565333265376533303564303638376536
396436303634613135383839396566393135 373863396332313264373733323437303130

3
inv Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
exec uv run inv "$@"

View File

@@ -11,12 +11,16 @@ pre-commit:
- name: "format python" - name: "format python"
glob: "**/*.py" glob: "**/*.py"
run: "black --quiet {staged_files}" run: "uv run ruff format {staged_files}"
stage_fixed: true stage_fixed: true
- name: "check python"
glob: "**/*.py"
run: "uv run ruff check {staged_files}"
- name: "mypy" - name: "mypy"
glob: "**/*.py" glob: "**/*.py"
run: "mypy {staged_files}" run: "uv run mypy {staged_files}"
- name: "yamllint" - name: "yamllint"
glob: "**/*.{yml,yaml}" glob: "**/*.{yml,yaml}"

View File

@@ -23,7 +23,7 @@
ansible.builtin.command: ansible.builtin.command:
cmd: > cmd: >
{{ eget_bin_path }} rclone/rclone --quiet --upgrade-only --to {{ eget_install_dir }} --asset zip {{ eget_bin_path }} rclone/rclone --quiet --upgrade-only --to {{ eget_install_dir }} --asset zip
--tag v1.72.0 --tag v1.73.2
changed_when: false changed_when: false
- name: "Install restic" - name: "Install restic"
@@ -33,11 +33,19 @@
--tag v0.18.1 --tag v0.18.1
changed_when: false changed_when: false
- name: "Install resticprofile"
ansible.builtin.command:
cmd: >
{{ eget_bin_path }} creativeprojects/resticprofile --quiet --upgrade-only --to {{ eget_install_dir }}
--asset '^no_self_update'
--tag v0.32.0
changed_when: false
- name: "Install btop" - name: "Install btop"
ansible.builtin.command: ansible.builtin.command:
cmd: > cmd: >
{{ eget_bin_path }} aristocratos/btop --quiet --upgrade-only --to {{ eget_install_dir }} {{ eget_bin_path }} aristocratos/btop --quiet --upgrade-only --to {{ eget_install_dir }}
--tag v1.4.5 --tag v1.4.6
changed_when: false changed_when: false
- name: "Install gobackup" - name: "Install gobackup"
@@ -51,12 +59,19 @@
ansible.builtin.command: ansible.builtin.command:
cmd: > cmd: >
{{ eget_bin_path }} go-task/task --quiet --upgrade-only --to {{ eget_install_dir }} --asset tar.gz {{ eget_bin_path }} go-task/task --quiet --upgrade-only --to {{ eget_install_dir }} --asset tar.gz
--tag v3.45.5 --tag v3.48.0
changed_when: false changed_when: false
- name: 'Install dust' - name: 'Install dust'
ansible.builtin.command: ansible.builtin.command:
cmd: > cmd: >
{{ bin_prefix }}/eget bootandy/dust --quiet --upgrade-only --to {{ bin_prefix }} --asset gnu {{ eget_bin_path }} bootandy/dust --quiet --upgrade-only --to {{ bin_prefix }} --asset gnu
--tag v1.2.3 --tag v1.2.4
changed_when: false
- name: 'Install zellij'
ansible.builtin.command:
cmd: >
{{ eget_bin_path }} zellij-org/zellij --quiet --upgrade-only --to {{ bin_prefix }} --asset no-web
--tag v0.43.1
changed_when: false changed_when: false

View File

@@ -72,6 +72,7 @@
owner: "{{ app_user }}" owner: "{{ app_user }}"
group: "{{ app_user }}" group: "{{ app_user }}"
mode: "0640" mode: "0640"
register: docker_compose_file_result
- name: "Run application with docker compose" - name: "Run application with docker compose"
community.docker.docker_compose_v2: community.docker.docker_compose_v2:

78
playbook-remembos.yml Normal file
View File

@@ -0,0 +1,78 @@
---
- name: "Configure remembos application"
hosts: all
vars_files:
- vars/secrets.yml
vars:
app_name: "remembos"
app_user: "{{ app_name }}"
app_owner_uid: 1103
app_owner_gid: 1103
base_dir: "{{ (application_dir, app_name) | path_join }}"
config_dir: "{{ (base_dir, 'config') | path_join }}"
data_dir: "{{ (base_dir, 'data') | path_join }}"
config_file: "{{ (config_dir, 'config.toml') | path_join }}"
tasks:
- name: "Create user and environment"
ansible.builtin.import_role:
name: owner
vars:
owner_name: "{{ app_user }}"
owner_uid: "{{ app_owner_uid }}"
owner_gid: "{{ app_owner_gid }}"
owner_extra_groups: ["docker"]
- name: "Create application internal directories"
ansible.builtin.file:
path: "{{ item }}"
state: "directory"
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: "0750"
loop:
- "{{ base_dir }}"
- "{{ data_dir }}"
- "{{ config_dir }}"
- name: "Copy config"
ansible.builtin.template:
src: "./files/{{ app_name }}/config.template.toml"
dest: "{{ config_file }}"
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: "0640"
register: config_file_result
- name: "Copy docker compose file"
ansible.builtin.template:
src: "./files/{{ app_name }}/docker-compose.template.yml"
dest: "{{ base_dir }}/docker-compose.yml"
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: "0640"
register: docker_compose_file_result
- name: 'Login to Yandex Container Registry'
community.docker.docker_login:
registry_url: '{{ yc_container_registry }}'
username: 'oauth'
password: '{{ yc_oauth_token }}'
- name: "Run application with docker compose"
community.docker.docker_compose_v2:
project_src: "{{ base_dir }}"
state: "present"
remove_orphans: true
tags:
- run-app
- name: "Restart docker compose services if config changed but not docker-compose.yml"
community.docker.docker_compose_v2:
project_src: "{{ base_dir }}"
state: "restarted"
when:
- config_file_result.changed
- not docker_compose_file_result.changed

View File

@@ -7,5 +7,10 @@ requires-python = ">=3.12"
dependencies = [ dependencies = [
"ansible>=13.2.0", "ansible>=13.2.0",
"ansible-lint>=25.12.2", "ansible-lint>=25.12.2",
"invoke>=2.2.1",
"mypy>=1.19.1",
"requests>=2.32.5",
"ruff>=0.15.2",
"types-requests>=2.32.4.20260107",
"yamllint>=1.37.1", "yamllint>=1.37.1",
] ]

View File

@@ -39,11 +39,11 @@ TERMINAL = "aws4_request"
VERSION = 0x04 VERSION = 0x04
def sign(key, msg): def sign(key: bytes, msg: str) -> bytes:
return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest() return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()
def calculate_key(secret_access_key): def calculate_key(secret_access_key: str) -> str:
signature = sign(("AWS4" + secret_access_key).encode("utf-8"), DATE) signature = sign(("AWS4" + secret_access_key).encode("utf-8"), DATE)
signature = sign(signature, REGION) signature = sign(signature, REGION)
signature = sign(signature, SERVICE) signature = sign(signature, SERVICE)
@@ -54,7 +54,7 @@ def calculate_key(secret_access_key):
return smtp_password.decode("utf-8") return smtp_password.decode("utf-8")
def main(): def main() -> None:
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
raise Exception("Must be using Python 3") raise Exception("Must be using Python 3")

View File

@@ -16,11 +16,11 @@ import sys
from email.message import EmailMessage from email.message import EmailMessage
def send_test_email(login, password, to_email): def send_test_email(login: str, password: str, to_email: str) -> None:
"""Отправляет тестовое email через Yandex Cloud Postbox SMTP""" """Отправляет тестовое email через Yandex Cloud Postbox SMTP"""
# initialize connection to our email server # initialize connection to our email server
smtp = smtplib.SMTP("postbox.cloud.yandex.net", port="587") smtp = smtplib.SMTP("postbox.cloud.yandex.net", port=587)
smtp.set_debuglevel(2) smtp.set_debuglevel(2)
@@ -43,7 +43,7 @@ def send_test_email(login, password, to_email):
print(f"Test email successfully sent to {to_email}") print(f"Test email successfully sent to {to_email}")
def main(): def main() -> None:
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Send a test email via Yandex Cloud Postbox SMTP server." description="Send a test email via Yandex Cloud Postbox SMTP server."
) )

147
tasks.py Normal file
View File

@@ -0,0 +1,147 @@
#!/usr/bin/env python3
"""Invoke tasks — замена Taskfile.yml"""
import os
import subprocess
import sys
from invoke.context import Context
from invoke.exceptions import Exit
from invoke.tasks import task
HOSTS_FILE = "production.yml"
AUTHELIA_DOCKER = "docker run --rm -v $PWD:/data authelia/authelia:4.39.4 authelia"
def _yq(query: str) -> str:
result = subprocess.run(
["yq", query, HOSTS_FILE], capture_output=True, text=True, check=True
)
return result.stdout.strip()
def _remote_user() -> str:
return _yq(".ungrouped.hosts.server.ansible_user")
def _remote_host() -> str:
return _yq(".ungrouped.hosts.server.ansible_host")
def _rest_args() -> list[str]:
"""Возвращает аргументы после '--' из sys.argv"""
try:
return sys.argv[sys.argv.index("--") + 1 :]
except ValueError:
return []
def _resolve_playbook(name: str) -> str:
candidates = [name, f"{name}.yml", f"playbook-{name}.yml"]
for candidate in candidates:
if os.path.isfile(candidate):
return candidate
raise Exit(
f"Плейбук для '{name}' не найден. Проверял: {', '.join(candidates)}", code=1
)
@task
def install_roles(ctx: Context) -> None:
"""Установить ansible-galaxy roles"""
ctx.run("uv run ansible-galaxy role install --role-file requirements.yml --force")
@task
def pl(ctx: Context) -> None:
"""Запустить плейбуки по имени: inv pl -- gitea miniflux"""
names = _rest_args()
if not names:
raise Exit("Укажи хотя бы один плейбук: inv pl -- <name> [name ...]", code=1)
playbooks = [_resolve_playbook(name) for name in names]
ctx.run(
f"uv run ansible-playbook -i production.yml --diff {' '.join(playbooks)}",
pty=True,
)
@task
def ssh(ctx: Context) -> None:
"""SSH на удалённый сервер"""
subprocess.run(f"ssh {_remote_user()}@{_remote_host()}", shell=True)
@task
def zj(ctx: Context) -> None:
"""Запуск zellij на удаленном сервере"""
subprocess.run(
f"ssh {_remote_user()}@{_remote_host()} -t zellij attach --create main",
shell=True,
)
@task
def btop(ctx: Context) -> None:
"""Запустить btop на удалённом сервере"""
subprocess.run(f"ssh {_remote_user()}@{_remote_host()} -t btop", shell=True)
@task
def encrypt(ctx: Context, file: str) -> None:
"""Зашифровать файлы через ansible-vault"""
ctx.run(f"uv run ansible-vault encrypt {file}")
@task
def decrypt(ctx: Context, file: str) -> None:
"""Расшифровать файлы через ansible-vault"""
ctx.run(f"uv run ansible-vault decrypt {file}")
@task
def authelia_cli(ctx: Context, args: str = "") -> None:
"""Запустить authelia CLI в docker"""
ctx.run(f"{AUTHELIA_DOCKER} {args}")
@task
def authelia_validate_config(ctx: Context) -> None:
"""Отрендерить конфиг authelia из шаблона и проверить его"""
dest = "temp/configuration.yml"
try:
ctx.run(
"uv run ansible localhost"
" --module-name template"
f' --args "src=files/authelia/configuration.template.yml dest={dest}"'
" --extra-vars @vars/secrets.yml"
" --extra-vars @files/authelia/secrets.yml"
)
ctx.run(f"{AUTHELIA_DOCKER} validate-config --config /data/{dest}")
finally:
ctx.run(f"rm -f {dest}", warn=True)
@task
def authelia_gen_random_string(ctx: Context, length: int = 10) -> None:
"""Сгенерировать случайную alphanumeric-строку"""
ctx.run(f"{AUTHELIA_DOCKER} crypto rand --length {length} --charset alphanumeric")
@task
def authelia_gen_secret_and_hash(ctx: Context, length: int = 72) -> None:
"""Сгенерировать случайный секрет и его pbkdf2-sha512 хэш"""
ctx.run(
f"{AUTHELIA_DOCKER} crypto hash generate pbkdf2"
f" --variant sha512 --random --random.length {length} --random.charset rfc3986"
)
@task
def format_py_files(ctx: Context) -> None:
"""Отформатировать Python-файлы через Black в docker"""
uid = os.getuid()
gid = os.getgid()
ctx.run(
f"docker run --rm -u {uid}:{gid} -v $PWD:/app -w /app"
" pyfound/black:latest_release black ."
)

248
uv.lock generated
View File

@@ -128,6 +128,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" }, { url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" },
] ]
[[package]]
name = "certifi"
version = "2026.2.25"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
]
[[package]] [[package]]
name = "cffi" name = "cffi"
version = "2.0.0" version = "2.0.0"
@@ -185,6 +194,63 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
] ]
[[package]]
name = "charset-normalizer"
version = "3.4.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9c/b6/9ee9c1a608916ca5feae81a344dffbaa53b26b90be58cc2159e3332d44ec/charset_normalizer-3.4.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed97c282ee4f994ef814042423a529df9497e3c666dca19be1d4cd1129dc7ade", size = 280976, upload-time = "2026-03-06T06:01:15.276Z" },
{ url = "https://files.pythonhosted.org/packages/f8/d8/a54f7c0b96f1df3563e9190f04daf981e365a9b397eedfdfb5dbef7e5c6c/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0294916d6ccf2d069727d65973c3a1ca477d68708db25fd758dd28b0827cff54", size = 189356, upload-time = "2026-03-06T06:01:16.511Z" },
{ url = "https://files.pythonhosted.org/packages/42/69/2bf7f76ce1446759a5787cb87d38f6a61eb47dbbdf035cfebf6347292a65/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dc57a0baa3eeedd99fafaef7511b5a6ef4581494e8168ee086031744e2679467", size = 206369, upload-time = "2026-03-06T06:01:17.853Z" },
{ url = "https://files.pythonhosted.org/packages/10/9c/949d1a46dab56b959d9a87272482195f1840b515a3380e39986989a893ae/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ed1a9a204f317ef879b32f9af507d47e49cd5e7f8e8d5d96358c98373314fc60", size = 203285, upload-time = "2026-03-06T06:01:19.473Z" },
{ url = "https://files.pythonhosted.org/packages/67/5c/ae30362a88b4da237d71ea214a8c7eb915db3eec941adda511729ac25fa2/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad83b8f9379176c841f8865884f3514d905bcd2a9a3b210eaa446e7d2223e4d", size = 196274, upload-time = "2026-03-06T06:01:20.728Z" },
{ url = "https://files.pythonhosted.org/packages/b2/07/c9f2cb0e46cb6d64fdcc4f95953747b843bb2181bda678dc4e699b8f0f9a/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:a118e2e0b5ae6b0120d5efa5f866e58f2bb826067a646431da4d6a2bdae7950e", size = 184715, upload-time = "2026-03-06T06:01:22.194Z" },
{ url = "https://files.pythonhosted.org/packages/36/64/6b0ca95c44fddf692cd06d642b28f63009d0ce325fad6e9b2b4d0ef86a52/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:754f96058e61a5e22e91483f823e07df16416ce76afa4ebf306f8e1d1296d43f", size = 193426, upload-time = "2026-03-06T06:01:23.795Z" },
{ url = "https://files.pythonhosted.org/packages/50/bc/a730690d726403743795ca3f5bb2baf67838c5fea78236098f324b965e40/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c300cefd9b0970381a46394902cd18eaf2aa00163f999590ace991989dcd0fc", size = 191780, upload-time = "2026-03-06T06:01:25.053Z" },
{ url = "https://files.pythonhosted.org/packages/97/4f/6c0bc9af68222b22951552d73df4532b5be6447cee32d58e7e8c74ecbb7b/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c108f8619e504140569ee7de3f97d234f0fbae338a7f9f360455071ef9855a95", size = 185805, upload-time = "2026-03-06T06:01:26.294Z" },
{ url = "https://files.pythonhosted.org/packages/dd/b9/a523fb9b0ee90814b503452b2600e4cbc118cd68714d57041564886e7325/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d1028de43596a315e2720a9849ee79007ab742c06ad8b45a50db8cdb7ed4a82a", size = 208342, upload-time = "2026-03-06T06:01:27.55Z" },
{ url = "https://files.pythonhosted.org/packages/4d/61/c59e761dee4464050713e50e27b58266cc8e209e518c0b378c1580c959ba/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:19092dde50335accf365cce21998a1c6dd8eafd42c7b226eb54b2747cdce2fac", size = 193661, upload-time = "2026-03-06T06:01:29.051Z" },
{ url = "https://files.pythonhosted.org/packages/1c/43/729fa30aad69783f755c5ad8649da17ee095311ca42024742701e202dc59/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4354e401eb6dab9aed3c7b4030514328a6c748d05e1c3e19175008ca7de84fb1", size = 204819, upload-time = "2026-03-06T06:01:30.298Z" },
{ url = "https://files.pythonhosted.org/packages/87/33/d9b442ce5a91b96fc0840455a9e49a611bbadae6122778d0a6a79683dd31/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a68766a3c58fde7f9aaa22b3786276f62ab2f594efb02d0a1421b6282e852e98", size = 198080, upload-time = "2026-03-06T06:01:31.478Z" },
{ url = "https://files.pythonhosted.org/packages/56/5a/b8b5a23134978ee9885cee2d6995f4c27cc41f9baded0a9685eabc5338f0/charset_normalizer-3.4.5-cp312-cp312-win32.whl", hash = "sha256:1827734a5b308b65ac54e86a618de66f935a4f63a8a462ff1e19a6788d6c2262", size = 132630, upload-time = "2026-03-06T06:01:33.056Z" },
{ url = "https://files.pythonhosted.org/packages/70/53/e44a4c07e8904500aec95865dc3f6464dc3586a039ef0df606eb3ac38e35/charset_normalizer-3.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:728c6a963dfab66ef865f49286e45239384249672cd598576765acc2a640a636", size = 142856, upload-time = "2026-03-06T06:01:34.489Z" },
{ url = "https://files.pythonhosted.org/packages/ea/aa/c5628f7cad591b1cf45790b7a61483c3e36cf41349c98af7813c483fd6e8/charset_normalizer-3.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:75dfd1afe0b1647449e852f4fb428195a7ed0588947218f7ba929f6538487f02", size = 132982, upload-time = "2026-03-06T06:01:35.641Z" },
{ url = "https://files.pythonhosted.org/packages/f5/48/9f34ec4bb24aa3fdba1890c1bddb97c8a4be1bd84ef5c42ac2352563ad05/charset_normalizer-3.4.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac59c15e3f1465f722607800c68713f9fbc2f672b9eb649fe831da4019ae9b23", size = 280788, upload-time = "2026-03-06T06:01:37.126Z" },
{ url = "https://files.pythonhosted.org/packages/0e/09/6003e7ffeb90cc0560da893e3208396a44c210c5ee42efff539639def59b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:165c7b21d19365464e8f70e5ce5e12524c58b48c78c1f5a57524603c1ab003f8", size = 188890, upload-time = "2026-03-06T06:01:38.73Z" },
{ url = "https://files.pythonhosted.org/packages/42/1e/02706edf19e390680daa694d17e2b8eab4b5f7ac285e2a51168b4b22ee6b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:28269983f25a4da0425743d0d257a2d6921ea7d9b83599d4039486ec5b9f911d", size = 206136, upload-time = "2026-03-06T06:01:40.016Z" },
{ url = "https://files.pythonhosted.org/packages/c7/87/942c3def1b37baf3cf786bad01249190f3ca3d5e63a84f831e704977de1f/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d27ce22ec453564770d29d03a9506d449efbb9fa13c00842262b2f6801c48cce", size = 202551, upload-time = "2026-03-06T06:01:41.522Z" },
{ url = "https://files.pythonhosted.org/packages/94/0a/af49691938dfe175d71b8a929bd7e4ace2809c0c5134e28bc535660d5262/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0625665e4ebdddb553ab185de5db7054393af8879fb0c87bd5690d14379d6819", size = 195572, upload-time = "2026-03-06T06:01:43.208Z" },
{ url = "https://files.pythonhosted.org/packages/20/ea/dfb1792a8050a8e694cfbde1570ff97ff74e48afd874152d38163d1df9ae/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:c23eb3263356d94858655b3e63f85ac5d50970c6e8febcdde7830209139cc37d", size = 184438, upload-time = "2026-03-06T06:01:44.755Z" },
{ url = "https://files.pythonhosted.org/packages/72/12/c281e2067466e3ddd0595bfaea58a6946765ace5c72dfa3edc2f5f118026/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e6302ca4ae283deb0af68d2fbf467474b8b6aedcd3dab4db187e07f94c109763", size = 193035, upload-time = "2026-03-06T06:01:46.051Z" },
{ url = "https://files.pythonhosted.org/packages/ba/4f/3792c056e7708e10464bad0438a44708886fb8f92e3c3d29ec5e2d964d42/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e51ae7d81c825761d941962450f50d041db028b7278e7b08930b4541b3e45cb9", size = 191340, upload-time = "2026-03-06T06:01:47.547Z" },
{ url = "https://files.pythonhosted.org/packages/e7/86/80ddba897127b5c7a9bccc481b0cd36c8fefa485d113262f0fe4332f0bf4/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:597d10dec876923e5c59e48dbd366e852eacb2b806029491d307daea6b917d7c", size = 185464, upload-time = "2026-03-06T06:01:48.764Z" },
{ url = "https://files.pythonhosted.org/packages/4d/00/b5eff85ba198faacab83e0e4b6f0648155f072278e3b392a82478f8b988b/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5cffde4032a197bd3b42fd0b9509ec60fb70918d6970e4cc773f20fc9180ca67", size = 208014, upload-time = "2026-03-06T06:01:50.371Z" },
{ url = "https://files.pythonhosted.org/packages/c8/11/d36f70be01597fd30850dde8a1269ebc8efadd23ba5785808454f2389bde/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2da4eedcb6338e2321e831a0165759c0c620e37f8cd044a263ff67493be8ffb3", size = 193297, upload-time = "2026-03-06T06:01:51.933Z" },
{ url = "https://files.pythonhosted.org/packages/1a/1d/259eb0a53d4910536c7c2abb9cb25f4153548efb42800c6a9456764649c0/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:65a126fb4b070d05340a84fc709dd9e7c75d9b063b610ece8a60197a291d0adf", size = 204321, upload-time = "2026-03-06T06:01:53.887Z" },
{ url = "https://files.pythonhosted.org/packages/84/31/faa6c5b9d3688715e1ed1bb9d124c384fe2fc1633a409e503ffe1c6398c1/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7a80a9242963416bd81f99349d5f3fce1843c303bd404f204918b6d75a75fd6", size = 197509, upload-time = "2026-03-06T06:01:56.439Z" },
{ url = "https://files.pythonhosted.org/packages/fd/a5/c7d9dd1503ffc08950b3260f5d39ec2366dd08254f0900ecbcf3a6197c7c/charset_normalizer-3.4.5-cp313-cp313-win32.whl", hash = "sha256:f1d725b754e967e648046f00c4facc42d414840f5ccc670c5670f59f83693e4f", size = 132284, upload-time = "2026-03-06T06:01:57.812Z" },
{ url = "https://files.pythonhosted.org/packages/b9/0f/57072b253af40c8aa6636e6de7d75985624c1eb392815b2f934199340a89/charset_normalizer-3.4.5-cp313-cp313-win_amd64.whl", hash = "sha256:e37bd100d2c5d3ba35db9c7c5ba5a9228cbcffe5c4778dc824b164e5257813d7", size = 142630, upload-time = "2026-03-06T06:01:59.062Z" },
{ url = "https://files.pythonhosted.org/packages/31/41/1c4b7cc9f13bd9d369ce3bc993e13d374ce25fa38a2663644283ecf422c1/charset_normalizer-3.4.5-cp313-cp313-win_arm64.whl", hash = "sha256:93b3b2cc5cf1b8743660ce77a4f45f3f6d1172068207c1defc779a36eea6bb36", size = 133254, upload-time = "2026-03-06T06:02:00.281Z" },
{ url = "https://files.pythonhosted.org/packages/43/be/0f0fd9bb4a7fa4fb5067fb7d9ac693d4e928d306f80a0d02bde43a7c4aee/charset_normalizer-3.4.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8197abe5ca1ffb7d91e78360f915eef5addff270f8a71c1fc5be24a56f3e4873", size = 280232, upload-time = "2026-03-06T06:02:01.508Z" },
{ url = "https://files.pythonhosted.org/packages/28/02/983b5445e4bef49cd8c9da73a8e029f0825f39b74a06d201bfaa2e55142a/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2aecdb364b8a1802afdc7f9327d55dad5366bc97d8502d0f5854e50712dbc5f", size = 189688, upload-time = "2026-03-06T06:02:02.857Z" },
{ url = "https://files.pythonhosted.org/packages/d0/88/152745c5166437687028027dc080e2daed6fe11cfa95a22f4602591c42db/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a66aa5022bf81ab4b1bebfb009db4fd68e0c6d4307a1ce5ef6a26e5878dfc9e4", size = 206833, upload-time = "2026-03-06T06:02:05.127Z" },
{ url = "https://files.pythonhosted.org/packages/cb/0f/ebc15c8b02af2f19be9678d6eed115feeeccc45ce1f4b098d986c13e8769/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d77f97e515688bd615c1d1f795d540f32542d514242067adcb8ef532504cb9ee", size = 202879, upload-time = "2026-03-06T06:02:06.446Z" },
{ url = "https://files.pythonhosted.org/packages/38/9c/71336bff6934418dc8d1e8a1644176ac9088068bc571da612767619c97b3/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01a1ed54b953303ca7e310fafe0fe347aab348bd81834a0bcd602eb538f89d66", size = 195764, upload-time = "2026-03-06T06:02:08.763Z" },
{ url = "https://files.pythonhosted.org/packages/b7/95/ce92fde4f98615661871bc282a856cf9b8a15f686ba0af012984660d480b/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:b2d37d78297b39a9eb9eb92c0f6df98c706467282055419df141389b23f93362", size = 183728, upload-time = "2026-03-06T06:02:10.137Z" },
{ url = "https://files.pythonhosted.org/packages/1c/e7/f5b4588d94e747ce45ae680f0f242bc2d98dbd4eccfab73e6160b6893893/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e71bbb595973622b817c042bd943c3f3667e9c9983ce3d205f973f486fec98a7", size = 192937, upload-time = "2026-03-06T06:02:11.663Z" },
{ url = "https://files.pythonhosted.org/packages/f9/29/9d94ed6b929bf9f48bf6ede6e7474576499f07c4c5e878fb186083622716/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cd966c2559f501c6fd69294d082c2934c8dd4719deb32c22961a5ac6db0df1d", size = 192040, upload-time = "2026-03-06T06:02:13.489Z" },
{ url = "https://files.pythonhosted.org/packages/15/d2/1a093a1cf827957f9445f2fe7298bcc16f8fc5e05c1ed2ad1af0b239035e/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d5e52d127045d6ae01a1e821acfad2f3a1866c54d0e837828538fabe8d9d1bd6", size = 184107, upload-time = "2026-03-06T06:02:14.83Z" },
{ url = "https://files.pythonhosted.org/packages/0f/7d/82068ce16bd36135df7b97f6333c5d808b94e01d4599a682e2337ed5fd14/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:30a2b1a48478c3428d047ed9690d57c23038dac838a87ad624c85c0a78ebeb39", size = 208310, upload-time = "2026-03-06T06:02:16.165Z" },
{ url = "https://files.pythonhosted.org/packages/84/4e/4dfb52307bb6af4a5c9e73e482d171b81d36f522b21ccd28a49656baa680/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d8ed79b8f6372ca4254955005830fd61c1ccdd8c0fac6603e2c145c61dd95db6", size = 192918, upload-time = "2026-03-06T06:02:18.144Z" },
{ url = "https://files.pythonhosted.org/packages/08/a4/159ff7da662cf7201502ca89980b8f06acf3e887b278956646a8aeb178ab/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c5af897b45fa606b12464ccbe0014bbf8c09191e0a66aab6aa9d5cf6e77e0c94", size = 204615, upload-time = "2026-03-06T06:02:19.821Z" },
{ url = "https://files.pythonhosted.org/packages/d6/62/0dd6172203cb6b429ffffc9935001fde42e5250d57f07b0c28c6046deb6b/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1088345bcc93c58d8d8f3d783eca4a6e7a7752bbff26c3eee7e73c597c191c2e", size = 197784, upload-time = "2026-03-06T06:02:21.86Z" },
{ url = "https://files.pythonhosted.org/packages/c7/5e/1aab5cb737039b9c59e63627dc8bbc0d02562a14f831cc450e5f91d84ce1/charset_normalizer-3.4.5-cp314-cp314-win32.whl", hash = "sha256:ee57b926940ba00bca7ba7041e665cc956e55ef482f851b9b65acb20d867e7a2", size = 133009, upload-time = "2026-03-06T06:02:23.289Z" },
{ url = "https://files.pythonhosted.org/packages/40/65/e7c6c77d7aaa4c0d7974f2e403e17f0ed2cb0fc135f77d686b916bf1eead/charset_normalizer-3.4.5-cp314-cp314-win_amd64.whl", hash = "sha256:4481e6da1830c8a1cc0b746b47f603b653dadb690bcd851d039ffaefe70533aa", size = 143511, upload-time = "2026-03-06T06:02:26.195Z" },
{ url = "https://files.pythonhosted.org/packages/ba/91/52b0841c71f152f563b8e072896c14e3d83b195c188b338d3cc2e582d1d4/charset_normalizer-3.4.5-cp314-cp314-win_arm64.whl", hash = "sha256:97ab7787092eb9b50fb47fa04f24c75b768a606af1bcba1957f07f128a7219e4", size = 133775, upload-time = "2026-03-06T06:02:27.473Z" },
{ url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" },
]
[[package]] [[package]]
name = "click" name = "click"
version = "8.3.1" version = "8.3.1"
@@ -280,6 +346,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697, upload-time = "2026-01-02T15:33:31.133Z" }, { url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697, upload-time = "2026-01-02T15:33:31.133Z" },
] ]
[[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 = "invoke"
version = "2.2.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/de/bd/b461d3424a24c80490313fd77feeb666ca4f6a28c7e72713e3d9095719b4/invoke-2.2.1.tar.gz", hash = "sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707", size = 304762, upload-time = "2025-10-11T00:36:35.172Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/32/4b/b99e37f88336009971405cbb7630610322ed6fbfa31e1d7ab3fbf3049a2d/invoke-2.2.1-py3-none-any.whl", hash = "sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8", size = 160287, upload-time = "2025-10-11T00:36:33.703Z" },
]
[[package]] [[package]]
name = "jinja2" name = "jinja2"
version = "3.1.6" version = "3.1.6"
@@ -319,6 +403,66 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
] ]
[[package]]
name = "librt"
version = "0.8.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/95/21/d39b0a87ac52fc98f621fb6f8060efb017a767ebbbac2f99fbcbc9ddc0d7/librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a", size = 66516, upload-time = "2026-02-17T16:11:41.604Z" },
{ url = "https://files.pythonhosted.org/packages/69/f1/46375e71441c43e8ae335905e069f1c54febee63a146278bcee8782c84fd/librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9", size = 68634, upload-time = "2026-02-17T16:11:43.268Z" },
{ url = "https://files.pythonhosted.org/packages/0a/33/c510de7f93bf1fa19e13423a606d8189a02624a800710f6e6a0a0f0784b3/librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb", size = 198941, upload-time = "2026-02-17T16:11:44.28Z" },
{ url = "https://files.pythonhosted.org/packages/dd/36/e725903416409a533d92398e88ce665476f275081d0d7d42f9c4951999e5/librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d", size = 209991, upload-time = "2026-02-17T16:11:45.462Z" },
{ url = "https://files.pythonhosted.org/packages/30/7a/8d908a152e1875c9f8eac96c97a480df425e657cdb47854b9efaa4998889/librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7", size = 224476, upload-time = "2026-02-17T16:11:46.542Z" },
{ url = "https://files.pythonhosted.org/packages/a8/b8/a22c34f2c485b8903a06f3fe3315341fe6876ef3599792344669db98fcff/librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440", size = 217518, upload-time = "2026-02-17T16:11:47.746Z" },
{ url = "https://files.pythonhosted.org/packages/79/6f/5c6fea00357e4f82ba44f81dbfb027921f1ab10e320d4a64e1c408d035d9/librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9", size = 225116, upload-time = "2026-02-17T16:11:49.298Z" },
{ url = "https://files.pythonhosted.org/packages/f2/a0/95ced4e7b1267fe1e2720a111685bcddf0e781f7e9e0ce59d751c44dcfe5/librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972", size = 217751, upload-time = "2026-02-17T16:11:50.49Z" },
{ url = "https://files.pythonhosted.org/packages/93/c2/0517281cb4d4101c27ab59472924e67f55e375bc46bedae94ac6dc6e1902/librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921", size = 218378, upload-time = "2026-02-17T16:11:51.783Z" },
{ url = "https://files.pythonhosted.org/packages/43/e8/37b3ac108e8976888e559a7b227d0ceac03c384cfd3e7a1c2ee248dbae79/librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0", size = 241199, upload-time = "2026-02-17T16:11:53.561Z" },
{ url = "https://files.pythonhosted.org/packages/4b/5b/35812d041c53967fedf551a39399271bbe4257e681236a2cf1a69c8e7fa1/librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a", size = 54917, upload-time = "2026-02-17T16:11:54.758Z" },
{ url = "https://files.pythonhosted.org/packages/de/d1/fa5d5331b862b9775aaf2a100f5ef86854e5d4407f71bddf102f4421e034/librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444", size = 62017, upload-time = "2026-02-17T16:11:55.748Z" },
{ url = "https://files.pythonhosted.org/packages/c7/7c/c614252f9acda59b01a66e2ddfd243ed1c7e1deab0293332dfbccf862808/librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d", size = 52441, upload-time = "2026-02-17T16:11:56.801Z" },
{ url = "https://files.pythonhosted.org/packages/c5/3c/f614c8e4eaac7cbf2bbdf9528790b21d89e277ee20d57dc6e559c626105f/librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35", size = 66529, upload-time = "2026-02-17T16:11:57.809Z" },
{ url = "https://files.pythonhosted.org/packages/ab/96/5836544a45100ae411eda07d29e3d99448e5258b6e9c8059deb92945f5c2/librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583", size = 68669, upload-time = "2026-02-17T16:11:58.843Z" },
{ url = "https://files.pythonhosted.org/packages/06/53/f0b992b57af6d5531bf4677d75c44f095f2366a1741fb695ee462ae04b05/librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c", size = 199279, upload-time = "2026-02-17T16:11:59.862Z" },
{ url = "https://files.pythonhosted.org/packages/f3/ad/4848cc16e268d14280d8168aee4f31cea92bbd2b79ce33d3e166f2b4e4fc/librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04", size = 210288, upload-time = "2026-02-17T16:12:00.954Z" },
{ url = "https://files.pythonhosted.org/packages/52/05/27fdc2e95de26273d83b96742d8d3b7345f2ea2bdbd2405cc504644f2096/librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363", size = 224809, upload-time = "2026-02-17T16:12:02.108Z" },
{ url = "https://files.pythonhosted.org/packages/7a/d0/78200a45ba3240cb042bc597d6f2accba9193a2c57d0356268cbbe2d0925/librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0", size = 218075, upload-time = "2026-02-17T16:12:03.631Z" },
{ url = "https://files.pythonhosted.org/packages/af/72/a210839fa74c90474897124c064ffca07f8d4b347b6574d309686aae7ca6/librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012", size = 225486, upload-time = "2026-02-17T16:12:04.725Z" },
{ url = "https://files.pythonhosted.org/packages/a3/c1/a03cc63722339ddbf087485f253493e2b013039f5b707e8e6016141130fa/librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb", size = 218219, upload-time = "2026-02-17T16:12:05.828Z" },
{ url = "https://files.pythonhosted.org/packages/58/f5/fff6108af0acf941c6f274a946aea0e484bd10cd2dc37610287ce49388c5/librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b", size = 218750, upload-time = "2026-02-17T16:12:07.09Z" },
{ url = "https://files.pythonhosted.org/packages/71/67/5a387bfef30ec1e4b4f30562c8586566faf87e47d696768c19feb49e3646/librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d", size = 241624, upload-time = "2026-02-17T16:12:08.43Z" },
{ url = "https://files.pythonhosted.org/packages/d4/be/24f8502db11d405232ac1162eb98069ca49c3306c1d75c6ccc61d9af8789/librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a", size = 54969, upload-time = "2026-02-17T16:12:09.633Z" },
{ url = "https://files.pythonhosted.org/packages/5c/73/c9fdf6cb2a529c1a092ce769a12d88c8cca991194dfe641b6af12fa964d2/librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79", size = 62000, upload-time = "2026-02-17T16:12:10.632Z" },
{ url = "https://files.pythonhosted.org/packages/d3/97/68f80ca3ac4924f250cdfa6e20142a803e5e50fca96ef5148c52ee8c10ea/librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0", size = 52495, upload-time = "2026-02-17T16:12:11.633Z" },
{ url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" },
{ url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" },
{ url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" },
{ url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" },
{ url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" },
{ url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" },
{ url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" },
{ url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" },
{ url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" },
{ url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" },
{ url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" },
{ url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" },
{ url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" },
{ url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" },
{ url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" },
{ url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" },
{ url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" },
{ url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" },
{ url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" },
{ url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" },
{ url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" },
{ url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" },
{ url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" },
{ url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" },
{ url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" },
{ url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" },
]
[[package]] [[package]]
name = "markupsafe" name = "markupsafe"
version = "3.0.3" version = "3.0.3"
@@ -382,6 +526,39 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
] ]
[[package]]
name = "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 = "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/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]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.1.0" version = "1.1.0"
@@ -416,6 +593,11 @@ source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "ansible" }, { name = "ansible" },
{ name = "ansible-lint" }, { name = "ansible-lint" },
{ name = "invoke" },
{ name = "mypy" },
{ name = "requests" },
{ name = "ruff" },
{ name = "types-requests" },
{ name = "yamllint" }, { name = "yamllint" },
] ]
@@ -423,6 +605,11 @@ dependencies = [
requires-dist = [ requires-dist = [
{ name = "ansible", specifier = ">=13.2.0" }, { name = "ansible", specifier = ">=13.2.0" },
{ name = "ansible-lint", specifier = ">=25.12.2" }, { name = "ansible-lint", specifier = ">=25.12.2" },
{ name = "invoke", specifier = ">=2.2.1" },
{ name = "mypy", specifier = ">=1.19.1" },
{ name = "requests", specifier = ">=2.32.5" },
{ name = "ruff", specifier = ">=0.15.2" },
{ name = "types-requests", specifier = ">=2.32.4.20260107" },
{ name = "yamllint", specifier = ">=1.37.1" }, { name = "yamllint", specifier = ">=1.37.1" },
] ]
@@ -513,6 +700,21 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" },
] ]
[[package]]
name = "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]] [[package]]
name = "resolvelib" name = "resolvelib"
version = "1.2.1" version = "1.2.1"
@@ -659,6 +861,31 @@ version = "0.3.7"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/cb/73/2a9857a017f8ee260c683d8155634f0e3ca57964da2c3055b02822d582cd/ruamel_yaml_clibz-0.3.7.tar.gz", hash = "sha256:2be85214793cfc787eb12380fa3226e10cd7727b24551c3067c173d66c9bedd9", size = 231233, upload-time = "2026-01-02T14:52:41.734Z" } sdist = { url = "https://files.pythonhosted.org/packages/cb/73/2a9857a017f8ee260c683d8155634f0e3ca57964da2c3055b02822d582cd/ruamel_yaml_clibz-0.3.7.tar.gz", hash = "sha256:2be85214793cfc787eb12380fa3226e10cd7727b24551c3067c173d66c9bedd9", size = 231233, upload-time = "2026-01-02T14:52:41.734Z" }
[[package]]
name = "ruff"
version = "0.15.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" },
{ url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" },
{ url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" },
{ url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" },
{ url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" },
{ url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" },
{ url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" },
{ url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" },
{ url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" },
{ url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" },
{ url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" },
{ url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" },
{ url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" },
{ url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" },
{ url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" },
{ url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" },
{ url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" },
]
[[package]] [[package]]
name = "subprocess-tee" name = "subprocess-tee"
version = "0.4.2" version = "0.4.2"
@@ -668,6 +895,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4d/ab/e3a3be062cd544b2803760ff707dee38f0b1cb5685b2446de0ec19be28d9/subprocess_tee-0.4.2-py3-none-any.whl", hash = "sha256:21942e976715af4a19a526918adb03a8a27a8edab959f2d075b777e3d78f532d", size = 5249, upload-time = "2024-06-17T19:51:15.949Z" }, { url = "https://files.pythonhosted.org/packages/4d/ab/e3a3be062cd544b2803760ff707dee38f0b1cb5685b2446de0ec19be28d9/subprocess_tee-0.4.2-py3-none-any.whl", hash = "sha256:21942e976715af4a19a526918adb03a8a27a8edab959f2d075b777e3d78f532d", size = 5249, upload-time = "2024-06-17T19:51:15.949Z" },
] ]
[[package]]
name = "types-requests"
version = "2.32.4.20260107"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/a0663907082280664d745929205a89d41dffb29e89a50f753af7d57d0a96/types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f", size = 23165, upload-time = "2026-01-07T03:20:54.091Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl", hash = "sha256:b703fe72f8ce5b31ef031264fe9395cac8f46a04661a79f7ed31a80fb308730d", size = 20676, upload-time = "2026-01-07T03:20:52.929Z" },
]
[[package]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.15.0" version = "4.15.0"
@@ -677,6 +916,15 @@ 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" }, { 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 = "urllib3"
version = "2.6.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
]
[[package]] [[package]]
name = "wcmatch" name = "wcmatch"
version = "10.1" version = "10.1"

View File

@@ -1,2 +1,2 @@
--- ---
homepage_nginx_image: "homepage-nginx:f797e17-1761204003" homepage_nginx_image: "homepage-nginx:531c1cd-1772885069"

View File

@@ -1,162 +1,157 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
35643431306561396237633439336230333563316364353462393534646565653163396362393566 30353464333261353263666333626634633162666239653631386263363431333734656631313930
6636306532353662343437646631363766376166333934340a363062323332386261643832323762 6539363363653239656166623839636131306462633834310a646438626666653163613762313637
33303235646434636636366532626331653865666465643561633863663938313535623162306334 33316565343539376535303135366530386333313562306161633861306237313030386366656435
3332616236326436650a383636393434303165363964383966633138326361373134306563653363 3830353139613066350a666564333832393465316531353863373437646464316262396532383738
37376465643762383761653132636336663762656136303730616463386134346436383539653661 36643034623263643038633162666265646661383461303335653935376330633033653730643235
35623933346565633030373730316331633236623561313166376335636464333439643637623338 38663938333934353131393762363762366333306439396264346565336439653239353034386138
32393433653339656135343766393565366530636132346339306339353438396337303534336266 65343832666363663731656263616263636662323038663835386437306564643265396434393832
34303635316363343031363263626434386139633762353038666266643338343631303530313661 31373231636363656463366436303433616239646331353239363966393264623866636466323839
61373239663739666535636466393937333437316334306631336334303961396134323062666339 61653037396130373763633265666663316666623961643131373564326361653038646530323964
62303437623131626130363838353736386463663734356530333061353031643861636437323431 66383738303230313533653562356535343162633231636634646237663466313031346463393965
62633036316639306366643633333366386132343337313832343133313235626162323266306165 65336164373666343932376234343133623531323163653961666432326134333865336262333336
39326434326235373536633464313234623464373465653061383834363266663435303461633834 63643038636537323039616563613861386566393364306131326463366531363063613766383965
36663031323634326436303138623262396332363934646337353166373163326132626437636138 66353237383734643564626239346662656435386166356161343031343633613331623433366465
38623864666434363939663234623732623962323836323532393031396638343737373764303239 34613237383934343636613833353933613536386637626338326537373438646139623839366263
31316639653066373166326432653930666630393061366461663337333936326239376165633064 31386137636362356339333530626565333561333634613964343133393038663033656433376165
32356530333338303636366234336135353130646134643432613965366430326164393563383135 33323633383237343433636532613965303232306262326237383233656430363030366164643561
63653237646237323832613363643732383436646539396239333632353566386135633961316132 37373930646233366439383635333133393631366265373439643635396231336263373266373338
62313630313065376465346338663661343466366364363761616363376535373031383736616136 33613432616634666531623631356162363364643437623239643536336636396132313232656233
37343634626366356261363030616330396263623965306166386238363039663461396431303733 64333032653930353430336364353335396130633634666131393166383765656362616139396265
61626164353466323762666236376536356364653565333266363730653539626531663639333864 32653563366562383930623439363539333235326661383665336564623832313839306263386232
32366333336234376635616361626635616265376361316439653230646537303031343564653631 61633734353733346266343936306364393835316635633061386661313262386630623933656436
63663237353766643766343130613739386636663534336536353936353561616538316535333064 30633662613937326162666666353339363736373139626133316233383433373665623637326634
62343835643636633831366265313939313433326239633130303863303136363732653766303663 62623165306431363931616335363339383836366363353565366136643661366638343361306438
33643231363761336463623339323831363034636532346237373236656266303063633365393636 36346265383930326461653931626537306431633766653265373266623333643437323533353233
36663066336233643236393837323762393435303665303661356237666237646464326536623731 30336437353739353861316134306361333063336233323437616630386532663934303032356238
64396431323561353832333834336232396366663439643161626338653930633665346566303435 64626335653161313533636539353665656239336237633461346535636539393161643961613464
66636466313936316530353537643637323833653561616339353465323466333332363436613461 30313366323937313265636563333261643732363161323934303463316663313033633831386536
38653837373637343532343662366435616366313831623239343363366131633062303036333135 36313733326133643663353830643936613366653766636638643737323362303537636563336339
36356136376236383431613266663164616135343062666136353430626663653631313064326131 66353930633761396666383138653339343632656232643866376337623732326635373735623362
63353066313433653838613934323833373237356230376363376132306663656461653264383866 38613831356437383865653964656637396137386463316562663464383834323962333465356562
37333863633536346538366665346666346364633733366434393135353664336330623865343132 62343864613364623639336334646462376366356138386162373763353930366663646463303736
31396534643633333134363465323063313435333236646630613066353232613039393235366630 36323165373236643139303935333266323064633230353934343538616332653265373438633564
36646664366339613535616437376437326561636130333063626637316431626330386137306162 62393332383533313564656434366435326362316666623763353563626138643732643531343238
65393533306439613032623061373331333762643336633863333061393734313335386633666338 33313031313366656363343562653763613833653536613562343465376664376562356164613936
31316637643031353462363363626662373462633065653738613733633933623432343535316438 66343763313262636532626363393562316661613130313866346165633862373136393661303936
31356530306263303566636535363465356562633439386365316461323339393339643133323032 38633562663461623133653864306139393165386265313032653231306361393830653763663062
32616662633565346564643737386266623836623830663265323439313762636437336436346430 63383430633734646134303239666532626264613332313136363238323139326237623035623964
65353266373766363166633363636231623031363337626631626466616637616630383632333565 37663435353965383535646331343761383562653735363666666335613630373865643265643336
35303737316531306237613832366565376364313435376266306263623139663964336635633030 32343664666239326337643366306531623834336463386637666564646338333433303134323564
39306662616233646136336237646139326239653435653436323066333332626266646564616631 32323866323337303262363833313838623337323232616135363963363631336637623865373437
31653433663539333633663433643261363065663030373265646533323832323366376230346266 31316539663237316162366338303763346139663435313037306338623339316637363133363965
65616633363938333037656663393334363564626136333162383162663437653565663532646366 62303439383637353333333631363234343866623763616261666239316631353434323930373066
31343063306434663231396464646232353335636138393038633737323339303033373539363739 32613334303566353830323064626537663339373130613533373739616236346337393033316638
64306163343534363131646135396234346166313039323833656636343235656238623333626534 39303462633463306634373933396233666530303465323133386435333563373936623466376334
30653264656166326562343534313063326332336330623530646563313262396233386335316538 39323131353866313263333436303831323166366165623263323730333663616665373261313232
64316363613865313236633437646139353433386234326537633961356133353361333833636339 62333361623964316236303739363430636461396264333638363835646366633633326666326363
65646232336137626130326631626436623933353333383438306237326132303838353833376432 30376339646361386337343561666230313066303263353430333436613464303965353634353831
31653936363131623535386331353066323462613238636130376562376361643166363332343537 35343866396639366539653939313939656234663665666533326630306530333863383761613161
63346366306161373666306536396164323437613066363537366562666130653638356564383235 61376433623635663636656564643135626239343663333532663366353165383463383038353232
66303838616266623335363338376535303665643363326662376166643865383039306236393730 35346437383931653166323431353766393036626136643262623263363932396437303033356131
34303130386631636636393736616237633933346136303530373033383739653531326437656463 31333066393166356665663963306366383837303036373930653462386232373563303630633636
39326239616163313463636232343036626435366261643030386530393763356133663863373264 30363466353437306232383663363161396665393739306536643236663761323366613130656330
62316164386464366663373635393365363161336530313734343633346563396666616262396563 30366661353939303030363833636238346134323738366138396336393463373563333632653262
37383638613930366635623962366662343232303635636330383534653861336264396132653538 39633333353466313339386362656538336338373565323536646333616434626137323335353563
65306539613333306339643063303063333165653734323333353461356536663661613463633632 31636564636537613033656236366362316134353733623961366333313165626637616536646361
61613530653734643761616636386238633535643961633765313863323961313362323265373132 39623561656234356663313032326231313231363963643534666136343433663730333333633434
65346530653962613534343062333039663837623130666261636135343663643036356261643333 35303363366133323330376163363662653534633431333035363837633831343861373633393930
64306430343136616438636231623236316264623533313439643434343333623030376338663365 30626635353166303962313639326239623532396435623230353166323165656261643030356131
36393932613161316137386136343939383035326231323561636337343833613635643261633165 65356632613834653063656138353261613231663465336366623564316165623932663530376631
38316233323862666439633833646235623031336638353834323633333562346463333436316437 31616137386433336135323636613665356162353139306263633833336566346339666135626433
36303237353138353763346166626465663137323062643633323762313137343661323839353231 30336361333736333334383162343336663631663333353739633036346633393763366636353161
38643137383739393866616364386262363733316133313934366165353761643164303439643534 36373566613530366632666333646563336136663034663337313032643165643966303964613234
37633636323535373964323939346339633138386239333466363239393430613139623466643531 38653332343037653464646635666634376138616636326531353865346663396534363338393465
66323662363834653166363835343363303066306262623432353165313239323130616235316264 37393962343233633739313961663531616565363337346535303962663533643866363333353430
65376532623530353935346238346261613062633439333630643962343233326234316130616538 35323864383338313837643266653937316432313834653038636561653238303164626362326432
64353932613038353866383263333561623632663863373231636132653365613836363730636263 61626638636539303135646432643539306566316464383935333535343163393832316561323764
65626666653962653266343134343638666437373532333464633163333861386632356562346637 38373239376363633237346664626137363562303134333563346434396335383235383032653637
62303433383464373165316561646633636130636434633430623031633364643336643835613030 66356138396436623734316139373964373364633937373431386432333263326563326234623936
64653937656262623536353764343661326632303964393862343032343330653534353530326238 62313830613436356337623865373432356165313930373362643037386239303937666637636332
34613236336339653364333565313862613531643763633166363734316363643534323838333531 36666239343336316538623938376538383038386662396662626137633138663766396432353061
36353137653535393862393534303366366464613035376439383134336534366263393661646564 66656665656535303535376161303562643035383961343832373137636335363534393861316332
39616233323638653337333461636465353935613236646430623163656334376463323135323761 63353831616439376663616363363763323838366363396637313931616337633832643061616662
36353064646532323738363837663238653766366634363232323933363033656332626436363166 31663738396162316538343763353330653739303963616530323064373331366433326465326532
36376366336236626265373530646664633335623035646662663261353165313634646463316535 34303437346463366362346532376263356134633838373630323831643432663265313965633964
38633862623433613937666162343936393337336537623663306439373830326434356366323664 63386361303666376162653938346236636434666564623638646161656661393462613237363935
61646337396562373535353834393665643037626539303932663831306535623733626239323939 66346661353735646261333339313638653061636130623963346235376234346138613762643566
61616165643439653235346566346631323035306437323339326665363232333338616133666366 30323831613461383766643836666633636364323139333261303632613730663730336637646233
61396136353432376263333961353738343463663937313136336536623539383835663361353232 37373733373930333735306532663930396331343037383032636461653463353862613362303332
38343737383361613930326265346562356136313539393464623935626566343137346430356261 66663361373030363031396663616638396465313438396230633835633335636664356565316664
62633230396665316533313831346236303265303232363935313138323537373933633232343732 61356632303035366638613762306636333439373534356239626439626465613837336539636532
35346363663938306562663433396138393861343332373934303864303963623739316239303264 61393564613962303938393435306238383761396339656533653265633461666435353133333164
62393634346231393534633861386364336639366663353065333930616335323438383537616666 33316630663131323634343637643435326237666134326534666563623734633634366636623731
63373836363839336634316338643935346634626437326431363132636335326238353930663662 33666536396138393137333761633139323735303039313837366635623037333037663231353338
62383464366263336430633338646263626565393030646230306230353837313965623430636138 61633962643830663038343530643330356137663665663537336564353730323565626135313662
38393334623661363532663464363163383365323736386134393634333332353263353763393636 38646430306638663431373037323061313438666433313264633732303664323634303236356364
35353535303030356665303262333334353630613832323733393638613035343833356662353565 32326131656438656661616638393462333532313737396235643830663832643435373362373533
64373334626565653631613863323866336261393533333639326266343435376666646131313535 34313638626264363561653232323263643135323666626539636435303131336533623137643735
39343734326162623831343730303734643830626338653232633834373565643133393562653336 38333734636133336431393634316566626266356165663639333461306463363637613366643433
35373432316161623061373238333932366161663137616337613632366263373830663464396537 61313031623933633731353533346264363336326534366231366239373137666430376266383836
37303363386336663663303161343963633834623564643661653332623434626466376637323631 33396365343161616238396133326433343535333032643533616439643236323561353236356536
64653265623861363837346462613164373264313766633034353531666561623732353838643639 39663534666533393638376639653161376562636333616437623937383035313032636632396232
37646262646362386331663334666131336335313833313463373463313439353934313733303763 62373961616262313936623663613837316539616330336339363436373465363662313836656662
65626339363732326565366464633230303933386438373539633338363439393630316164376565 31333231653836306362643234383631666431663431666333366563393830343837393339313533
63333132613739663461346361613761396161323863616263333638376437613139353733613963 65343034373265343737326232316162386434326661336530373639633838373766323437393937
32663062393435323061353738316132363438393762316666626231386138366639313566646461 38313962356364306165393730356339336639303731393931323130386462663139353639626338
36306664343433653836316436303736343436343762366133373066313232333834363536343462 30373162356131313737326164393164373837366632643064326635323934396239363033303938
30303866646131663530313463343261633261663932323562636135346664323761343765333730 62376539313164333365336331393735346138376362333962396364323063636539346663613631
39663231636465336361393062666135316534656637306236323137653939383565643637623866 66353062643261666538633430653036636461626161356265303037353665326461333335373562
33633536366163346466303864313732303036306665326664353064366134326539333831663632 62363237356166363139616532333530373230623865383862383362376534363162336163633133
64343533323166623661326536393437623432336435366435396165333431366532653936396636 37636564353836643963613333373837343431346538303738346462663739623932363831353534
30653263306461656230663731336266363832616539373333306238363834333838393063383432 64613934323136623761633830313335306666643765343037363665303733613639343466393963
61343238373861303932653162663330333964623834336235336430376562313963613134353834 62386361326362386535376364303237313564316661326337336434616134313464313565333136
63666537343837336531633536633038666232343165336663356639636537306333303434383231 64663436643939623438366437643034666362386233666238363434613862386333323134363566
64306633383338646362633238386263336632393562623330343532373839663238383965643739 61646661386139393731666632343066366139333638333366336137353833383931383835363934
39313363383331363339616431653434366131303666623263326662636161666635643162663730 35666563303333303932386264316134383035613035663466656465336439346137656336656434
62356136643364666164383932376536623266373535613230336165396163383830346265393738 34363438663962393434633761633336623966636465623665356433343236383862636435303038
30636139353336343630316132366365306234313064636537646262666463646437376336366562 33313661336364346562666234396462646231666162306566636461613462643034653861663439
31663731666664313339353331626534626462663431633530653365613762363666373532383762 39633361643733643533346561363232336465383633396461376239623837366135336238346332
34323866356239383332373632616464666230373339386235393838376333333464613038373337 33373762613230353537656566353466623864636161316361396338613566336132303762306538
33373231386263623664353231626331366565356662623934316632653763363739653862356265 36633663643136303262373365363063396163613464333662653430396636623335313061626561
39653539616232356333326463373666656133303161356630393839336638316338646238623138 38636165346532373732333463373436323239386432326634613762303665343636343366656162
61343833613130376562656465343438653861653431313762313062656563643665356664646465 39613035626133306139663831313236353739313930666339333133663839313932336433353531
33343430663066616536393935366132336666616164356463323663373930653266653238663336 63373966633635336632363137326533363864303466366664656532623362663265613936663636
35616263613461356333633430653661376239663363653434346437656161623961333761633663 32336265393330616437646664333464623635353662616133623264393935303530356330633834
35643031323063666163623639313864313937386339376235653033366136373333653239653238 64626161646366306134303634356138663634396231353064343661373662646132653563656162
36376636653766366632613262326336333430353534326464653931663366383039643466303739 36343864396263343561333137383238393063333634376634656231346238383862313264303263
66393065323965383962633266623033643330333437383262373461363539626333653433356436 66343766353133316337356265343361363931373362303462663935323735393330623632623237
64383738653735386630346264643462353336313830376139353166666330303638386639623039 34636565646461666431313362613862303530343537306563396236663435623164326134326530
34303137623936663636303864623932343766323235653934303263363164326534653137613863 61356566313733363035346530613934376236383136633363316263393761383532393133323939
39353739633466376136343938303634643565613537646166326536303739316536376162353838 38653731643330666261356236623039633262343031393330356565326261336230303132656332
61326235373733623465313530393831623438343530616339326561386239646562343130376336 37353464336365633633643063353237626535326537653131633535306361353165313232366664
63373430313332613561623636393338353933613161656264646366633665373336343530303635 65613966356634633134633563343036323539633036363437626466363865626333376134613731
35336561336334626333343030366264356264343062623531363331313466666136666332376265 31363434373534613239333031333564653733363732343835346435633934356236356166393538
62363862623635376631336235353531343931663131333861616566356438396664633962646236 38613432303032333830633161353938383632313137633437313131653664323934613432356635
61343063383238376261656465386635623263386430656132393631623330326462326166643631 32656661303163646335633137363734323363653330623137613438623831366135393261343833
34333238663531366232393764626665376465386336653133643335656161343261616532386135 61383839623733346434653739626365376266353430363131636665636639333037646262346465
63333931646435373630323931396564636131616234346130393566663131353835323833666338 65393934373564386335343865656161306635653833373430663064616264653135316530303338
63653332383130666164376534656430366664356339323463393338353066663537313336653864 38366434323961396638663534396530636639613338643463326432646366646163316363383832
66323361383737323930663732376261323238653537623335636638363966343264346537383264 31373331366565376439643131343631393663666434363838316435653132393034643536353332
64663334366538326365663266613662356132646230363461643862643337633531333233363134 66343530363564346335623464653862643632356638656535353666353336323033356336636134
66313565313733326363623935363535336166623761346162663964396266613932356462376664 39316165633562303239623863613633313238323862393636336464633934316266313235343736
63313339333035333234353765383735303830653162346565303465363762623465326431353431 38353435663166643566653236623039353465303431383132306135323239346135323831336363
65616335313733353863626561613236616339393038383562313263376633363765306262396230 65396136666433393334393731373437383631313139666139663239303330363031356330373035
38373963306637316534613964376538666536383235393663616236653338373034363765636135 34366264396332643163626237636132623532326636396461356566363835363163643161396130
65666239356563363538666162313038633861353732386630633930616439323838666536383165 30663637346464646333623833393534613464336432336239386238393630376435343535356464
34353761613738616361613862656236623633356364383436383435383632303635343233356435 36393539653632393430663035613539626165396463323739353263636364346662653535633261
35353466636461376436643965653837633461643430386565353530323333313964376233666665 63663461623435386231653232313539356131346534636137383562313733663031653730353533
63353838323363666435393634643237626663356331653461303936366533343435373732613861 37393233363635643339373530376130326333643764356634643161333135663436663437373136
33393231636235613234383737633430343461616261373265313163363730653237346563393835 38393163343166666237663062313236373938646263356530363136383666636536616436626139
38646566313730633866636162393434316365396663333938656235613635613161363938653531 66633038303961336537613030323639383666333930623161633061643131313235333235303561
65316233643561623837633362383232313664313737643231363838616434666635343466653435 64633631333964336164363963346163303730306334353834343061353661633436363536313839
62653765303832353761346563363338656431313439346234333432363535626461336163616330 30366535376537313065303839323939396465623734656233396535316465333436323937323232
33306633313764616533666263633634306633633261663637633133356430313231323331353535 36656662316232306330393435333836363234666161656434653033643236303864356137393834
31316663373063376665373732366365386464393032313335376463353435313133376161336263 38643234663365663037353663616439383430616665643061363531343765363034386432626564
33363835363062646536343833383232386133666137313539663534653138333236626438333866 62323630613337663562616664613138623262326134343430623661656166653135396562323364
39316433626133666636376532366332346134646233383737386337356464363263343334363663 38616165316464376563636535643839346665613465316662363566313337333666383336303064
32363538343566666263396265636261643764383736643663386333623266363535333766353037 37633130323464393831323962356633663430343761393932323266353864363062653132323639
33333864636539636165373433343532326431316138666164353262643236623237636539646636 33656337666236303764653834326230613165636437306337393132626339663161623536376138
30356361663863646366303238643335626434353832306338346231383764616566626163313931 32343063313864643164613739653038663430633466356331313638343766393166306138336239
64663663613363396661396564383531653231663735653535393437356339353466353737366266 39303938303861343331626231303333343931306136373533613466616336366261313866656631
37353739646632393837353032636331316338393564643261383536383536323036333238633237 37336566623933656433646465306237383334363264333532386537343336363933636133306263
38643735663339316263633964336137303939303531626633646236656430373132316432343436 37333033633461656236623433356438643936343861363833306333386636633463356365643730
66383135663130323462373934656666653837336332626137303931303263613038646235623631 61303931326162353638363035666333333661393262306234366165383530663231656334623133
39383936393665316561373637333935643565656433316462333832323034323533316232656164 30363436616266313062636232313435376462633734393130656239396462613039623236396330
63656630356363336231326364656531623839316236616266363037303138306537376131616134 62666336663661623239666530656664346461363436303930306338303031623461646137366432
31323132613533663664376136376437623837303835613331623339623531653563386464306339 62643332353135663935
62346465396362303262356239326636666435343131333566653661613463363461633631383030
63303738613735313262656362383432356236613339646462393836633861303562663262333561
62323562656461663764336462353230653537383038323931353831643731343837323234643565
36386531613931623036636332663561663438333364616232626461333639326564313335376134
3935