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'
policy: 'two_factor'
- domain: 'remembos.vakhrushev.me'
subject: 'group:admins'
policy: 'two_factor'
- domain: 'rssbridge.vakhrushev.me'
subject: 'group:admins'
policy: 'one_factor'

View File

@@ -2,7 +2,7 @@ services:
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 }}'
restart: 'unless-stopped'
networks:

View File

@@ -4,6 +4,7 @@ Backup script for all applications
Automatically discovers and runs backup scripts for all users,
then creates restic backups and sends notifications.
"""
import itertools
import os
import sys
@@ -153,7 +154,7 @@ class ResticStorage(Storage):
class Notifier(ABC):
def send(self, html_message: str):
def send(self, html_message: str) -> None:
raise NotImplementedError()
@@ -174,7 +175,7 @@ class TelegramNotifier(Notifier):
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"
data = {
"chat_id": self.telegram_chat_id,
@@ -358,10 +359,10 @@ class BackupManager:
)
if self.warnings:
message += f"\n\n⚠️ Предупреждения:\n" + "\n".join(self.warnings)
message += "\n\n⚠️ Предупреждения:\n" + "\n".join(self.warnings)
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:
try:
@@ -470,7 +471,7 @@ def initialize(config_path: Path) -> BackupManager:
)
def main():
def main() -> None:
try:
backup_manager = initialize(CONFIG_PATH)
success = backup_manager.run_backup_process()

View File

@@ -97,6 +97,19 @@ memos.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
reverse_proxy {

View File

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

View File

@@ -1,7 +1,7 @@
services:
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
restart: unless-stopped
networks:

View File

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

View File

@@ -1,7 +1,7 @@
services:
gitea_app:
image: gitea/gitea:1.25.4
image: gitea/gitea:1.25.5
restart: unless-stopped
container_name: gitea_app
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(
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")
return parser.parse_args()
@@ -33,7 +35,9 @@ def rename_files(directory: Path, names: list[str]) -> None:
for name in names:
hash_part, dot, _ = name.partition(".")
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
source = directory / hash_part

View File

@@ -4,7 +4,7 @@ import os
import argparse
def main():
def main() -> None:
parser = argparse.ArgumentParser(
description="Retain specified number of files in a directory sorted by name, delete others."
)
@@ -32,7 +32,7 @@ def main():
sorted_files = sorted(files)
# Identify files to delete
to_delete = sorted_files[:-args.keep] if args.keep > 0 else sorted_files.copy()
to_delete = sorted_files[: -args.keep] if args.keep > 0 else sorted_files.copy()
# Delete files and print results
for filename in to_delete:

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ services:
# See sample https://github.com/outline/outline/blob/main/.env.sample
outline_app:
image: outlinewiki/outline:1.4.0
image: outlinewiki/outline:1.6.1
container_name: outline_app
user: "{{ owner_create_result.uid }}:{{ owner_create_result.group }}"
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
33396537353265633634336630353330653337623861373731613734663938633837613437366537
3439383366633266623463366530626662346338393165630a663539313066663061353635666366
61393437393131333166626165306563366661353338363138633239666566313330363331666537
3763356535396334380a386362383436363732353234333033613133383264643934306432313335
34646164323664636532663835306230386633316539373564383163346663376666633564326134
30666135626637343963383766383836653135633739636261353666303666633566346562643962
63376165636434343066306539653637343736323437653465656436323533636237643333326438
35626239323530643066363533323039393237333338316135313838643464306161646635313062
36386565626435373333393566393831366538363864313737306565343162316536353539333864
63376264643566613266373665666363366662643262616634333132386535383731396462633430
32343738343039616139343833366661303430383766376139636434616565356161396433643035
37363165383935373937346464343738643430333764336264373931616332393964346566636638
39303434343461326464623363323937396663376335316237373166306134636432376435663033
34346436623435626363636237373965633139343661623135633764303862353465306235666563
66653764666635636462636434663264646665383236343166643133613966366334653030653262
38326437313939616332636638323033346139343732653933356239306132613665376163646164
30316663643666633334653133613764396165646533636534613931663138666366316235396466
61313964396264626339306135376635633133366433303033633363396132303938363638346333
66326466326134313535393831343262363862663065323135643630316431336531373833316363
64376338653366353031333836643137333736363534363164306331313337353663653961623665
64626562366637336637353433303261303964633236356162363139396339396136393237643935
34316266326561663834353762343766363933313463313263393063343562613933393361653861
38363635323231666438366536626435373365323733663139666534636564623666356436346539
63326436386436356636633637373738343032353664323736653939346234643165313461643833
35666439613136396264313033336539313537613238393262306365656238396464373936616538
64316365616464386638313331653030346330393665353539393834346135643434363736323135
37663433326439356663633162616435313061353662373766633731636439636266666466613363
39343930386534376330663230623832643933336235636166626534366664366562356165373764
63343432323864366162376263656565646661633536666336643030363039616666343063386165
37343238303034313832393538313632396261316232376635633732656663396631323261363433
38373738363833323934353739643538376237316535623035383965613965636337646537326537
64663837643632666334393634323264613139353332306263613165383733386662366333316139
63373839346265366166333331353231663763306163323063613138323835313831303666306561
39316666343761303464333535336361333462623363633333383363303134336139356436666165
62616364373030613837353939363636653537373965613531636130383266643637333233316137
39353866366239643265366162663031346439663234363935353138323739393337313835313062
33373263326565383735366364316461323930336437623834356132346633636364313732383661
66346634613762613037386238656334616430633037343066623463313035646339313638653137
65643166316664626236633332326136303235623934306462643636373437373630346435633835
66346364393236393563623032306631396561623263653236393939313333373635303365316638
66373037333565323733656331636337336665363038353635383531386366633632363031623430
31356461663438653736316464363231303938653932613561633139316361633461626361383132
396436303634613135383839396566393135
64636264303339643062343231346262316463353562396635623734643763376163383361623135
3065326434613532376662343761323339316234356363630a386563613639363332623137653365
30386363303332333566633737306335336162396366316133653837326264383966653762383037
6466333038346436650a343238626637356532376133323464396666643061376363393466663838
37313235336563643361316339316661356639343933396161333335356332363933656530393634
34376632326135373864636232616163373738383165326338613037303364323530313766343038
34366538633062623064626131376261663032666663306339663361663665303866373833646261
32663931626266663064663066643866356532353363636365633139663930353764386436623539
66313061393564303737306261383632303063313032613033336130376563386139353835303531
65623864613639346238663434653361616563626639643437636638396230323232393065663839
34383737653064343433313364663532363635326165623361303536373136666130306266383237
61653939326137356139363535353666356265336536393763656136353661636336633231366132
62303065663233306130316435333364313039366362393762383463313035333034623730643931
63323035633838303530313361323966346437656366386430316631303637376431396261343166
31313734643831376633383065373436633136633261373838633662633433363363616162323233
34666564333637316266623439383934363862336238613436356531373834643262653463326634
64306530383338613161303138313038393433306430663331343033393832323532376261653838
33373463636533356134633030393965386131353034323734303934636462363863386231353534
65303739643338653265313864633632376461373766343536626464303332636332346531303165
64396363323465393736633937363435663662346136613636643265353830616563623838613632
65613565363139323431653463363461353666313464656664656331633263333766353666346138
37366561366262356239366133616266643032636239363238643237383663633433383365626238
61336632613763616439373730633532316362623663646365303336383531633438323837323939
32313962313264303435633736346565326438626238356361353264353666643165653535303336
31633137396465363035373137636162366165323130396631373865393638376335313838396138
37316263663535376664383764343030623138363137356465316664336564636166313163353566
30656636626163333138346639323465396531666664396231326136653430343061393234366266
35386534633131666166353938343066343830613133643833303338656165393439373038336638
34373436313931666234393530353536353866343330616133653563303764363962333361353639
61316365373565313865393364356361313063303333303063623435323336316534643937316466
30633664353131336531336332323862653566363635623965373238313965353434343733303239
34313836353233653333336130376532386265383762383163386264396231623938616162363861
64363938366665626666383033356566623765363737643565643964326135666566383866366563
39643532306134346562346665656431656366383564376135633536313965613738333535376137
31663566336664373436613866396434623133663361343564623535646462366636616236396661
34663866323835373438623533353833663261663736646335316564383339343363626264343630
65346434303763343763383337306463376235663361643037636231323139303239363532303439
34316133326639623035653532346130633263376531623130616239626433343131333064333632
35626531353562396462633639653534373537356666343266396565623137306232656633303335
35316432643633643139616264316636383364316432373533373535323762353035346434343166
39356266643137663365613832313765376462623032366332363563306536353736333461643930
38633666333330323433373532313030316130346464616565333265376533303564303638376536
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"
glob: "**/*.py"
run: "black --quiet {staged_files}"
run: "uv run ruff format {staged_files}"
stage_fixed: true
- name: "check python"
glob: "**/*.py"
run: "uv run ruff check {staged_files}"
- name: "mypy"
glob: "**/*.py"
run: "mypy {staged_files}"
run: "uv run mypy {staged_files}"
- name: "yamllint"
glob: "**/*.{yml,yaml}"

View File

@@ -23,7 +23,7 @@
ansible.builtin.command:
cmd: >
{{ 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
- name: "Install restic"
@@ -33,11 +33,19 @@
--tag v0.18.1
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"
ansible.builtin.command:
cmd: >
{{ eget_bin_path }} aristocratos/btop --quiet --upgrade-only --to {{ eget_install_dir }}
--tag v1.4.5
--tag v1.4.6
changed_when: false
- name: "Install gobackup"
@@ -51,12 +59,19 @@
ansible.builtin.command:
cmd: >
{{ 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
- name: 'Install dust'
ansible.builtin.command:
cmd: >
{{ bin_prefix }}/eget bootandy/dust --quiet --upgrade-only --to {{ bin_prefix }} --asset gnu
--tag v1.2.3
{{ eget_bin_path }} bootandy/dust --quiet --upgrade-only --to {{ bin_prefix }} --asset gnu
--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

View File

@@ -72,6 +72,7 @@
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: "0640"
register: docker_compose_file_result
- name: "Run application with docker compose"
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 = [
"ansible>=13.2.0",
"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",
]

View File

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

View File

@@ -16,11 +16,11 @@ import sys
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"""
# 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)
@@ -43,7 +43,7 @@ def send_test_email(login, password, to_email):
print(f"Test email successfully sent to {to_email}")
def main():
def main() -> None:
parser = argparse.ArgumentParser(
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" },
]
[[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]]
name = "cffi"
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" },
]
[[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]]
name = "click"
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" },
]
[[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]]
name = "jinja2"
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" },
]
[[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]]
name = "markupsafe"
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" },
]
[[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]]
name = "mypy-extensions"
version = "1.1.0"
@@ -416,6 +593,11 @@ source = { virtual = "." }
dependencies = [
{ name = "ansible" },
{ name = "ansible-lint" },
{ name = "invoke" },
{ name = "mypy" },
{ name = "requests" },
{ name = "ruff" },
{ name = "types-requests" },
{ name = "yamllint" },
]
@@ -423,6 +605,11 @@ dependencies = [
requires-dist = [
{ name = "ansible", specifier = ">=13.2.0" },
{ 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" },
]
@@ -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" },
]
[[package]]
name = "requests"
version = "2.32.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "charset-normalizer" },
{ name = "idna" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
]
[[package]]
name = "resolvelib"
version = "1.2.1"
@@ -659,6 +861,31 @@ version = "0.3.7"
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" }
[[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]]
name = "subprocess-tee"
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" },
]
[[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]]
name = "typing-extensions"
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" },
]
[[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]]
name = "wcmatch"
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
35643431306561396237633439336230333563316364353462393534646565653163396362393566
6636306532353662343437646631363766376166333934340a363062323332386261643832323762
33303235646434636636366532626331653865666465643561633863663938313535623162306334
3332616236326436650a383636393434303165363964383966633138326361373134306563653363
37376465643762383761653132636336663762656136303730616463386134346436383539653661
35623933346565633030373730316331633236623561313166376335636464333439643637623338
32393433653339656135343766393565366530636132346339306339353438396337303534336266
34303635316363343031363263626434386139633762353038666266643338343631303530313661
61373239663739666535636466393937333437316334306631336334303961396134323062666339
62303437623131626130363838353736386463663734356530333061353031643861636437323431
62633036316639306366643633333366386132343337313832343133313235626162323266306165
39326434326235373536633464313234623464373465653061383834363266663435303461633834
36663031323634326436303138623262396332363934646337353166373163326132626437636138
38623864666434363939663234623732623962323836323532393031396638343737373764303239
31316639653066373166326432653930666630393061366461663337333936326239376165633064
32356530333338303636366234336135353130646134643432613965366430326164393563383135
63653237646237323832613363643732383436646539396239333632353566386135633961316132
62313630313065376465346338663661343466366364363761616363376535373031383736616136
37343634626366356261363030616330396263623965306166386238363039663461396431303733
61626164353466323762666236376536356364653565333266363730653539626531663639333864
32366333336234376635616361626635616265376361316439653230646537303031343564653631
63663237353766643766343130613739386636663534336536353936353561616538316535333064
62343835643636633831366265313939313433326239633130303863303136363732653766303663
33643231363761336463623339323831363034636532346237373236656266303063633365393636
36663066336233643236393837323762393435303665303661356237666237646464326536623731
64396431323561353832333834336232396366663439643161626338653930633665346566303435
66636466313936316530353537643637323833653561616339353465323466333332363436613461
38653837373637343532343662366435616366313831623239343363366131633062303036333135
36356136376236383431613266663164616135343062666136353430626663653631313064326131
63353066313433653838613934323833373237356230376363376132306663656461653264383866
37333863633536346538366665346666346364633733366434393135353664336330623865343132
31396534643633333134363465323063313435333236646630613066353232613039393235366630
36646664366339613535616437376437326561636130333063626637316431626330386137306162
65393533306439613032623061373331333762643336633863333061393734313335386633666338
31316637643031353462363363626662373462633065653738613733633933623432343535316438
31356530306263303566636535363465356562633439386365316461323339393339643133323032
32616662633565346564643737386266623836623830663265323439313762636437336436346430
65353266373766363166633363636231623031363337626631626466616637616630383632333565
35303737316531306237613832366565376364313435376266306263623139663964336635633030
39306662616233646136336237646139326239653435653436323066333332626266646564616631
31653433663539333633663433643261363065663030373265646533323832323366376230346266
65616633363938333037656663393334363564626136333162383162663437653565663532646366
31343063306434663231396464646232353335636138393038633737323339303033373539363739
64306163343534363131646135396234346166313039323833656636343235656238623333626534
30653264656166326562343534313063326332336330623530646563313262396233386335316538
64316363613865313236633437646139353433386234326537633961356133353361333833636339
65646232336137626130326631626436623933353333383438306237326132303838353833376432
31653936363131623535386331353066323462613238636130376562376361643166363332343537
63346366306161373666306536396164323437613066363537366562666130653638356564383235
66303838616266623335363338376535303665643363326662376166643865383039306236393730
34303130386631636636393736616237633933346136303530373033383739653531326437656463
39326239616163313463636232343036626435366261643030386530393763356133663863373264
62316164386464366663373635393365363161336530313734343633346563396666616262396563
37383638613930366635623962366662343232303635636330383534653861336264396132653538
65306539613333306339643063303063333165653734323333353461356536663661613463633632
61613530653734643761616636386238633535643961633765313863323961313362323265373132
65346530653962613534343062333039663837623130666261636135343663643036356261643333
64306430343136616438636231623236316264623533313439643434343333623030376338663365
36393932613161316137386136343939383035326231323561636337343833613635643261633165
38316233323862666439633833646235623031336638353834323633333562346463333436316437
36303237353138353763346166626465663137323062643633323762313137343661323839353231
38643137383739393866616364386262363733316133313934366165353761643164303439643534
37633636323535373964323939346339633138386239333466363239393430613139623466643531
66323662363834653166363835343363303066306262623432353165313239323130616235316264
65376532623530353935346238346261613062633439333630643962343233326234316130616538
64353932613038353866383263333561623632663863373231636132653365613836363730636263
65626666653962653266343134343638666437373532333464633163333861386632356562346637
62303433383464373165316561646633636130636434633430623031633364643336643835613030
64653937656262623536353764343661326632303964393862343032343330653534353530326238
34613236336339653364333565313862613531643763633166363734316363643534323838333531
36353137653535393862393534303366366464613035376439383134336534366263393661646564
39616233323638653337333461636465353935613236646430623163656334376463323135323761
36353064646532323738363837663238653766366634363232323933363033656332626436363166
36376366336236626265373530646664633335623035646662663261353165313634646463316535
38633862623433613937666162343936393337336537623663306439373830326434356366323664
61646337396562373535353834393665643037626539303932663831306535623733626239323939
61616165643439653235346566346631323035306437323339326665363232333338616133666366
61396136353432376263333961353738343463663937313136336536623539383835663361353232
38343737383361613930326265346562356136313539393464623935626566343137346430356261
62633230396665316533313831346236303265303232363935313138323537373933633232343732
35346363663938306562663433396138393861343332373934303864303963623739316239303264
62393634346231393534633861386364336639366663353065333930616335323438383537616666
63373836363839336634316338643935346634626437326431363132636335326238353930663662
62383464366263336430633338646263626565393030646230306230353837313965623430636138
38393334623661363532663464363163383365323736386134393634333332353263353763393636
35353535303030356665303262333334353630613832323733393638613035343833356662353565
64373334626565653631613863323866336261393533333639326266343435376666646131313535
39343734326162623831343730303734643830626338653232633834373565643133393562653336
35373432316161623061373238333932366161663137616337613632366263373830663464396537
37303363386336663663303161343963633834623564643661653332623434626466376637323631
64653265623861363837346462613164373264313766633034353531666561623732353838643639
37646262646362386331663334666131336335313833313463373463313439353934313733303763
65626339363732326565366464633230303933386438373539633338363439393630316164376565
63333132613739663461346361613761396161323863616263333638376437613139353733613963
32663062393435323061353738316132363438393762316666626231386138366639313566646461
36306664343433653836316436303736343436343762366133373066313232333834363536343462
30303866646131663530313463343261633261663932323562636135346664323761343765333730
39663231636465336361393062666135316534656637306236323137653939383565643637623866
33633536366163346466303864313732303036306665326664353064366134326539333831663632
64343533323166623661326536393437623432336435366435396165333431366532653936396636
30653263306461656230663731336266363832616539373333306238363834333838393063383432
61343238373861303932653162663330333964623834336235336430376562313963613134353834
63666537343837336531633536633038666232343165336663356639636537306333303434383231
64306633383338646362633238386263336632393562623330343532373839663238383965643739
39313363383331363339616431653434366131303666623263326662636161666635643162663730
62356136643364666164383932376536623266373535613230336165396163383830346265393738
30636139353336343630316132366365306234313064636537646262666463646437376336366562
31663731666664313339353331626534626462663431633530653365613762363666373532383762
34323866356239383332373632616464666230373339386235393838376333333464613038373337
33373231386263623664353231626331366565356662623934316632653763363739653862356265
39653539616232356333326463373666656133303161356630393839336638316338646238623138
61343833613130376562656465343438653861653431313762313062656563643665356664646465
33343430663066616536393935366132336666616164356463323663373930653266653238663336
35616263613461356333633430653661376239663363653434346437656161623961333761633663
35643031323063666163623639313864313937386339376235653033366136373333653239653238
36376636653766366632613262326336333430353534326464653931663366383039643466303739
66393065323965383962633266623033643330333437383262373461363539626333653433356436
64383738653735386630346264643462353336313830376139353166666330303638386639623039
34303137623936663636303864623932343766323235653934303263363164326534653137613863
39353739633466376136343938303634643565613537646166326536303739316536376162353838
61326235373733623465313530393831623438343530616339326561386239646562343130376336
63373430313332613561623636393338353933613161656264646366633665373336343530303635
35336561336334626333343030366264356264343062623531363331313466666136666332376265
62363862623635376631336235353531343931663131333861616566356438396664633962646236
61343063383238376261656465386635623263386430656132393631623330326462326166643631
34333238663531366232393764626665376465386336653133643335656161343261616532386135
63333931646435373630323931396564636131616234346130393566663131353835323833666338
63653332383130666164376534656430366664356339323463393338353066663537313336653864
66323361383737323930663732376261323238653537623335636638363966343264346537383264
64663334366538326365663266613662356132646230363461643862643337633531333233363134
66313565313733326363623935363535336166623761346162663964396266613932356462376664
63313339333035333234353765383735303830653162346565303465363762623465326431353431
65616335313733353863626561613236616339393038383562313263376633363765306262396230
38373963306637316534613964376538666536383235393663616236653338373034363765636135
65666239356563363538666162313038633861353732386630633930616439323838666536383165
34353761613738616361613862656236623633356364383436383435383632303635343233356435
35353466636461376436643965653837633461643430386565353530323333313964376233666665
63353838323363666435393634643237626663356331653461303936366533343435373732613861
33393231636235613234383737633430343461616261373265313163363730653237346563393835
38646566313730633866636162393434316365396663333938656235613635613161363938653531
65316233643561623837633362383232313664313737643231363838616434666635343466653435
62653765303832353761346563363338656431313439346234333432363535626461336163616330
33306633313764616533666263633634306633633261663637633133356430313231323331353535
31316663373063376665373732366365386464393032313335376463353435313133376161336263
33363835363062646536343833383232386133666137313539663534653138333236626438333866
39316433626133666636376532366332346134646233383737386337356464363263343334363663
32363538343566666263396265636261643764383736643663386333623266363535333766353037
33333864636539636165373433343532326431316138666164353262643236623237636539646636
30356361663863646366303238643335626434353832306338346231383764616566626163313931
64663663613363396661396564383531653231663735653535393437356339353466353737366266
37353739646632393837353032636331316338393564643261383536383536323036333238633237
38643735663339316263633964336137303939303531626633646236656430373132316432343436
66383135663130323462373934656666653837336332626137303931303263613038646235623631
39383936393665316561373637333935643565656433316462333832323034323533316232656164
63656630356363336231326364656531623839316236616266363037303138306537376131616134
31323132613533663664376136376437623837303835613331623339623531653563386464306339
62346465396362303262356239326636666435343131333566653661613463363461633631383030
63303738613735313262656362383432356236613339646462393836633861303562663262333561
62323562656461663764336462353230653537383038323931353831643731343837323234643565
36386531613931623036636332663561663438333364616232626461333639326564313335376134
3935
30353464333261353263666333626634633162666239653631386263363431333734656631313930
6539363363653239656166623839636131306462633834310a646438626666653163613762313637
33316565343539376535303135366530386333313562306161633861306237313030386366656435
3830353139613066350a666564333832393465316531353863373437646464316262396532383738
36643034623263643038633162666265646661383461303335653935376330633033653730643235
38663938333934353131393762363762366333306439396264346565336439653239353034386138
65343832666363663731656263616263636662323038663835386437306564643265396434393832
31373231636363656463366436303433616239646331353239363966393264623866636466323839
61653037396130373763633265666663316666623961643131373564326361653038646530323964
66383738303230313533653562356535343162633231636634646237663466313031346463393965
65336164373666343932376234343133623531323163653961666432326134333865336262333336
63643038636537323039616563613861386566393364306131326463366531363063613766383965
66353237383734643564626239346662656435386166356161343031343633613331623433366465
34613237383934343636613833353933613536386637626338326537373438646139623839366263
31386137636362356339333530626565333561333634613964343133393038663033656433376165
33323633383237343433636532613965303232306262326237383233656430363030366164643561
37373930646233366439383635333133393631366265373439643635396231336263373266373338
33613432616634666531623631356162363364643437623239643536336636396132313232656233
64333032653930353430336364353335396130633634666131393166383765656362616139396265
32653563366562383930623439363539333235326661383665336564623832313839306263386232
61633734353733346266343936306364393835316635633061386661313262386630623933656436
30633662613937326162666666353339363736373139626133316233383433373665623637326634
62623165306431363931616335363339383836366363353565366136643661366638343361306438
36346265383930326461653931626537306431633766653265373266623333643437323533353233
30336437353739353861316134306361333063336233323437616630386532663934303032356238
64626335653161313533636539353665656239336237633461346535636539393161643961613464
30313366323937313265636563333261643732363161323934303463316663313033633831386536
36313733326133643663353830643936613366653766636638643737323362303537636563336339
66353930633761396666383138653339343632656232643866376337623732326635373735623362
38613831356437383865653964656637396137386463316562663464383834323962333465356562
62343864613364623639336334646462376366356138386162373763353930366663646463303736
36323165373236643139303935333266323064633230353934343538616332653265373438633564
62393332383533313564656434366435326362316666623763353563626138643732643531343238
33313031313366656363343562653763613833653536613562343465376664376562356164613936
66343763313262636532626363393562316661613130313866346165633862373136393661303936
38633562663461623133653864306139393165386265313032653231306361393830653763663062
63383430633734646134303239666532626264613332313136363238323139326237623035623964
37663435353965383535646331343761383562653735363666666335613630373865643265643336
32343664666239326337643366306531623834336463386637666564646338333433303134323564
32323866323337303262363833313838623337323232616135363963363631336637623865373437
31316539663237316162366338303763346139663435313037306338623339316637363133363965
62303439383637353333333631363234343866623763616261666239316631353434323930373066
32613334303566353830323064626537663339373130613533373739616236346337393033316638
39303462633463306634373933396233666530303465323133386435333563373936623466376334
39323131353866313263333436303831323166366165623263323730333663616665373261313232
62333361623964316236303739363430636461396264333638363835646366633633326666326363
30376339646361386337343561666230313066303263353430333436613464303965353634353831
35343866396639366539653939313939656234663665666533326630306530333863383761613161
61376433623635663636656564643135626239343663333532663366353165383463383038353232
35346437383931653166323431353766393036626136643262623263363932396437303033356131
31333066393166356665663963306366383837303036373930653462386232373563303630633636
30363466353437306232383663363161396665393739306536643236663761323366613130656330
30366661353939303030363833636238346134323738366138396336393463373563333632653262
39633333353466313339386362656538336338373565323536646333616434626137323335353563
31636564636537613033656236366362316134353733623961366333313165626637616536646361
39623561656234356663313032326231313231363963643534666136343433663730333333633434
35303363366133323330376163363662653534633431333035363837633831343861373633393930
30626635353166303962313639326239623532396435623230353166323165656261643030356131
65356632613834653063656138353261613231663465336366623564316165623932663530376631
31616137386433336135323636613665356162353139306263633833336566346339666135626433
30336361333736333334383162343336663631663333353739633036346633393763366636353161
36373566613530366632666333646563336136663034663337313032643165643966303964613234
38653332343037653464646635666634376138616636326531353865346663396534363338393465
37393962343233633739313961663531616565363337346535303962663533643866363333353430
35323864383338313837643266653937316432313834653038636561653238303164626362326432
61626638636539303135646432643539306566316464383935333535343163393832316561323764
38373239376363633237346664626137363562303134333563346434396335383235383032653637
66356138396436623734316139373964373364633937373431386432333263326563326234623936
62313830613436356337623865373432356165313930373362643037386239303937666637636332
36666239343336316538623938376538383038386662396662626137633138663766396432353061
66656665656535303535376161303562643035383961343832373137636335363534393861316332
63353831616439376663616363363763323838366363396637313931616337633832643061616662
31663738396162316538343763353330653739303963616530323064373331366433326465326532
34303437346463366362346532376263356134633838373630323831643432663265313965633964
63386361303666376162653938346236636434666564623638646161656661393462613237363935
66346661353735646261333339313638653061636130623963346235376234346138613762643566
30323831613461383766643836666633636364323139333261303632613730663730336637646233
37373733373930333735306532663930396331343037383032636461653463353862613362303332
66663361373030363031396663616638396465313438396230633835633335636664356565316664
61356632303035366638613762306636333439373534356239626439626465613837336539636532
61393564613962303938393435306238383761396339656533653265633461666435353133333164
33316630663131323634343637643435326237666134326534666563623734633634366636623731
33666536396138393137333761633139323735303039313837366635623037333037663231353338
61633962643830663038343530643330356137663665663537336564353730323565626135313662
38646430306638663431373037323061313438666433313264633732303664323634303236356364
32326131656438656661616638393462333532313737396235643830663832643435373362373533
34313638626264363561653232323263643135323666626539636435303131336533623137643735
38333734636133336431393634316566626266356165663639333461306463363637613366643433
61313031623933633731353533346264363336326534366231366239373137666430376266383836
33396365343161616238396133326433343535333032643533616439643236323561353236356536
39663534666533393638376639653161376562636333616437623937383035313032636632396232
62373961616262313936623663613837316539616330336339363436373465363662313836656662
31333231653836306362643234383631666431663431666333366563393830343837393339313533
65343034373265343737326232316162386434326661336530373639633838373766323437393937
38313962356364306165393730356339336639303731393931323130386462663139353639626338
30373162356131313737326164393164373837366632643064326635323934396239363033303938
62376539313164333365336331393735346138376362333962396364323063636539346663613631
66353062643261666538633430653036636461626161356265303037353665326461333335373562
62363237356166363139616532333530373230623865383862383362376534363162336163633133
37636564353836643963613333373837343431346538303738346462663739623932363831353534
64613934323136623761633830313335306666643765343037363665303733613639343466393963
62386361326362386535376364303237313564316661326337336434616134313464313565333136
64663436643939623438366437643034666362386233666238363434613862386333323134363566
61646661386139393731666632343066366139333638333366336137353833383931383835363934
35666563303333303932386264316134383035613035663466656465336439346137656336656434
34363438663962393434633761633336623966636465623665356433343236383862636435303038
33313661336364346562666234396462646231666162306566636461613462643034653861663439
39633361643733643533346561363232336465383633396461376239623837366135336238346332
33373762613230353537656566353466623864636161316361396338613566336132303762306538
36633663643136303262373365363063396163613464333662653430396636623335313061626561
38636165346532373732333463373436323239386432326634613762303665343636343366656162
39613035626133306139663831313236353739313930666339333133663839313932336433353531
63373966633635336632363137326533363864303466366664656532623362663265613936663636
32336265393330616437646664333464623635353662616133623264393935303530356330633834
64626161646366306134303634356138663634396231353064343661373662646132653563656162
36343864396263343561333137383238393063333634376634656231346238383862313264303263
66343766353133316337356265343361363931373362303462663935323735393330623632623237
34636565646461666431313362613862303530343537306563396236663435623164326134326530
61356566313733363035346530613934376236383136633363316263393761383532393133323939
38653731643330666261356236623039633262343031393330356565326261336230303132656332
37353464336365633633643063353237626535326537653131633535306361353165313232366664
65613966356634633134633563343036323539633036363437626466363865626333376134613731
31363434373534613239333031333564653733363732343835346435633934356236356166393538
38613432303032333830633161353938383632313137633437313131653664323934613432356635
32656661303163646335633137363734323363653330623137613438623831366135393261343833
61383839623733346434653739626365376266353430363131636665636639333037646262346465
65393934373564386335343865656161306635653833373430663064616264653135316530303338
38366434323961396638663534396530636639613338643463326432646366646163316363383832
31373331366565376439643131343631393663666434363838316435653132393034643536353332
66343530363564346335623464653862643632356638656535353666353336323033356336636134
39316165633562303239623863613633313238323862393636336464633934316266313235343736
38353435663166643566653236623039353465303431383132306135323239346135323831336363
65396136666433393334393731373437383631313139666139663239303330363031356330373035
34366264396332643163626237636132623532326636396461356566363835363163643161396130
30663637346464646333623833393534613464336432336239386238393630376435343535356464
36393539653632393430663035613539626165396463323739353263636364346662653535633261
63663461623435386231653232313539356131346534636137383562313733663031653730353533
37393233363635643339373530376130326333643764356634643161333135663436663437373136
38393163343166666237663062313236373938646263356530363136383666636536616436626139
66633038303961336537613030323639383666333930623161633061643131313235333235303561
64633631333964336164363963346163303730306334353834343061353661633436363536313839
30366535376537313065303839323939396465623734656233396535316465333436323937323232
36656662316232306330393435333836363234666161656434653033643236303864356137393834
38643234663365663037353663616439383430616665643061363531343765363034386432626564
62323630613337663562616664613138623262326134343430623661656166653135396562323364
38616165316464376563636535643839346665613465316662363566313337333666383336303064
37633130323464393831323962356633663430343761393932323266353864363062653132323639
33656337666236303764653834326230613165636437306337393132626339663161623536376138
32343063313864643164613739653038663430633466356331313638343766393166306138336239
39303938303861343331626231303333343931306136373533613466616336366261313866656631
37336566623933656433646465306237383334363264333532386537343336363933636133306263
37333033633461656236623433356438643936343861363833306333386636633463356365643730
61303931326162353638363035666333333661393262306234366165383530663231656334623133
30363436616266313062636232313435376462633734393130656239396462613039623236396330
62666336663661623239666530656664346461363436303930306338303031623461646137366432
62643332353135663935