8 Commits

40 changed files with 6402 additions and 3 deletions

5
.gitignore vendored
View File

@@ -158,5 +158,8 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
.vscode/
# Project specific
config.json

75
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,75 @@
# Contributing to isp-maintenance
### Getting started
To get started, fork the isp-maintenance `isp-maintenance` git repository on Gitea and clone it:
$ git clone git@git.isptech.ru:<user>/isp-maintenance.git
To keep your forked repository up to date, setup the `upstream` remote to pull in new changes:
$ git remote add upstream https://git.isptech.ru/ISPsystem/isp-maintenance.git
$ git pull --rebase upstream main
### Creating a new feature, fix, etc
Using the Gitea web editor for making changes is strongly discouraged, because you will need to clone the repo anyways to edit and test your changes.
Using the `main` branch of your fork for contributing is also strongly discouraged.
It can cause many issues with updating your pull request (also called a PR), and having multiple PRs open at once.
To create a new branch:
$ git checkout main -b <a-descriptive-name>
- Stick to PEP and use a linter. We use flake8 (default config)
### Starting a pull request
Once you have successfully built the package, you can [create a pull request](https://docs.gitea.com/usage/pull-request).
Pull requests are also known as PRs.
Most pull requests should only contain a single feature or fix.
Before a pull request, update the `main` branch and rebase to your branch.
[rebase docs](https://git-scm.com/book/ru/v2/Ветвление-в-Git-Перебазирование).
$ git checkout main
$ git pull --rebase upstream main
$ git checkout <your-branch-name>
$ git rebase main
#### Review
It's possible (and common) that a pull request will contain mistakes or reviewers will ask for additional tweaks.
Reviewers will comment on your pull request and point out which changes are needed before the pull request can be merged.
Most PRs will have a single commit, as seen so if you need to make changes to the commit and already have a pull request open, you can use the following commands:
$ git add <file>
$ git commit --amend
$ git push -f
A more powerful way of modifying commits than using `git commit --amend` is with [git-rebase](https://git-scm.com/docs/git-rebase#_interactive_mode), which allows you to join, reorder, change description of past commits and more.
Alternatively, if there are issues with your git history, you can make another branch and push it to the existing PR:
$ git checkout main -b <attempt2>
$ # do changes anew
$ git push -f <fork> <attempt2>:<branch-of-pr>
#### Closing the pull request
Once you have applied all requested changes, the reviewers will merge your request.
If the pull request becomes inactive for some days, the reviewers may or may not warn you when they are about to close it.
If it stays inactive further, it will be closed.
Please abstain from temporarily closing a pull request while revising the templates.
Instead, leave a comment on the PR describing what still needs work, add "[[WIP](https://docs.gitea.com/usage/automatically-linked-references)]" to the PR title.
Only close your pull request if you're sure you don't want your changes to be included.

10
Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
FROM python:3.11-alpine
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir --root-user-action=ignore -r requirements.txt
COPY main.py .
CMD [ "python", "-u", "main.py" ]

View File

@@ -1,3 +1,8 @@
# isp_maintenance
# isp-maintenance
Maintenance application for quick access, check and resolve issues VM/DCImanager 6 generation
### In progress
### See [CONTRIBUTING.md](CONTRIBUTING.md) for a general overview of how to contribute

View File

View File

View File

View File

@@ -0,0 +1,12 @@
import click
@click.group(help='access command for lazy example')
@click.option('--debug/--no-debug', default=False)
def cli(debug):
click.echo(f"Debug mode is {'on' if debug else 'off'}")
@cli.command()
def enable():
click.echo('Access granted')

View File

@@ -0,0 +1,13 @@
import click
from core.cli.lazy_group import LazyGroup
from settings.general import INSTALLED_APPS
@click.group(
cls=LazyGroup,
lazy_subcommands=INSTALLED_APPS['dci6'],
help='dci6 command for lazy example',
)
def cli():
pass

View File

View File

@@ -0,0 +1,24 @@
import click
from db.vm6.databases import isp_database
from db.vm6.models import AuthUser
@click.group(help='access command for lazy example')
def cli():
pass
@cli.command(help='show all users and their roles on platform (DEMO EXAMPLE)')
def users():
# check and init connection to db:
isp_database.connect()
# get all fields from auth_user table
# SELECT * FROM auth_user;
all_users = AuthUser.select()
# Iterate fields and print to console users' email and role
for user in all_users:
result = f'{user.email} | {user.roles[0]}'
click.echo(result)
# Close connection
isp_database.close()

View File

@@ -0,0 +1,12 @@
import click
from core.cli.lazy_group import LazyGroup
from settings.general import INSTALLED_APPS
@click.group(
cls=LazyGroup,
lazy_subcommands=INSTALLED_APPS['vm6'],
help='vm6 command for lazy example',
)
def cli():
pass

View File

@@ -0,0 +1,13 @@
import click
@click.group(help='nodes command for lazy example')
def cli():
pass
@cli.command(name='list')
def nodes_list():
click.echo('NODES LIST: etc...')
for num in range(1, 10):
click.echo(num)

View File

View File

View File

@@ -0,0 +1,39 @@
import importlib
import click
class LazyGroup(click.Group):
def __init__(self, *args, lazy_subcommands=None, **kwargs):
super().__init__(*args, **kwargs)
# lazy_subcommands is a map of the form:
#
# {command-name} -> {module-name}.{command-object-name}
#
self.lazy_subcommands = lazy_subcommands or {}
def list_commands(self, ctx):
base = super().list_commands(ctx)
lazy = sorted(self.lazy_subcommands.keys())
return base + lazy
def get_command(self, ctx, cmd_name):
if cmd_name in self.lazy_subcommands:
return self._lazy_load(cmd_name)
return super().get_command(ctx, cmd_name)
def _lazy_load(self, cmd_name):
# lazily loading a command,
# first get the module name and attribute name
import_path = self.lazy_subcommands[cmd_name]
modname, cmd_object_name = import_path.rsplit(".", 1)
# do the import
mod = importlib.import_module(modname)
# get the Command object from that module
cmd_object = getattr(mod, cmd_object_name)
# check the result to make debugging easier
if not isinstance(cmd_object, click.BaseCommand):
raise ValueError(
f"Lazy loading of {import_path} failed by returning "
"a non-command object"
)
return cmd_object

View File

View File

@@ -0,0 +1,20 @@
import json
from peewee import TextField
class JSONField(TextField):
"""
Class to "fake" a JSON field with a text field.
Not efficient but works nicely
"""
def db_value(self, value):
"""Convert the python value for storage in the database."""
return value if value is None else json.dumps(value)
def python_value(self, value):
"""Convert the database value to a pythonic value."""
return value if value is None else json.loads(value)
class UnknownField(object):
def __init__(self, *_, **__): pass

View File

@@ -0,0 +1,46 @@
from peewee import MySQLDatabase, PostgresqlDatabase
from settings.db import (
DB_ENGINE,
DB_HOST,
DB_PORT,
DB_USER,
DB_PASSWORD
)
def guess_database(db_name):
"""
function checks DB_ENGINE and set correct connection class
with connection params. Expected database name in input.
Args:
db_name (_str_): database name
Returns:
(_MySQLDatabase_or_PostgresqlDatabase_ class):
contains db connection params
"""
if DB_ENGINE == 'mysql':
return MySQLDatabase(
db_name, **{
'charset': 'utf8',
'sql_mode': 'PIPES_AS_CONCAT',
'use_unicode': True,
'host': DB_HOST,
'port': DB_PORT,
'user': DB_USER,
'password': DB_PASSWORD
}
)
if DB_ENGINE == 'psql':
return PostgresqlDatabase(
db_name, **{
'charset': 'utf8',
'sql_mode': 'PIPES_AS_CONCAT',
'use_unicode': True,
'host': DB_HOST,
'port': DB_PORT,
'user': DB_USER,
'password': DB_PASSWORD
}
)

View File

View File

@@ -0,0 +1,9 @@
from db.connection import guess_database
# The variable will contain an object of
# the MySQLDatabase or PostgresqlDatabase class as well as all connection data
# If in the future there will be more databases in the platform,
# they should be added here
auth_database = guess_database('auth')
dci_1_database = guess_database('dci_1')

View File

@@ -0,0 +1,980 @@
from peewee import (
AutoField,
BigIntegerField,
CharField,
CompositeKey,
DateTimeField,
FloatField,
ForeignKeyField,
IntegerField,
Model,
TextField,
SQL
)
from db.common import UnknownField
from db.dci6.databases import auth_database
class BaseModel(Model):
class Meta:
database = auth_database
class AlertSetting(BaseModel):
channel = UnknownField(null=True) # json
enabled = IntegerField(constraints=[SQL("DEFAULT 1")])
metric = UnknownField(null=True) # json
metric_id = CharField(null=True)
name = CharField(null=True)
class Meta:
table_name = 'alert_setting'
class AuthAcl(BaseModel):
ip_list = UnknownField() # json
name = CharField(constraints=[SQL("DEFAULT ''")], unique=True)
class Meta:
table_name = 'auth_acl'
class AuthUser(BaseModel):
auth_source = CharField(constraints=[SQL("DEFAULT 'local'")])
avatar = TextField(null=True)
avatar_content_type = CharField(null=True)
avatar_filename = CharField(null=True)
created_date = DateTimeField(null=True)
email = CharField(constraints=[SQL("DEFAULT ''")], unique=True)
email_confirm = IntegerField(constraints=[SQL("DEFAULT 0")])
full_name = CharField(null=True)
ip_list = UnknownField(null=True) # json
lang = CharField(constraints=[SQL("DEFAULT 'en'")])
password = CharField(null=True)
phone_number = CharField(null=True)
property = UnknownField(null=True) # json
reserve_codes = UnknownField(null=True) # json
roles = UnknownField() # json
ssh_priv_key = TextField(null=True)
ssh_pub_key = TextField(null=True)
state = CharField(constraints=[SQL("DEFAULT 'active'")])
timezone = CharField(null=True)
totp = CharField(null=True)
uuid = CharField(null=True, unique=True)
class Meta:
table_name = 'auth_user'
class AuthConfirmToken(BaseModel):
expires_at = DateTimeField(null=True)
resend_token_after = DateTimeField(null=True)
token = CharField(null=True, unique=True)
user = ForeignKeyField(
column_name='user',
field='id',
model=AuthUser,
null=True,
unique=True
)
class Meta:
table_name = 'auth_confirm_token'
class AuthGdprDoc(BaseModel):
change_date = DateTimeField(null=True)
desc_condition = CharField(null=True)
entry_date = DateTimeField(null=True)
locale = CharField(null=True)
name = CharField(unique=True)
required = IntegerField(constraints=[SQL("DEFAULT 0")])
state = CharField()
url = CharField(null=True)
class Meta:
table_name = 'auth_gdpr_doc'
class AuthGdprJournal(BaseModel):
action_date = DateTimeField(null=True)
action_type = CharField()
doc = ForeignKeyField(
column_name='doc',
field='id',
model=AuthGdprDoc,
null=True
)
ip = CharField(null=True)
user_email = CharField()
class Meta:
table_name = 'auth_gdpr_journal'
class AuthGeneratedSshkey(BaseModel):
generation_date = DateTimeField(null=True)
privkey = TextField(null=True)
pubkey = TextField(null=True)
class Meta:
table_name = 'auth_generated_sshkey'
class AuthProduct(BaseModel):
docker_compose_file = TextField(null=True)
name = CharField(null=True)
script = TextField(null=True)
version = CharField(null=True)
class Meta:
table_name = 'auth_product'
indexes = (
(('name', 'version'), True),
)
class AuthInstance(BaseModel):
conn_params = UnknownField(null=True) # json
dbkey = TextField(null=True)
demo = IntegerField(constraints=[SQL("DEFAULT 0")])
failure_reason = UnknownField(null=True) # json
limits = UnknownField(null=True) # json
name = CharField(null=True)
owner = ForeignKeyField(
column_name='owner',
field='id',
model=AuthUser,
null=True
)
product = ForeignKeyField(
column_name='product',
field='id',
model=AuthProduct,
null=True
)
roles = UnknownField(null=True) # json
started = DateTimeField(null=True)
status = CharField()
class Meta:
table_name = 'auth_instance'
class AuthInstanceHistory(BaseModel):
create_time = DateTimeField(constraints=[SQL("DEFAULT CURRENT_TIMESTAMP")])
event_info = UnknownField(null=True) # json
event_type = CharField(null=True)
prev_time = DateTimeField(null=True)
ref = ForeignKeyField(
column_name='ref',
field='id',
model=AuthInstance,
null=True
)
request_id = CharField(null=True)
request_ip = CharField(null=True)
request_owner = CharField(null=True)
request_user = CharField(null=True)
class Meta:
table_name = 'auth_instance_history'
class AuthKey(BaseModel):
expires_at = DateTimeField(null=True)
name = CharField(constraints=[SQL("DEFAULT ''")], unique=True)
user = ForeignKeyField(column_name='user', field='id', model=AuthUser)
class Meta:
table_name = 'auth_key'
class AuthLicense(BaseModel):
instance = ForeignKeyField(
column_name='instance',
field='id',
model=AuthInstance,
null=True,
unique=True
)
last_update = DateTimeField(null=True)
lic_data = UnknownField(null=True) # json
lic_request = UnknownField(null=True) # json
product = CharField(null=True)
signature_expire_date = DateTimeField(null=True)
status = CharField()
class Meta:
table_name = 'auth_license'
class AuthPermission(BaseModel):
data = UnknownField() # json
plugin = CharField(constraints=[SQL("DEFAULT ''")])
service = CharField(constraints=[SQL("DEFAULT ''")])
class Meta:
table_name = 'auth_permission'
indexes = (
(('service', 'plugin'), True),
)
class AuthPricelist(BaseModel):
bill_id = IntegerField(null=True, unique=True)
name = CharField(null=True)
params = UnknownField(null=True) # json
class Meta:
table_name = 'auth_pricelist'
class AuthRestrictions(BaseModel):
attempts_counting_duration = BigIntegerField()
attempts_max_count = IntegerField(null=True)
role = CharField(constraints=[SQL("DEFAULT ''")], unique=True)
time_between_attempts = BigIntegerField()
time_to_unban = BigIntegerField()
class Meta:
table_name = 'auth_restrictions'
class AuthRestrictionsBans(BaseModel):
banned_until = DateTimeField()
user = ForeignKeyField(column_name='user', field='id', model=AuthUser)
user_ip = CharField(null=True)
class Meta:
table_name = 'auth_restrictions_bans'
indexes = (
(('user', 'user_ip'), True),
)
class AuthRole(BaseModel):
data = UnknownField() # json
human_descr = CharField(null=True)
human_name = CharField(null=True)
name = CharField(constraints=[SQL("DEFAULT ''")], unique=True)
class Meta:
table_name = 'auth_role'
class AuthServer(BaseModel):
demo = IntegerField(constraints=[SQL("DEFAULT 0")])
host = CharField(null=True)
instance = ForeignKeyField(
column_name='instance',
field='id',
model=AuthInstance,
null=True,
unique=True
)
login = CharField(null=True)
machine_id = CharField(null=True)
password = CharField(null=True)
port = IntegerField(null=True)
class Meta:
table_name = 'auth_server'
indexes = (
(('host', 'port'), True),
)
class AuthService(BaseModel):
bill_id = IntegerField(null=True, unique=True)
info = UnknownField(null=True) # json
instance = ForeignKeyField(
column_name='instance',
field='id',
model=AuthInstance,
null=True,
unique=True
)
params = UnknownField(null=True) # json
payment_form = TextField(null=True)
status = CharField(null=True)
class Meta:
table_name = 'auth_service'
indexes = (
(('instance', 'bill_id'), True),
)
class AuthServiceDbkey(BaseModel):
dbkey = TextField(null=True)
name = CharField(null=True, unique=True)
class Meta:
table_name = 'auth_service_dbkey'
class AuthSession(BaseModel):
expires_at = DateTimeField(null=True)
is_internal = IntegerField(constraints=[SQL("DEFAULT 0")])
name = CharField(null=True, unique=True)
owner = ForeignKeyField(
column_name='owner',
field='id',
model=AuthUser,
null=True
)
trustee = ForeignKeyField(
backref='auth_user_trustee_set',
column_name='trustee',
field='id',
model=AuthUser,
null=True
)
updated_at = DateTimeField(null=True)
xsrf_token = CharField(null=True)
class Meta:
table_name = 'auth_session'
class AuthToken(BaseModel):
client_ip = CharField(null=True)
description = CharField(constraints=[SQL("DEFAULT ''")])
expires_at = DateTimeField(null=True)
last_used = DateTimeField()
name = CharField(constraints=[SQL("DEFAULT ''")], unique=True)
need_2fa = IntegerField(constraints=[SQL("DEFAULT 0")])
owner = ForeignKeyField(column_name='owner', field='id', model=AuthUser)
trustee = ForeignKeyField(
backref='auth_user_trustee_set',
column_name='trustee',
field='id',
model=AuthUser
)
class Meta:
table_name = 'auth_token'
class AuthTrusteeUser(BaseModel):
instance = ForeignKeyField(
column_name='instance',
field='id',
model=AuthInstance,
null=True
)
role = CharField(null=True)
trustee = ForeignKeyField(
column_name='trustee',
field='id',
model=AuthUser,
null=True
)
user = ForeignKeyField(
backref='auth_user_user_set',
column_name='user',
field='id',
model=AuthUser,
null=True
)
class Meta:
table_name = 'auth_trustee_user'
indexes = (
(('user', 'trustee', 'instance'), True),
)
class AuthUser2Acl(BaseModel):
acl = ForeignKeyField(column_name='acl', field='id', model=AuthAcl)
user = ForeignKeyField(column_name='user', field='id', model=AuthUser)
class Meta:
table_name = 'auth_user2acl'
indexes = (
(('user', 'acl'), True),
)
class AuthUserRole(BaseModel):
instance = ForeignKeyField(
column_name='instance',
field='id',
model=AuthInstance,
null=True
)
roles = UnknownField() # json
state = CharField(constraints=[SQL("DEFAULT 'active'")])
trustee = ForeignKeyField(
column_name='trustee',
field='id',
model=AuthUser
)
user = ForeignKeyField(
backref='auth_user_user_set',
column_name='user',
field='id',
model=AuthUser
)
class Meta:
table_name = 'auth_user_role'
indexes = (
(('user', 'trustee', 'instance'), True),
)
class AuthUserSetting(BaseModel):
data = UnknownField(null=True) # json
instance = ForeignKeyField(
column_name='instance',
field='id',
model=AuthInstance,
null=True
)
name = CharField(null=True)
user = ForeignKeyField(
column_name='user',
field='id',
model=AuthUser
)
class Meta:
table_name = 'auth_user_setting'
indexes = (
(('user', 'name', 'instance'), True),
)
class AuthUserSshkey(BaseModel):
name = CharField(constraints=[SQL("DEFAULT ''")])
owner = ForeignKeyField(
column_name='owner',
field='id',
model=AuthUser,
null=True
)
ssh_pub_key = TextField()
class Meta:
table_name = 'auth_user_sshkey'
indexes = (
(('name', 'owner'), True),
)
class AuthUsersLocks(BaseModel):
description = CharField(constraints=[SQL("DEFAULT ''")])
service_name = CharField()
user = ForeignKeyField(column_name='user', field='id', model=AuthUser)
class Meta:
table_name = 'auth_users_locks'
indexes = (
(('user', 'service_name'), True),
)
primary_key = CompositeKey('service_name', 'user')
class BackupAlembicVersion(BaseModel):
version_num = CharField(primary_key=True)
class Meta:
table_name = 'backup_alembic_version'
class BackupTask(BaseModel):
connection_params = TextField()
cron_expression = CharField()
enabled = IntegerField()
limit_count = IntegerField()
limit_size_mib = IntegerField(null=True)
name = CharField()
note = TextField()
schedule_type = CharField()
storage_type = CharField()
class Meta:
table_name = 'backup_task'
class BackupFile(BaseModel):
date = DateTimeField()
downloadable = IntegerField()
name = CharField()
size = FloatField()
storage_type = CharField()
task = ForeignKeyField(
column_name='task',
field='id',
model=BackupTask,
null=True
)
class Meta:
table_name = 'backup_file'
class CsDocuments(BaseModel):
lang = CharField(constraints=[SQL("DEFAULT ''")])
name = CharField(constraints=[SQL("DEFAULT ''")])
product = CharField(constraints=[SQL("DEFAULT ''")])
required = IntegerField(constraints=[SQL("DEFAULT 0")])
url = CharField(constraints=[SQL("DEFAULT ''")])
class Meta:
table_name = 'cs_documents'
indexes = (
(('product', 'lang', 'name'), True),
)
class CsSettings(BaseModel):
lang = CharField(constraints=[SQL("DEFAULT ''")])
product = CharField(constraints=[SQL("DEFAULT ''")])
prop_key = CharField(constraints=[SQL("DEFAULT ''")])
prop_value = CharField(constraints=[SQL("DEFAULT ''")])
class Meta:
table_name = 'cs_settings'
indexes = (
(('product', 'lang', 'prop_key'), True),
)
class EserviceAlembicVersion(BaseModel):
version_num = CharField(primary_key=True)
class Meta:
table_name = 'eservice_alembic_version'
class EserviceCustomEquipment(BaseModel):
data = TextField(null=True)
device_type = CharField()
features = UnknownField(null=True) # json
handler = CharField(unique=True)
handler_import = CharField(null=True)
name = CharField(unique=True)
protocol = UnknownField(null=True) # json
update_time = DateTimeField()
version = CharField()
class Meta:
table_name = 'eservice_custom_equipment'
class EserviceIpmiFru(BaseModel):
fru_info = UnknownField(null=True) # json
ipmi_id = AutoField()
update_time = DateTimeField()
class Meta:
table_name = 'eservice_ipmi_fru'
class EserviceIpmiInfo(BaseModel):
ipmi_id = AutoField()
model = CharField()
class Meta:
table_name = 'eservice_ipmi_info'
class EserviceIpmiSensors(BaseModel):
ipmi_id = AutoField()
sensors_info = UnknownField(null=True) # json
update_time = DateTimeField()
class Meta:
table_name = 'eservice_ipmi_sensors'
class IpmiProxyLocation(BaseModel):
docker_compose = TextField(null=True)
instance = IntegerField(null=True)
location = IntegerField(null=True)
status = CharField(constraints=[SQL("DEFAULT 'setting_up'")])
status_info = UnknownField(null=True) # json
supported_ipmi_consoles = UnknownField(null=True) # json
class Meta:
table_name = 'ipmi_proxy_location'
indexes = (
(('instance', 'location'), True),
)
class IpmiProxyConnection(BaseModel):
close_time = DateTimeField(null=True)
connection_data = UnknownField(null=True) # json
device_data = UnknownField(null=True) # json
intel_amt = IntegerField(null=True)
ipmi = IntegerField(null=True)
listen_web_port = IntegerField(null=True, unique=True)
location = ForeignKeyField(
column_name='location_id',
field='id',
model=IpmiProxyLocation
)
type = CharField(constraints=[SQL("DEFAULT 'web'")])
user = IntegerField(null=True)
vnc_port = IntegerField(null=True)
class Meta:
table_name = 'ipmi_proxy_connection'
class IpmiProxyJavaAgreement(BaseModel):
instance = IntegerField(null=True, unique=True)
java_agree = IntegerField(constraints=[SQL("DEFAULT 1")])
class Meta:
table_name = 'ipmi_proxy_java_agreement'
class IpmiProxyPlugin(BaseModel):
instance = IntegerField(null=True, unique=True)
class Meta:
table_name = 'ipmi_proxy_plugin'
class IspSettings(BaseModel):
name = CharField(primary_key=True)
value = TextField()
class Meta:
table_name = 'isp_settings'
class JournalAlembicVersion(BaseModel):
version_num = CharField(primary_key=True)
class Meta:
table_name = 'journal_alembic_version'
class JournalEvents(BaseModel):
data = UnknownField(null=True) # json
date_time = DateTimeField(
constraints=[SQL("DEFAULT CURRENT_TIMESTAMP(3)")]
)
entity_id = IntegerField()
entity_name = CharField()
entity_owner = IntegerField()
entity_type = CharField()
ip = CharField()
roles = UnknownField(null=True) # json
trustee_email = CharField(index=True)
trustee_id = IntegerField()
type = CharField()
user_email = CharField(index=True)
user_id = IntegerField()
class Meta:
table_name = 'journal_events'
class MsgsChannel(BaseModel):
comment = TextField(null=True)
creation_date = DateTimeField(null=True)
delivery_method = CharField()
enabled = IntegerField(constraints=[SQL("DEFAULT 1")])
language = CharField()
name = CharField()
params = UnknownField(null=True) # json
state = CharField(null=True)
class Meta:
table_name = 'msgs_channel'
class MsgsDeliveryMethod(BaseModel):
delivery_method = CharField(primary_key=True)
dm_params = UnknownField(null=True) # json
class Meta:
table_name = 'msgs_delivery_method'
class MsgsMessageDesign(BaseModel):
design = CharField(primary_key=True)
class Meta:
table_name = 'msgs_message_design'
class MsgsMessageDesignVariant(BaseModel):
delivery_method = CharField()
design = CharField()
design_content = TextField(null=True)
language = CharField()
class Meta:
table_name = 'msgs_message_design_variant'
indexes = (
(('design', 'delivery_method', 'language'), True),
(('design', 'delivery_method', 'language'), True),
)
primary_key = CompositeKey('delivery_method', 'design', 'language')
class MsgsNoticeReceiver(BaseModel):
delivery_method = CharField()
receivers = UnknownField(null=True) # json
user = IntegerField(null=True)
class Meta:
table_name = 'msgs_notice_receiver'
indexes = (
(('user', 'delivery_method'), True),
)
class MsgsTemplate(BaseModel):
priority = CharField()
template = CharField(primary_key=True)
class Meta:
table_name = 'msgs_template'
class MsgsTemplate2Category(BaseModel):
category = CharField()
template = CharField()
class Meta:
table_name = 'msgs_template2category'
indexes = (
(('template', 'category'), True),
(('template', 'category'), True),
)
primary_key = CompositeKey('category', 'template')
class MsgsTemplateVariant(BaseModel):
delivery_method = CharField()
language = CharField()
template = CharField()
tv_params = UnknownField(null=True) # json
class Meta:
table_name = 'msgs_template_variant'
indexes = (
(('template', 'delivery_method', 'language'), True),
(('template', 'delivery_method', 'language'), True),
)
primary_key = CompositeKey('delivery_method', 'language', 'template')
class MsgsUser(BaseModel):
language = CharField()
user = AutoField()
class Meta:
table_name = 'msgs_user'
class MsgsUser2DeliveryMethod(BaseModel):
delivery_method = CharField()
u2dm_params = UnknownField(null=True) # json
user = IntegerField()
class Meta:
table_name = 'msgs_user2delivery_method'
indexes = (
(('user', 'delivery_method'), True),
(('user', 'delivery_method'), True),
)
primary_key = CompositeKey('delivery_method', 'user')
class MsgsUserSubscription(BaseModel):
category = CharField()
delivery_method = CharField()
user = IntegerField()
class Meta:
table_name = 'msgs_user_subscription'
indexes = (
(('user', 'delivery_method', 'category'), True),
)
primary_key = CompositeKey('category', 'delivery_method', 'user')
class NcNotice(BaseModel):
create_timestamp = IntegerField(null=True)
entity = UnknownField(null=True) # json
params = UnknownField(null=True) # json
status = CharField(constraints=[SQL("DEFAULT 'sended'")])
timestamp = IntegerField(null=True)
type = CharField(null=True)
class Meta:
table_name = 'nc_notice'
class NcUser(BaseModel):
last_notice_timestamp = IntegerField(constraints=[SQL("DEFAULT 0")])
read_timestamp = IntegerField(constraints=[SQL("DEFAULT 0")])
class Meta:
table_name = 'nc_user'
class NcNotice2User(BaseModel):
notice = ForeignKeyField(
column_name='notice',
field='id',
model=NcNotice,
null=True
)
read_timestamp = IntegerField(constraints=[SQL("DEFAULT 0")])
user = ForeignKeyField(
column_name='user',
field='id',
model=NcUser,
null=True
)
class Meta:
table_name = 'nc_notice2user'
indexes = (
(('user', 'notice'), True),
)
class NotifierNotify(BaseModel):
additional_info = UnknownField() # json
description = UnknownField() # json
instance_id = IntegerField(null=True)
modify_index = BigIntegerField()
name = CharField(null=True)
notify_type = CharField()
owner = IntegerField(null=True)
request_id = CharField(null=True)
request_ip = CharField(null=True)
time = DateTimeField(
constraints=[SQL("DEFAULT CURRENT_TIMESTAMP")],
index=True
)
trustee = IntegerField(null=True)
class Meta:
table_name = 'notifier_notify'
class PsPlugin(BaseModel):
content = TextField()
current_version = CharField(null=True)
deprecated = IntegerField(constraints=[SQL("DEFAULT 0")])
filename = CharField(null=True)
intname = CharField(null=True, unique=True)
metadata = UnknownField() # json
name = CharField(null=True, unique=True)
obsoletes = UnknownField(null=True) # json
plugin_requirement = UnknownField(null=True) # json
product = CharField()
remote = IntegerField(constraints=[SQL("DEFAULT 0")])
status = CharField(constraints=[SQL("DEFAULT 'disabled'")])
version = CharField(null=True)
class Meta:
table_name = 'ps_plugin'
class PsPluginLicense(BaseModel):
instance = IntegerField(null=True)
license = UnknownField(null=True) # json
plugin = IntegerField(null=True)
class Meta:
table_name = 'ps_plugin_license'
indexes = (
(('instance', 'plugin'), True),
)
class ReportAlembicVersion(BaseModel):
version_num = CharField(primary_key=True)
class Meta:
table_name = 'report_alembic_version'
class ReportFile(BaseModel):
additional_info = UnknownField(null=True) # json
content = TextField(null=True)
create_datetime = DateTimeField()
entity = CharField()
entity_ids = UnknownField() # json
filename = CharField(null=True)
is_read = IntegerField()
status = CharField()
status_info = UnknownField(null=True) # json
type = CharField()
class Meta:
table_name = 'report_file'
class TaskmgrTask(BaseModel):
before_execute = UnknownField(null=True) # json
bin_args = UnknownField(null=True) # json
bin_path = CharField(constraints=[SQL("DEFAULT ''")])
callback_params = UnknownField(null=True) # json
defer_resolve = UnknownField(null=True) # json
defer_wait = UnknownField(null=True) # json
depends_on = UnknownField(null=True) # json
env = UnknownField(null=True) # json
instance_id = CharField(null=True)
lock_tag = UnknownField(null=True) # json
name = CharField(constraints=[SQL("DEFAULT ''")])
notify = UnknownField(null=True) # json
on_start = UnknownField(null=True) # json
output = TextField()
queue = UnknownField(null=True) # json
registration_time = DateTimeField(
constraints=[SQL("DEFAULT CURRENT_TIMESTAMP")]
)
request_info = UnknownField(null=True) # json
return_code = IntegerField()
service = CharField(constraints=[SQL("DEFAULT ''")])
status = CharField(constraints=[SQL("DEFAULT 'created'")], index=True)
stdin = UnknownField(null=True) # json
ttl = IntegerField()
work_dir = CharField(constraints=[SQL("DEFAULT ''")])
worker_id = CharField(null=True)
class Meta:
table_name = 'taskmgr_task'
class Vault(BaseModel):
key = CharField(unique=True)
value = TextField()
class Meta:
table_name = 'vault'
class VaultAlembicVersion(BaseModel):
version_num = CharField(primary_key=True)
class Meta:
table_name = 'vault_alembic_version'
class VaultQueryLog(BaseModel):
date = DateTimeField()
owner_email = CharField()
owner_id = IntegerField()
request_id = CharField()
request_ip = CharField()
service = CharField()
trustee_id = IntegerField()
class Meta:
table_name = 'vault_query_log'

View File

View File

@@ -0,0 +1,8 @@
from db.connection import guess_database
# The variable will contain an object of
# the MySQLDatabase or PostgresqlDatabase class as well as all connection data
# If in the future there will be more databases in the platform,
# they should be added here
isp_database = guess_database('isp')

File diff suppressed because it is too large Load Diff

21
isp_maintenance/ispmgr.py Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import click
from core.cli.lazy_group import LazyGroup
@click.group(
cls=LazyGroup,
lazy_subcommands={
'vm6': 'apps.vm6.commands.cli',
'dci6': 'apps.dci6.commands.cli',
},
help='main CLI command for lazy example',
)
def cli():
pass
if __name__ == '__main__':
cli()

View File

@@ -0,0 +1,15 @@
from settings.general import BASE_DIR
from settings.platform import (
PLATFORM_TYPE,
PLATFORM_URL,
PLATFORM_CONFIG
)
from settings.db import(
DB_ENGINE,
DB_HOST,
DB_PORT,
DB_USER,
DB_PASSWORD
)

View File

@@ -0,0 +1,23 @@
from settings.environment import env
from settings.platform import PLATFORM_CONFIG
# ! Required because some instance use psql db:
DB_ENGINE = env.str(
'DB_ENGINE',
PLATFORM_CONFIG.get('DatabaseType', 'mysql')
)
# Connection parameters:
DB_HOST = env.str(
'DB_HOST',
PLATFORM_CONFIG.get('DatabaseType', 'mysql')
)
DB_PORT = env.int('DB_PORT', 3306)
DB_USER = env.str('DB_USER', 'root')
# ! Do not pass password on production. Use value from config.json
DB_PASSWORD = env.str(
'DB_PASSWORD',
PLATFORM_CONFIG.get('MysqlRootPassword', '')
)

View File

@@ -0,0 +1,9 @@
from environs import Env
# Init environment:
env = Env()
# read .env file, if it exists
# reed more about .env file here: https://github.com/sloria/environs
env.read_env()

View File

@@ -0,0 +1,15 @@
import pathlib
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
INSTALLED_APPS = {
'vm6': {
'access': 'apps.vm6.access.commands.cli',
'nodes': 'apps.vm6.nodes.commands.cli',
},
'dci6': {
'access': 'apps.dci6.access.commands.cli',
},
}

View File

@@ -0,0 +1,13 @@
from settings.environment import env
from settings.general import BASE_DIR
from utils.helpers import parse_json_file
PLATFORM_TYPE = env.str('PLATFORM_TYPE', 'vm')
PLATFORM_CONFIG = parse_json_file(f'{BASE_DIR}/config.json')
PLATFORM_URL = env.url(
'PLATFORM_URL',
f"https://{PLATFORM_CONFIG.get('DomainName' ,'replace.me')}"
)

View File

View File

@@ -0,0 +1,20 @@
import json
import sys
def parse_json_file(file_path):
"""
Function read json file as usual config.json then parse it to python dict
Args:
config_file_path (str): path to config file
Returns:
dict: contains parse json content
"""
try:
with open(file_path, 'r') as f:
return json.load(f)
except Exception as error:
print(error)
sys.exit(1)

1241
poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

24
pyproject.toml Normal file
View File

@@ -0,0 +1,24 @@
[tool.poetry]
name = "isp-maintenance"
version = "0.1.0"
description = "Maintenance service for ISPsystem platforms"
authors = ["MOIS3Y <s.zhukovskii@ispsystem.com>", "Failak3 <v.shmidt@ispsystem.com>", "a.garaev <a.garaev@ispsystem.com>", "Ann_M <a.moskovkina@ispsystem.com>"]
license = "MIT"
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.11"
peewee = "^3.17.0"
click = "^8.1.7"
requests = "^2.31.0"
environs = "^10.3.0"
pymysql = {extras = ["rsa"], version = "^1.1.0"}
poetry-plugin-export = "^1.6.0"
[tool.poetry.group.dev.dependencies]
flake8 = "^7.0.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

593
requirements.txt Normal file
View File

@@ -0,0 +1,593 @@
build==1.0.3 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:538aab1b64f9828977f84bc63ae570b060a8ed1be419e7870b8b4fc5e6ea553b \
--hash=sha256:589bf99a67df7c9cf07ec0ac0e5e2ea5d4b37ac63301c4986d1acb126aa83f8f
cachecontrol[filecache]==0.13.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:95dedbec849f46dda3137866dc28b9d133fc9af55f5b805ab1291833e4457aa4 \
--hash=sha256:f012366b79d2243a6118309ce73151bf52a38d4a5dac8ea57f09bd29087e506b
certifi==2024.2.2 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
cffi==1.16.0 ; python_version >= "3.11" and python_version < "4.0" and (platform_python_implementation != "PyPy" or sys_platform == "darwin") \
--hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
--hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \
--hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \
--hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \
--hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \
--hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \
--hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \
--hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \
--hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \
--hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \
--hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \
--hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \
--hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \
--hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \
--hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \
--hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \
--hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \
--hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \
--hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \
--hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \
--hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \
--hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \
--hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \
--hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \
--hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \
--hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \
--hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \
--hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \
--hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \
--hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \
--hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \
--hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \
--hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \
--hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \
--hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \
--hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \
--hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \
--hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \
--hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \
--hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \
--hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \
--hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \
--hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \
--hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \
--hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \
--hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \
--hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \
--hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \
--hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \
--hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
charset-normalizer==3.3.2 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
cleo==2.1.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:0b2c880b5d13660a7ea651001fb4acb527696c01f15c9ee650f377aa543fd523 \
--hash=sha256:4a31bd4dd45695a64ee3c4758f583f134267c2bc518d8ae9a29cf237d009b07e
click==8.1.7 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
colorama==0.4.6 ; python_version >= "3.11" and python_version < "4.0" and (platform_system == "Windows" or os_name == "nt") \
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
crashtest==0.4.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:80d7b1f316ebfbd429f648076d6275c877ba30ba48979de4191714a75266f0ce \
--hash=sha256:8d23eac5fa660409f57472e3851dab7ac18aba459a8d19cbbba86d3d5aecd2a5
cryptography==42.0.2 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380 \
--hash=sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589 \
--hash=sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea \
--hash=sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65 \
--hash=sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a \
--hash=sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3 \
--hash=sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008 \
--hash=sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1 \
--hash=sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2 \
--hash=sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635 \
--hash=sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2 \
--hash=sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90 \
--hash=sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee \
--hash=sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a \
--hash=sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242 \
--hash=sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12 \
--hash=sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2 \
--hash=sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d \
--hash=sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be \
--hash=sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee \
--hash=sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6 \
--hash=sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529 \
--hash=sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929 \
--hash=sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1 \
--hash=sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6 \
--hash=sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a \
--hash=sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446 \
--hash=sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9 \
--hash=sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888 \
--hash=sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4 \
--hash=sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33 \
--hash=sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f
distlib==0.3.8 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \
--hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64
dulwich==0.21.7 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:0fc3078a1ba04c588fabb0969d3530efd5cd1ce2cf248eefb6baf7cbc15fc285 \
--hash=sha256:10893105c6566fc95bc2a67b61df7cc1e8f9126d02a1df6a8b2b82eb59db8ab9 \
--hash=sha256:12d61334a575474e707614f2e93d6ed4cdae9eb47214f9277076d9e5615171d3 \
--hash=sha256:2590e9b431efa94fc356ae33b38f5e64f1834ec3a94a6ac3a64283b206d07aa3 \
--hash=sha256:25c3ab8fb2e201ad2031ddd32e4c68b7c03cb34b24a5ff477b7a7dcef86372f5 \
--hash=sha256:274c18ec3599a92a9b67abaf110e4f181a4f779ee1aaab9e23a72e89d71b2bd9 \
--hash=sha256:29bb5c1d70eba155ded41ed8a62be2f72edbb3c77b08f65b89c03976292f6d1b \
--hash=sha256:2bc12697f0918bee324c18836053644035362bb3983dc1b210318f2fed1d7132 \
--hash=sha256:2e2c66888207b71cd1daa2acb06d3984a6bc13787b837397a64117aa9fc5936a \
--hash=sha256:404b8edeb3c3a86c47c0a498699fc064c93fa1f8bab2ffe919e8ab03eafaaad3 \
--hash=sha256:40dcbd29ba30ba2c5bfbab07a61a5f20095541d5ac66d813056c122244df4ac0 \
--hash=sha256:460b3849d5c3d3818a80743b4f7a0094c893c559f678e56a02fff570b49a644a \
--hash=sha256:460ba74bdb19f8d498786ae7776745875059b1178066208c0fd509792d7f7bfc \
--hash=sha256:4637cbd8ed1012f67e1068aaed19fcc8b649bcf3e9e26649826a303298c89b9d \
--hash=sha256:471305af74790827fcbafe330fc2e8bdcee4fb56ca1177c8c481b1c8f806c4a4 \
--hash=sha256:4a043b90958cec866b4edc6aef5fe3c2c96a664d0b357e1682a46f6c477273c4 \
--hash=sha256:4b09bc3a64fb70132ec14326ecbe6e0555381108caff3496898962c4136a48c6 \
--hash=sha256:4bc4c5366eaf26dda3fdffe160a3b515666ed27c2419f1d483da285ac1411de0 \
--hash=sha256:4c51058ec4c0b45dc5189225b9e0c671b96ca9713c1daf71d622c13b0ab07681 \
--hash=sha256:4f18f0a311fb7734b033a3101292b932158cade54b74d1c44db519e42825e5a2 \
--hash=sha256:61e3451bd3d3844f2dca53f131982553be4d1b1e1ebd9db701843dd76c4dba31 \
--hash=sha256:62bfb26bdce869cd40be443dfd93143caea7089b165d2dcc33de40f6ac9d812a \
--hash=sha256:675a612ce913081beb0f37b286891e795d905691dfccfb9bf73721dca6757cde \
--hash=sha256:6bd69921fdd813b7469a3c77bc75c1783cc1d8d72ab15a406598e5a3ba1a1503 \
--hash=sha256:6c589468e5c0cd84e97eb7ec209ab005a2cb69399e8c5861c3edfe38989ac3a8 \
--hash=sha256:6de6f8de4a453fdbae8062a6faa652255d22a3d8bce0cd6d2d6701305c75f2b3 \
--hash=sha256:739b191f61e1c4ce18ac7d520e7a7cbda00e182c3489552408237200ce8411ad \
--hash=sha256:74700e4c7d532877355743336c36f51b414d01e92ba7d304c4f8d9a5946dbc81 \
--hash=sha256:7836da3f4110ce684dcd53489015fb7fa94ed33c5276e3318b8b1cbcb5b71e08 \
--hash=sha256:7bca4b86e96d6ef18c5bc39828ea349efb5be2f9b1f6ac9863f90589bac1084d \
--hash=sha256:7d8ab29c660125db52106775caa1f8f7f77a69ed1fe8bc4b42bdf115731a25bf \
--hash=sha256:808e8b9cc0aa9ac74870b49db4f9f39a52fb61694573f84b9c0613c928d4caf8 \
--hash=sha256:817822f970e196e757ae01281ecbf21369383285b9f4a83496312204cf889b8c \
--hash=sha256:8278835e168dd097089f9e53088c7a69c6ca0841aef580d9603eafe9aea8c358 \
--hash=sha256:858842b30ad6486aacaa607d60bab9c9a29e7c59dc2d9cb77ae5a94053878c08 \
--hash=sha256:869eb7be48243e695673b07905d18b73d1054a85e1f6e298fe63ba2843bb2ca1 \
--hash=sha256:8869fc8ec3dda743e03d06d698ad489b3705775fe62825e00fa95aa158097fc0 \
--hash=sha256:8929c37986c83deb4eb500c766ee28b6670285b512402647ee02a857320e377c \
--hash=sha256:a0650ec77d89cb947e3e4bbd4841c96f74e52b4650830112c3057a8ca891dc2f \
--hash=sha256:a7b5624b02ef808cdc62dabd47eb10cd4ac15e8ac6df9e2e88b6ac6b40133673 \
--hash=sha256:a9e9c66833cea580c3ac12927e4b9711985d76afca98da971405d414de60e968 \
--hash=sha256:b0d2e4485b98695bf95350ce9d38b1bb0aaac2c34ad00a0df789aa33c934469b \
--hash=sha256:c01a735b9a171dcb634a97a3cec1b174cfbfa8e840156870384b633da0460f18 \
--hash=sha256:c3a539b4696a42fbdb7412cb7b66a4d4d332761299d3613d90a642923c7560e1 \
--hash=sha256:c3d1685f320907a52c40fd5890627945c51f3a5fa4bcfe10edb24fec79caadec \
--hash=sha256:c92e72c43c9e9e936b01a57167e0ea77d3fd2d82416edf9489faa87278a1cdf7 \
--hash=sha256:cc1e11be527ac06316539b57a7688bcb1b6a3e53933bc2f844397bc50734e9ae \
--hash=sha256:ce8db196e79c1f381469410d26fb1d8b89c6b87a4e7f00ff418c22a35121405c \
--hash=sha256:d05d3c781bc74e2c2a2a8f4e4e2ed693540fbe88e6ac36df81deac574a6dad99 \
--hash=sha256:d097e963eb6b9fa53266146471531ad9c6765bf390849230311514546ed64db2 \
--hash=sha256:d4a2d76c96426e791556836ef43542b639def81be4f1d6d4322cd886c115eae1 \
--hash=sha256:d4c0110798099bb7d36a110090f2688050703065448895c4f53ade808d889dd3 \
--hash=sha256:d54c9d0e845be26f65f954dff13a1cd3f2b9739820c19064257b8fd7435ab263 \
--hash=sha256:d5882e70b74ac3c736a42d3fdd4f5f2e6570637f59ad5d3e684760290b58f041 \
--hash=sha256:d62446797163317a397a10080c6397ffaaca51a7804c0120b334f8165736c56a \
--hash=sha256:d96ca5e0dde49376fbcb44f10eddb6c30284a87bd03bb577c59bb0a1f63903fa \
--hash=sha256:e0064363bd5e814359657ae32517fa8001e8573d9d040bd997908d488ab886ed \
--hash=sha256:e138d516baa6b5bafbe8f030eccc544d0d486d6819b82387fc0e285e62ef5261 \
--hash=sha256:e1957b65f96e36c301e419d7adaadcff47647c30eb072468901bb683b1000bc5 \
--hash=sha256:e25953c7acbbe4e19650d0225af1c0c0e6882f8bddd2056f75c1cc2b109b88ad \
--hash=sha256:e274cebaf345f0b1e3b70197f2651de92b652386b68020cfd3bf61bc30f6eaaa \
--hash=sha256:e598d743c6c0548ebcd2baf94aa9c8bfacb787ea671eeeb5828cfbd7d56b552f \
--hash=sha256:e84cc606b1f581733df4350ca4070e6a8b30be3662bbb81a590b177d0c996c91 \
--hash=sha256:ecd315847dea406a4decfa39d388a2521e4e31acde3bd9c2609c989e817c6d62 \
--hash=sha256:ed60d1f610ef6437586f7768254c2a93820ccbd4cfdac7d182cf2d6e615969bb \
--hash=sha256:f34bf9b9fa9308376263fd9ac43143c7c09da9bc75037bb75c6c2423a151b92c \
--hash=sha256:f6c88acb60a1f4d31bd6d13bfba465853b3df940ee4a0f2a3d6c7a0778c705b7 \
--hash=sha256:fa4d14767cf7a49c9231c2e52cb2a3e90d0c83f843eb6a2ca2b5d81d254cf6b9 \
--hash=sha256:ffc27fb063f740712e02b4d2f826aee8bbed737ed799962fef625e2ce56e2d29
environs==10.3.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:cc421ddb143fa30183568164755aa113a160e555cd19e97e664c478662032c24 \
--hash=sha256:feeaf28f17fd0499f9cd7c0fcf408c6d82c308e69e335eb92d09322fc9ed8138
fastjsonschema==2.19.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0 \
--hash=sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d
filelock==3.13.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e \
--hash=sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c
idna==3.6 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
--hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
importlib-metadata==7.0.1 ; python_version >= "3.11" and python_version < "3.12" \
--hash=sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e \
--hash=sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc
installer==0.7.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53 \
--hash=sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631
jaraco-classes==3.3.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:86b534de565381f6b3c1c830d13f931d7be1a75f0081c57dff615578676e2206 \
--hash=sha256:cb28a5ebda8bc47d8c8015307d93163464f9f2b91ab4006e09ff0ce07e8bfb30
jeepney==0.8.0 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "linux" \
--hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \
--hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755
keyring==24.3.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836 \
--hash=sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25
marshmallow==3.20.2 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd \
--hash=sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9
more-itertools==10.2.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684 \
--hash=sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1
msgpack==1.0.7 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862 \
--hash=sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d \
--hash=sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3 \
--hash=sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672 \
--hash=sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0 \
--hash=sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9 \
--hash=sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee \
--hash=sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46 \
--hash=sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524 \
--hash=sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819 \
--hash=sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc \
--hash=sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc \
--hash=sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1 \
--hash=sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82 \
--hash=sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81 \
--hash=sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6 \
--hash=sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d \
--hash=sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2 \
--hash=sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c \
--hash=sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87 \
--hash=sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84 \
--hash=sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e \
--hash=sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95 \
--hash=sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f \
--hash=sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b \
--hash=sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93 \
--hash=sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf \
--hash=sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61 \
--hash=sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c \
--hash=sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8 \
--hash=sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d \
--hash=sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c \
--hash=sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4 \
--hash=sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba \
--hash=sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415 \
--hash=sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee \
--hash=sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d \
--hash=sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9 \
--hash=sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075 \
--hash=sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f \
--hash=sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7 \
--hash=sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681 \
--hash=sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329 \
--hash=sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1 \
--hash=sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf \
--hash=sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c \
--hash=sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5 \
--hash=sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b \
--hash=sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5 \
--hash=sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e \
--hash=sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b \
--hash=sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad \
--hash=sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd \
--hash=sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7 \
--hash=sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002 \
--hash=sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc
packaging==23.2 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
--hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
peewee==3.17.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:e009ac4227c4fdc0058a56e822ad5987684f0a1fbb20fed577200785102581c3
pexpect==4.9.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 \
--hash=sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f
pkginfo==1.9.6 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546 \
--hash=sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046
platformdirs==3.11.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3 \
--hash=sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e
poetry-core==1.8.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:194832b24f3283e01c5402eae71a6aae850ecdfe53f50a979c76bf7aa5010ffa \
--hash=sha256:67a76c671da2a70e55047cddda83566035b701f7e463b32a2abfeac6e2a16376
poetry-plugin-export==1.6.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:091939434984267a91abf2f916a26b00cff4eee8da63ec2a24ba4b17cf969a59 \
--hash=sha256:2dce6204c9318f1f6509a11a03921fb3f461b201840b59f1c237b6ab454dabcf
poetry==1.7.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:03d3807a0fb3bc1028cc3707dfd646aae629d58e476f7e7f062437680741c561 \
--hash=sha256:b348a70e7d67ad9c0bd3d0ea255bc6df84c24cf4b16f8d104adb30b425d6ff32
ptyprocess==0.7.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \
--hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220
pycparser==2.21 ; python_version >= "3.11" and python_version < "4.0" and (platform_python_implementation != "PyPy" or sys_platform == "darwin") \
--hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
--hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
pymysql[rsa]==1.1.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:4f13a7df8bf36a51e81dd9f3605fede45a4878fe02f9236349fd82a3f0612f96 \
--hash=sha256:8969ec6d763c856f7073c4c64662882675702efcb114b4bcbb955aea3a069fa7
pyproject-hooks==1.0.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8 \
--hash=sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5
python-dotenv==1.0.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \
--hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a
pywin32-ctypes==0.2.2 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "win32" \
--hash=sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60 \
--hash=sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7
rapidfuzz==3.6.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:01835d02acd5d95c1071e1da1bb27fe213c84a013b899aba96380ca9962364bc \
--hash=sha256:01eb03cd880a294d1bf1a583fdd00b87169b9cc9c9f52587411506658c864d73 \
--hash=sha256:03f73b381bdeccb331a12c3c60f1e41943931461cdb52987f2ecf46bfc22f50d \
--hash=sha256:0402f1629e91a4b2e4aee68043a30191e5e1b7cd2aa8dacf50b1a1bcf6b7d3ab \
--hash=sha256:060bd7277dc794279fa95522af355034a29c90b42adcb7aa1da358fc839cdb11 \
--hash=sha256:064c1d66c40b3a0f488db1f319a6e75616b2e5fe5430a59f93a9a5e40a656d15 \
--hash=sha256:06e98ff000e2619e7cfe552d086815671ed09b6899408c2c1b5103658261f6f3 \
--hash=sha256:08b6fb47dd889c69fbc0b915d782aaed43e025df6979b6b7f92084ba55edd526 \
--hash=sha256:0a9fc714b8c290261669f22808913aad49553b686115ad0ee999d1cb3df0cd66 \
--hash=sha256:0bbfae35ce4de4c574b386c43c78a0be176eeddfdae148cb2136f4605bebab89 \
--hash=sha256:12ff8eaf4a9399eb2bebd838f16e2d1ded0955230283b07376d68947bbc2d33d \
--hash=sha256:1936d134b6c513fbe934aeb668b0fee1ffd4729a3c9d8d373f3e404fbb0ce8a0 \
--hash=sha256:1c47d592e447738744905c18dda47ed155620204714e6df20eb1941bb1ba315e \
--hash=sha256:1dfc557c0454ad22382373ec1b7df530b4bbd974335efe97a04caec936f2956a \
--hash=sha256:1e12319c6b304cd4c32d5db00b7a1e36bdc66179c44c5707f6faa5a889a317c0 \
--hash=sha256:23de71e7f05518b0bbeef55d67b5dbce3bcd3e2c81e7e533051a2e9401354eb0 \
--hash=sha256:266dd630f12696ea7119f31d8b8e4959ef45ee2cbedae54417d71ae6f47b9848 \
--hash=sha256:2963f4a3f763870a16ee076796be31a4a0958fbae133dbc43fc55c3968564cf5 \
--hash=sha256:2a791168e119cfddf4b5a40470620c872812042f0621e6a293983a2d52372db0 \
--hash=sha256:2b155e67fff215c09f130555002e42f7517d0ea72cbd58050abb83cb7c880cec \
--hash=sha256:2b19795b26b979c845dba407fe79d66975d520947b74a8ab6cee1d22686f7967 \
--hash=sha256:2e03038bfa66d2d7cffa05d81c2f18fd6acbb25e7e3c068d52bb7469e07ff382 \
--hash=sha256:3028ee8ecc48250607fa8a0adce37b56275ec3b1acaccd84aee1f68487c8557b \
--hash=sha256:35660bee3ce1204872574fa041c7ad7ec5175b3053a4cb6e181463fc07013de7 \
--hash=sha256:3c772d04fb0ebeece3109d91f6122b1503023086a9591a0b63d6ee7326bd73d9 \
--hash=sha256:3c84294f4470fcabd7830795d754d808133329e0a81d62fcc2e65886164be83b \
--hash=sha256:40cced1a8852652813f30fb5d4b8f9b237112a0bbaeebb0f4cc3611502556764 \
--hash=sha256:4243a9c35667a349788461aae6471efde8d8800175b7db5148a6ab929628047f \
--hash=sha256:42f211e366e026de110a4246801d43a907cd1a10948082f47e8a4e6da76fef52 \
--hash=sha256:4381023fa1ff32fd5076f5d8321249a9aa62128eb3f21d7ee6a55373e672b261 \
--hash=sha256:484759b5dbc5559e76fefaa9170147d1254468f555fd9649aea3bad46162a88b \
--hash=sha256:49b9ed2472394d306d5dc967a7de48b0aab599016aa4477127b20c2ed982dbf9 \
--hash=sha256:53251e256017e2b87f7000aee0353ba42392c442ae0bafd0f6b948593d3f68c6 \
--hash=sha256:588c4b20fa2fae79d60a4e438cf7133d6773915df3cc0a7f1351da19eb90f720 \
--hash=sha256:5a2f3e9df346145c2be94e4d9eeffb82fab0cbfee85bd4a06810e834fe7c03fa \
--hash=sha256:5d82b9651e3d34b23e4e8e201ecd3477c2baa17b638979deeabbb585bcb8ba74 \
--hash=sha256:5dd95b6b7bfb1584f806db89e1e0c8dbb9d25a30a4683880c195cc7f197eaf0c \
--hash=sha256:692c9a50bea7a8537442834f9bc6b7d29d8729a5b6379df17c31b6ab4df948c2 \
--hash=sha256:6b0ccc2ec1781c7e5370d96aef0573dd1f97335343e4982bdb3a44c133e27786 \
--hash=sha256:6dede83a6b903e3ebcd7e8137e7ff46907ce9316e9d7e7f917d7e7cdc570ee05 \
--hash=sha256:7142ee354e9c06e29a2636b9bbcb592bb00600a88f02aa5e70e4f230347b373e \
--hash=sha256:7183157edf0c982c0b8592686535c8b3e107f13904b36d85219c77be5cefd0d8 \
--hash=sha256:7420e801b00dee4a344ae2ee10e837d603461eb180e41d063699fb7efe08faf0 \
--hash=sha256:757dfd7392ec6346bd004f8826afb3bf01d18a723c97cbe9958c733ab1a51791 \
--hash=sha256:76c23ceaea27e790ddd35ef88b84cf9d721806ca366199a76fd47cfc0457a81b \
--hash=sha256:7fec74c234d3097612ea80f2a80c60720eec34947066d33d34dc07a3092e8105 \
--hash=sha256:82300e5f8945d601c2daaaac139d5524d7c1fdf719aa799a9439927739917460 \
--hash=sha256:841eafba6913c4dfd53045835545ba01a41e9644e60920c65b89c8f7e60c00a9 \
--hash=sha256:8d7a072f10ee57c8413c8ab9593086d42aaff6ee65df4aa6663eecdb7c398dca \
--hash=sha256:8e4da90e4c2b444d0a171d7444ea10152e07e95972bb40b834a13bdd6de1110c \
--hash=sha256:96cd19934f76a1264e8ecfed9d9f5291fde04ecb667faef5f33bdbfd95fe2d1f \
--hash=sha256:a03863714fa6936f90caa7b4b50ea59ea32bb498cc91f74dc25485b3f8fccfe9 \
--hash=sha256:a1788ebb5f5b655a15777e654ea433d198f593230277e74d51a2a1e29a986283 \
--hash=sha256:a3ee4f8f076aa92184e80308fc1a079ac356b99c39408fa422bbd00145be9854 \
--hash=sha256:a490cd645ef9d8524090551016f05f052e416c8adb2d8b85d35c9baa9d0428ab \
--hash=sha256:a553cc1a80d97459d587529cc43a4c7c5ecf835f572b671107692fe9eddf3e24 \
--hash=sha256:a59472b43879012b90989603aa5a6937a869a72723b1bf2ff1a0d1edee2cc8e6 \
--hash=sha256:ac434fc71edda30d45db4a92ba5e7a42c7405e1a54cb4ec01d03cc668c6dcd40 \
--hash=sha256:ad9d74ef7c619b5b0577e909582a1928d93e07d271af18ba43e428dc3512c2a1 \
--hash=sha256:ae598a172e3a95df3383634589660d6b170cc1336fe7578115c584a99e0ba64d \
--hash=sha256:b2ef4c0fd3256e357b70591ffb9e8ed1d439fb1f481ba03016e751a55261d7c1 \
--hash=sha256:b3e5af946f419c30f5cb98b69d40997fe8580efe78fc83c2f0f25b60d0e56efb \
--hash=sha256:b53137d81e770c82189e07a8f32722d9e4260f13a0aec9914029206ead38cac3 \
--hash=sha256:b7e3375e4f2bfec77f907680328e4cd16cc64e137c84b1886d547ab340ba6928 \
--hash=sha256:bcc957c0a8bde8007f1a8a413a632a1a409890f31f73fe764ef4eac55f59ca87 \
--hash=sha256:be156f51f3a4f369e758505ed4ae64ea88900dcb2f89d5aabb5752676d3f3d7e \
--hash=sha256:be368573255f8fbb0125a78330a1a40c65e9ba3c5ad129a426ff4289099bfb41 \
--hash=sha256:c1a23eee225dfb21c07f25c9fcf23eb055d0056b48e740fe241cbb4b22284379 \
--hash=sha256:c65f92881753aa1098c77818e2b04a95048f30edbe9c3094dc3707d67df4598b \
--hash=sha256:ca3dfcf74f2b6962f411c33dd95b0adf3901266e770da6281bc96bb5a8b20de9 \
--hash=sha256:cd4ba4c18b149da11e7f1b3584813159f189dc20833709de5f3df8b1342a9759 \
--hash=sha256:d056e342989248d2bdd67f1955bb7c3b0ecfa239d8f67a8dfe6477b30872c607 \
--hash=sha256:d2f0274595cc5b2b929c80d4e71b35041104b577e118cf789b3fe0a77b37a4c5 \
--hash=sha256:d73dcfe789d37c6c8b108bf1e203e027714a239e50ad55572ced3c004424ed3b \
--hash=sha256:d79aec8aeee02ab55d0ddb33cea3ecd7b69813a48e423c966a26d7aab025cdfe \
--hash=sha256:da3e8c9f7e64bb17faefda085ff6862ecb3ad8b79b0f618a6cf4452028aa2222 \
--hash=sha256:dad55a514868dae4543ca48c4e1fc0fac704ead038dafedf8f1fc0cc263746c1 \
--hash=sha256:dec307b57ec2d5054d77d03ee4f654afcd2c18aee00c48014cb70bfed79597d6 \
--hash=sha256:e06c4242a1354cf9d48ee01f6f4e6e19c511d50bb1e8d7d20bcadbb83a2aea90 \
--hash=sha256:e19d519386e9db4a5335a4b29f25b8183a1c3f78cecb4c9c3112e7f86470e37f \
--hash=sha256:e49b9575d16c56c696bc7b06a06bf0c3d4ef01e89137b3ddd4e2ce709af9fe06 \
--hash=sha256:ebcfb5bfd0a733514352cfc94224faad8791e576a80ffe2fd40b2177bf0e7198 \
--hash=sha256:ed0f712e0bb5fea327e92aec8a937afd07ba8de4c529735d82e4c4124c10d5a0 \
--hash=sha256:edf97c321fd641fea2793abce0e48fa4f91f3c202092672f8b5b4e781960b891 \
--hash=sha256:eef8b346ab331bec12bbc83ac75641249e6167fab3d84d8f5ca37fd8e6c7a08c \
--hash=sha256:f056ba42fd2f32e06b2c2ba2443594873cfccc0c90c8b6327904fc2ddf6d5799 \
--hash=sha256:f382f7ffe384ce34345e1c0b2065451267d3453cadde78946fbd99a59f0cc23c \
--hash=sha256:f59d19078cc332dbdf3b7b210852ba1f5db8c0a2cd8cc4c0ed84cc00c76e6802 \
--hash=sha256:fbc07e2e4ac696497c5f66ec35c21ddab3fc7a406640bffed64c26ab2f7ce6d6 \
--hash=sha256:fde9b14302a31af7bdafbf5cfbb100201ba21519be2b9dedcf4f1048e4fbe65d
requests-toolbelt==1.0.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \
--hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06
requests==2.31.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
secretstorage==3.3.3 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "linux" \
--hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \
--hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99
shellingham==1.5.4 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \
--hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de
tomlkit==0.12.3 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4 \
--hash=sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba
trove-classifiers==2024.1.31 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:854aba3358f3cf10e5c0916aa533f5a39e27aadd8ade26a54cdc2a93257e39c4 \
--hash=sha256:bfdfe60bbf64985c524416afb637ecc79c558e0beb4b7f52b0039e01044b0229
urllib3==2.2.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20 \
--hash=sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224
virtualenv==20.25.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3 \
--hash=sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b
xattr==0.10.1 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "darwin" \
--hash=sha256:042ad818cda6013162c0bfd3816f6b74b7700e73c908cde6768da824686885f8 \
--hash=sha256:0aedf55b116beb6427e6f7958ccd80a8cbc80e82f87a4cd975ccb61a8d27b2ee \
--hash=sha256:0e14bd5965d3db173d6983abdc1241c22219385c22df8b0eb8f1846c15ce1fee \
--hash=sha256:13279fe8f7982e3cdb0e088d5cb340ce9cbe5ef92504b1fd80a0d3591d662f68 \
--hash=sha256:148466e5bb168aba98f80850cf976e931469a3c6eb11e9880d9f6f8b1e66bd06 \
--hash=sha256:16a660a883e703b311d1bbbcafc74fa877585ec081cd96e8dd9302c028408ab1 \
--hash=sha256:183ad611a2d70b5a3f5f7aadef0fcef604ea33dcf508228765fd4ddac2c7321d \
--hash=sha256:199b20301b6acc9022661412346714ce764d322068ef387c4de38062474db76c \
--hash=sha256:1dc9b9f580ef4b8ac5e2c04c16b4d5086a611889ac14ecb2e7e87170623a0b75 \
--hash=sha256:1e2973e72faa87ca29d61c23b58c3c89fe102d1b68e091848b0e21a104123503 \
--hash=sha256:1f0563196ee54756fe2047627d316977dc77d11acd7a07970336e1a711e934db \
--hash=sha256:209fb84c09b41c2e4cf16dd2f481bb4a6e2e81f659a47a60091b9bcb2e388840 \
--hash=sha256:2677d40b95636f3482bdaf64ed9138fb4d8376fb7933f434614744780e46e42d \
--hash=sha256:295b3ab335fcd06ca0a9114439b34120968732e3f5e9d16f456d5ec4fa47a0a2 \
--hash=sha256:3725746a6502f40f72ef27e0c7bfc31052a239503ff3eefa807d6b02a249be22 \
--hash=sha256:3e5825b5fc99ecdd493b0cc09ec35391e7a451394fdf623a88b24726011c950d \
--hash=sha256:3e739d624491267ec5bb740f4eada93491de429d38d2fcdfb97b25efe1288eca \
--hash=sha256:3ff0dbe4a6ce2ce065c6de08f415bcb270ecfd7bf1655a633ddeac695ce8b250 \
--hash=sha256:40039f1532c4456fd0f4c54e9d4e01eb8201248c321c6c6856262d87e9a99593 \
--hash=sha256:436e1aaf23c07e15bed63115f1712d2097e207214fc6bcde147c1efede37e2c5 \
--hash=sha256:46c32cd605673606b9388a313b0050ee7877a0640d7561eea243ace4fa2cc5a6 \
--hash=sha256:475c38da0d3614cc5564467c4efece1e38bd0705a4dbecf8deeb0564a86fb010 \
--hash=sha256:485539262c2b1f5acd6b6ea56e0da2bc281a51f74335c351ea609c23d82c9a79 \
--hash=sha256:49626096ddd72dcc1654aadd84b103577d8424f26524a48d199847b5d55612d0 \
--hash=sha256:4abef557028c551d59cf2fb3bf63f2a0c89f00d77e54c1c15282ecdd56943496 \
--hash=sha256:5267e5f9435c840d2674194150b511bef929fa7d3bc942a4a75b9eddef18d8d8 \
--hash=sha256:5b49d591cf34cda2079fd7a5cb2a7a1519f54dc2e62abe3e0720036f6ed41a85 \
--hash=sha256:5bc40570155beb85e963ae45300a530223d9822edfdf09991b880e69625ba38a \
--hash=sha256:5dc6099e76e33fa3082a905fe59df766b196534c705cf7a2e3ad9bed2b8a180e \
--hash=sha256:636ebdde0277bce4d12d2ef2550885804834418fee0eb456b69be928e604ecc4 \
--hash=sha256:6b8705ac6791426559c1a5c2b88bb2f0e83dc5616a09b4500899bfff6a929302 \
--hash=sha256:6b905e808df61b677eb972f915f8a751960284358b520d0601c8cbc476ba2df6 \
--hash=sha256:7298455ccf3a922d403339781b10299b858bb5ec76435445f2da46fb768e31a5 \
--hash=sha256:772b22c4ff791fe5816a7c2a1c9fcba83f9ab9bea138eb44d4d70f34676232b4 \
--hash=sha256:7880c8a54c18bc091a4ce0adc5c6d81da1c748aec2fe7ac586d204d6ec7eca5b \
--hash=sha256:789bd406d1aad6735e97b20c6d6a1701e1c0661136be9be862e6a04564da771f \
--hash=sha256:7f9be588a4b6043b03777d50654c6079af3da60cc37527dbb80d36ec98842b1e \
--hash=sha256:80638d1ce7189dc52f26c234cee3522f060fadab6a8bc3562fe0ddcbe11ba5a4 \
--hash=sha256:8068df3ebdfa9411e58d5ae4a05d807ec5994645bb01af66ec9f6da718b65c5b \
--hash=sha256:827b5a97673b9997067fde383a7f7dc67342403093b94ea3c24ae0f4f1fec649 \
--hash=sha256:89c93b42c3ba8aedbc29da759f152731196c2492a2154371c0aae3ef8ba8301b \
--hash=sha256:8faaacf311e2b5cc67c030c999167a78a9906073e6abf08eaa8cf05b0416515c \
--hash=sha256:925284a4a28e369459b2b7481ea22840eed3e0573a4a4c06b6b0614ecd27d0a7 \
--hash=sha256:986c2305c6c1a08f78611eb38ef9f1f47682774ce954efb5a4f3715e8da00d5f \
--hash=sha256:9d4c306828a45b41b76ca17adc26ac3dc00a80e01a5ba85d71df2a3e948828f2 \
--hash=sha256:a126eb38e14a2f273d584a692fe36cff760395bf7fc061ef059224efdb4eb62c \
--hash=sha256:a3878e1aff8eca64badad8f6d896cb98c52984b1e9cd9668a3ab70294d1ef92d \
--hash=sha256:a5ea974930e876bc5c146f54ac0f85bb39b7b5de2b6fc63f90364712ae368ebe \
--hash=sha256:a606280b0c9071ef52572434ecd3648407b20df3d27af02c6592e84486b05894 \
--hash=sha256:a9a7a807ab538210ff8532220d8fc5e2d51c212681f63dbd4e7ede32543b070f \
--hash=sha256:aa32f1b45fed9122bed911de0fcc654da349e1f04fa4a9c8ef9b53e1cc98b91e \
--hash=sha256:b0e919c24f5b74428afa91507b15e7d2ef63aba98e704ad13d33bed1288dca81 \
--hash=sha256:b27dfc13b193cb290d5d9e62f806bb9a99b00cd73bb6370d556116ad7bb5dc12 \
--hash=sha256:b34df5aad035d0343bd740a95ca30db99b776e2630dca9cc1ba8e682c9cc25ea \
--hash=sha256:b7bc4ae264aa679aacf964abf3ea88e147eb4a22aea6af8c6d03ebdebd64cfd6 \
--hash=sha256:c0cd2d02ef2fb45ecf2b0da066a58472d54682c6d4f0452dfe7ae2f3a76a42ea \
--hash=sha256:c12e7d81ffaa0605b3ac8c22c2994a8e18a9cf1c59287a1b7722a2289c952ec5 \
--hash=sha256:c3024a9ff157247c8190dd0eb54db4a64277f21361b2f756319d9d3cf20e475f \
--hash=sha256:c4120090dac33eddffc27e487f9c8f16b29ff3f3f8bcb2251b2c6c3f974ca1e1 \
--hash=sha256:c5d3d0e728bace64b74c475eb4da6148cd172b2d23021a1dcd055d92f17619ac \
--hash=sha256:cc6b8d5ca452674e1a96e246a3d2db5f477aecbc7c945c73f890f56323e75203 \
--hash=sha256:ceaa26bef8fcb17eb59d92a7481c2d15d20211e217772fb43c08c859b01afc6a \
--hash=sha256:d1ef954d0655f93a34d07d0cc7e02765ec779ff0b59dc898ee08c6326ad614d5 \
--hash=sha256:d60c27922ec80310b45574351f71e0dd3a139c5295e8f8b19d19c0010196544f \
--hash=sha256:e31d062cfe1aaeab6ba3db6bd255f012d105271018e647645941d6609376af18 \
--hash=sha256:e8c014c371391f28f8cd27d73ea59f42b30772cd640b5a2538ad4f440fd9190b \
--hash=sha256:ec0956a8ab0f0d3f9011ba480f1e1271b703d11542375ef73eb8695a6bd4b78b \
--hash=sha256:f1be6e733e9698f645dbb98565bb8df9b75e80e15a21eb52787d7d96800e823b \
--hash=sha256:f24a7c04ff666d0fe905dfee0a84bc899d624aeb6dccd1ea86b5c347f15c20c1 \
--hash=sha256:f55a2dd73a12a1ae5113c5d9cd4b4ab6bf7950f4d76d0a1a0c0c4264d50da61d \
--hash=sha256:fc354f086f926a1c7f04886f97880fed1a26d20e3bc338d0d965fd161dbdb8ab \
--hash=sha256:ffcb57ca1be338d69edad93cf59aac7c6bb4dbb92fd7bf8d456c69ea42f7e6d2
zipp==3.17.0 ; python_version >= "3.11" and python_version < "3.12" \
--hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \
--hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0