diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..a5aaed3b4d792a623e6b054770db6468d411964b
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,146 @@
+# Local app configuration
+.gen.env
+.env
+# Ide shit
+.idea/*
+.vscode/
+# Session shit
+bot_session.session
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000000000000000000000000000000000000..7106d7b454ffe6d6baa97270a2675b7de9e23192
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,6 @@
+[flake8]
+max-complexity = 6
+inline-quotes = double
+max-line-length = 88
+extend-ignore = E203
+docstring_style=sphinx
diff --git a/.gitignore b/.gitignore
index 9727cab8a4faa74f0437ab58be92e44dc97f9105..a5aaed3b4d792a623e6b054770db6468d411964b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 # Local app configuration
+.gen.env
 .env
 # Ide shit
 .idea/*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1837ac4516c3fb9cfdf4f3d120f03bc6e6104c2c..975f37b1c7c0210904a8a9c63153c22e9cce7da4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,14 +1,37 @@
 stages:
+  - tools
   - test
   - cleanup_tests
+  - build
   - deploy
 
-test:
+build_test:
+  stage: tools
+  tags:
+    - bots-deployer
+  script:
+    - make build-test
+
+flake8:
+  stage: test
+  tags:
+    - bots-deployer
+  script:
+    - make flake8
+
+pytest:
   stage: test
   tags:
     - bots-deployer
   script:
-    - make test
+    - make pytest
+
+black:
+  stage: test
+  tags:
+    - bots-deployer
+  script:
+    - make black
 
 cleanup_tests:
   stage: cleanup_tests
@@ -16,16 +39,25 @@ cleanup_tests:
     - bots-deployer
   when: always
   script:
-    - make clean_test
+    - make clear-test
+
+build:
+  stage: build
+  when: manual
+  tags:
+    - bots-deployer
+  script:
+    - make build push
 
 deploy:
   stage: deploy
-  only: ['master']
+  only:
+    - master
+    - tags
   environment:
     name: production
-    url: https://s3_bot.le-memese.com/
-
+    url: https://${BOT_HOST}/
   tags:
     - bots-deployer
   script:
-    - sh deploy.sh
+    - make deploy-prod
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7b45badf4f53acfc8fd5fce5319a8d950a747499..7f5557645daaa00e085e92119edd716e650eb15a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,33 +1,32 @@
 repos:
-  - repo: https://github.com/timothycrosley/isort
-    rev: 4.3.21
-    hooks:
-      - id: isort
-        exclude: >
-          (?x)^(
-              alembic/.+|
-              systemd/.+
-          )$
-  - repo: https://github.com/ambv/black
-    rev: 19.10b0
-    hooks:
-      - id: black
-  - repo: https://github.com/IamTheFij/docker-pre-commit
-    rev: v2.0.0
-    hooks:
-      - id: docker-compose-check
-      - id: hadolint
+
   - repo: https://github.com/pre-commit/pre-commit-hooks
     rev: v3.1.0
     hooks:
       - id: check-ast
-      - id: requirements-txt-fixer
       - id: trailing-whitespace
+
+  - repo: local
+    hooks:
+      - id: isort
+        name: isort
+        language: system
+        types: [python]
+        entry: isort
+
       - id: flake8
         name: flake8
+        language: system
         entry: flake8
-        exclude: >
-          (?x)^(
-              alembic/.+|
-              systemd/.+
-          )$
+        pass_filenames: false
+        types: [ python ]
+        args:
+          - --count
+          - .
+
+      - id: pytest
+        name: pytest
+        language: system
+        entry: pytest
+        pass_filenames: false
+        types: [ python ]
diff --git a/Dockerfiles/Dockerfile b/Dockerfiles/Dockerfile
deleted file mode 100644
index a25926ccd8ccfbf38123bd0850ece4c49b94c888..0000000000000000000000000000000000000000
--- a/Dockerfiles/Dockerfile
+++ /dev/null
@@ -1,14 +0,0 @@
-FROM python:3.8
-
-# Installing requirements
-COPY requirements/requirements.base.txt /tmp/
-RUN pip install --no-cache-dir -r /tmp/requirements.base.txt
-
-# Copying actuall application
-COPY src/ /app/src
-COPY main.py /app/main.py
-COPY static_messages/ /app/static_messages
-
-WORKDIR /app
-
-CMD ["python", "main.py"]
diff --git a/Dockerfiles/test.Dockerfile b/Dockerfiles/test.Dockerfile
deleted file mode 100644
index e7c28c343b31fd3ad5697a81741de8b6d58c915a..0000000000000000000000000000000000000000
--- a/Dockerfiles/test.Dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-FROM hadolint/hadolint:v1.18.0 as docker_linter
-
-FROM python:3.8
-
-RUN apt-get update -y \
-    && apt-get install -y --no-install-recommends \
-     make=4.2.1-1.2 \
-     sed=4.7-1 \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/*
-
-COPY --from=docker_linter /bin/hadolint /bin/
-RUN hadolint -v
-# Installing requirements
-COPY requirements/ /reqs
-RUN pip install --no-cache-dir -r /reqs/requirements.dev.txt
-
-# Copying actuall application
-COPY . /app
-
-WORKDIR /app
-
-RUN sed -i 's/hadolint/hadolint-system/g' .pre-commit-config.yaml
diff --git a/Makefile b/Makefile
index b661a71655fa4e17851f4faf7e95d9b514fdbe63..076d1716d57bde3ef7cab0c3ef489117ba7b5d47 100644
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,79 @@
-prod:
-	docker-compose -f docker-compose.yml up --build
+.DEFAULT_GOAL := help
 
-clean_prod:
-	docker-compose -f docker-compose.yml down
+.PHONY: help
+help:  ## Show help
+	@grep -E '^[\.a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
+	| awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
 
-test:
-	docker-compose -f docker-compose.test.yml up --build --abort-on-container-exit --exit-code-from test_bot_service
+.PHONY: env_file
+env_file:  ## Generate .gen.env file from env with "BOT_" prefix.
+	touch .gen.env && env | grep -E '^BOT_' > ".gen.env" || echo "Нет переменных среды"
+	test -f .env && cat .env > .gen.env || echo "Файл .env не найден"
 
-clean_test:
-	docker-compose -f docker-compose.test.yml down -v
+.PHONY: build
+build: env_file ## Build docker container image.
+	docker-compose \
+	-f ./deploy/docker-compose.yml \
+	--project-directory . \
+	build --pull bot_service
 
-_test:
-	cp .env.example .env
-	pre-commit run -a || exit 1
-	pytest
+.PHONY: build_test
+build-test: ## Build image for tests.
+	docker-compose \
+	-f ./deploy/docker-compose.test.yml \
+	--project-directory . \
+	build --no-cache test_bot_service
+
+.PHONY: flake8
+flake8:  ## Run flake8 check
+	docker-compose \
+	-f ./deploy/docker-compose.test.yml \
+	--project-directory . \
+	run test_bot_service flake8 --count .
+
+.PHONY: black
+black:  ## Run black check
+	docker-compose \
+	-f ./deploy/docker-compose.test.yml \
+	--project-directory . \
+	run test_bot_service black --check .
+
+.PHONY: pytest
+pytest: ## Run pytest tests
+	docker-compose \
+	-f ./deploy/docker-compose.test.yml \
+	--project-directory . \
+	run test_bot_service pytest -v --cov=bot_s3rius
+
+.PHONY: push
+push: env_file ## Push container to the registry.
+	docker-compose \
+	-f ./deploy/docker-compose.yml \
+	--project-directory . \
+	push bot_service
+
+.PHONY: pull
+pull: env_file  ## Download images from docker hub.
+	docker-compose \
+	    -f deploy/docker-compose.yml \
+	    --project-directory . \
+	    pull --ignore-pull-failures bot_service \
+	|| \
+	docker-compose \
+	    -f deploy/docker-compose.yml \
+	    --project-directory . \
+	    pull bot_service
+
+.PHONY: deploy-prod
+deploy-prod: pull  ## deploy container in production.
+	docker-compose \
+	-f ./deploy/docker-compose.yml \
+	--project-directory . \
+	up -d
+
+.PHONY: clear-test
+clear-test:  ## Remove containers and images for test
+	docker-compose \
+	-f ./deploy/docker-compose.test.yml \
+	--project-directory . \
+	down --rmi=all
diff --git a/README.md b/README.md
index ce7ef57d4601c186700d3f37f87e921926768129..a1877edf76babbd1b5d09773f63cf36eb6c194c5 100644
--- a/README.md
+++ b/README.md
@@ -44,15 +44,3 @@ Clone this repo to your gitlab.
     - LIBRARIES_IO_API_TOKEN
 * Don't forget to declare a global network on your server like memes_network in [docker-compose.yml](./docker-compose.yml).
 * Add access to your container from the network for token submission.
-
-## How to contribute
-First of all install docker and python
-Then run the following:
-```bash
-virtualenv venv
-source venv/bin/activate
-pip install -r requirements/requirements.dev.txt
-pre-commit install
-```
-Then you can do changes.
-For testing you can use `make test`.
diff --git a/src/actions/__init__.py b/bot_s3rius/actions/__init__.py
similarity index 100%
rename from src/actions/__init__.py
rename to bot_s3rius/actions/__init__.py
diff --git a/src/actions/basic.py b/bot_s3rius/actions/basic.py
similarity index 81%
rename from src/actions/basic.py
rename to bot_s3rius/actions/basic.py
index c9fe005133a79ea314153be9aee0d11566131a68..c69cba715c5a0c8903838d55a4fcaefe540284d5 100644
--- a/src/actions/basic.py
+++ b/bot_s3rius/actions/basic.py
@@ -2,25 +2,18 @@ import logging
 from datetime import datetime
 
 import pytz
-from src.config import config
-from src.utils.responses import mark_unread
 from telethon import events
 
+from bot_s3rius.config import config
+from bot_s3rius.utils.responses import mark_unread
+
 logger = logging.getLogger(__name__)
 
 
 @config.telegram_client.on(events.NewMessage(pattern=r"^\.h$"))
 @mark_unread
 async def show_help(event):
-    with open("./static_messages/help.txt") as f:
-        contents = f.read()
-    await event.respond(contents)
-
-
-@config.telegram_client.on(events.NewMessage(pattern=r"^\.ci$"))
-@mark_unread
-async def ci(event):
-    with open("./static_messages/app.info") as f:
+    with open(config.project_dir / "static_messages/help.txt") as f:
         contents = f.read()
     await event.respond(contents)
 
diff --git a/src/actions/converters/__init__.py b/bot_s3rius/actions/converters/__init__.py
similarity index 100%
rename from src/actions/converters/__init__.py
rename to bot_s3rius/actions/converters/__init__.py
diff --git a/src/actions/converters/crypto_currency.py b/bot_s3rius/actions/converters/crypto_currency.py
similarity index 95%
rename from src/actions/converters/crypto_currency.py
rename to bot_s3rius/actions/converters/crypto_currency.py
index f8ac8eb308d707a32bba20bca83960c5cfd90492..36eee365c7996ac2fc70e7e9aa7a4ee20dedbee0 100644
--- a/src/actions/converters/crypto_currency.py
+++ b/bot_s3rius/actions/converters/crypto_currency.py
@@ -4,11 +4,12 @@ import urllib.parse
 from decimal import Decimal
 
 import httpx
-from src.config import config
-from src.utils.converters import get_info_from_group
-from src.utils.responses import mark_unread
 from telethon import events
 
+from bot_s3rius.config import config
+from bot_s3rius.utils.converters import get_info_from_group
+from bot_s3rius.utils.responses import mark_unread
+
 logger = logging.getLogger(__name__)
 
 TARGET_CURRENCY = "rub"
diff --git a/src/actions/converters/currency.py b/bot_s3rius/actions/converters/currency.py
similarity index 95%
rename from src/actions/converters/currency.py
rename to bot_s3rius/actions/converters/currency.py
index b3b12aabe7006ab77661601495d8e8bf31be7259..6e190ae16bf1958a03e86b0b491d2372a2367c36 100644
--- a/src/actions/converters/currency.py
+++ b/bot_s3rius/actions/converters/currency.py
@@ -3,11 +3,12 @@ import re
 from decimal import Decimal
 
 import httpx
-from src.config import config
-from src.utils.converters import get_info_from_group
-from src.utils.responses import mark_unread
 from telethon import events
 
+from bot_s3rius.config import config
+from bot_s3rius.utils.converters import get_info_from_group
+from bot_s3rius.utils.responses import mark_unread
+
 logger = logging.getLogger(__name__)
 
 CURRENCY_MAPPING = {
diff --git a/src/actions/fun.py b/bot_s3rius/actions/fun.py
similarity index 97%
rename from src/actions/fun.py
rename to bot_s3rius/actions/fun.py
index 440ab14e2f3ba55169cf977641c08ef86c6a9e33..af4df49ec48e114a865a21a37fa997719e327ce6 100644
--- a/src/actions/fun.py
+++ b/bot_s3rius/actions/fun.py
@@ -5,11 +5,12 @@ import re
 from datetime import datetime
 
 import httpx
-from src.config import config
-from src.utils.responses import danger_message, mark_unread
-from src.utils.str_helpers import Rotor
 from telethon import events
 
+from bot_s3rius.config import config
+from bot_s3rius.utils.responses import danger_message, mark_unread
+from bot_s3rius.utils.str_helpers import Rotor
+
 logger = logging.getLogger(__name__)
 swearing = [
     "[Ии]ди нахуй",
diff --git a/src/actions/package_indexes.py b/bot_s3rius/actions/package_indexes.py
similarity index 95%
rename from src/actions/package_indexes.py
rename to bot_s3rius/actions/package_indexes.py
index fe47063fc52f2c6f96f5d6d82c23290f384ce5b0..5961afefec694236484a7226ef059b4c7adeca84 100644
--- a/src/actions/package_indexes.py
+++ b/bot_s3rius/actions/package_indexes.py
@@ -3,11 +3,12 @@ from dataclasses import dataclass
 from typing import Union
 
 import httpx
-from src.config import config
-from src.utils.library_package import get_library_info, render_package_info
-from src.utils.responses import failed_search_answer, mark_unread
 from telethon import events
 
+from bot_s3rius.config import config
+from bot_s3rius.utils.library_package import get_library_info, render_package_info
+from bot_s3rius.utils.responses import failed_search_answer, mark_unread
+
 logger = logging.getLogger(__name__)
 
 
diff --git a/src/actions/replies.py b/bot_s3rius/actions/replies.py
similarity index 93%
rename from src/actions/replies.py
rename to bot_s3rius/actions/replies.py
index a834cf1b61f358f8e4cfc65b0bbade97a7301191..dbb8ebbbb7bdf1e17f208802d1738434f0171de1 100644
--- a/src/actions/replies.py
+++ b/bot_s3rius/actions/replies.py
@@ -2,10 +2,11 @@ import logging
 import random
 import re
 
-from src.config import config
-from src.utils.responses import check_if_only_smiles, danger_message, mark_unread
 from telethon import events
 
+from bot_s3rius.config import config
+from bot_s3rius.utils.responses import check_if_only_smiles, danger_message, mark_unread
+
 logger = logging.getLogger(__name__)
 
 
diff --git a/src/actions/search_engines.py b/bot_s3rius/actions/search_engines.py
similarity index 91%
rename from src/actions/search_engines.py
rename to bot_s3rius/actions/search_engines.py
index 1bf7d32a9e99834bfb1a99728ce8358dd2622c10..ca7d1c36a6bda06773d689c609e013a6a2830021 100644
--- a/src/actions/search_engines.py
+++ b/bot_s3rius/actions/search_engines.py
@@ -2,17 +2,18 @@ import logging
 from urllib.parse import urlencode
 
 import httpx
-from src.config import config
-from src.utils.responses import failed_search_answer, mark_unread, thinking
 from telethon import events
 
+from bot_s3rius.config import config
+from bot_s3rius.utils.responses import failed_search_answer, mark_unread, thinking
+
 logger = logging.getLogger(__name__)
 
 
 @config.telegram_client.on(events.NewMessage(pattern=r"^\.i (.*)", forwards=False))
 @mark_unread
 @thinking
-async def search_images(event: events.NewMessage.Event):
+async def search_images(event: events.NewMessage.Event):  # noqa: C901
     query_str = event.pattern_match.group(1).strip()
     params = {
         "count": "30",
diff --git a/src/actions/speller.py b/bot_s3rius/actions/speller.py
similarity index 91%
rename from src/actions/speller.py
rename to bot_s3rius/actions/speller.py
index de6184ce04a2189022eebf1dfbc7927bac3646b6..3243cb4d1c87e2876472068e341351c32fc9fff9 100644
--- a/src/actions/speller.py
+++ b/bot_s3rius/actions/speller.py
@@ -2,11 +2,12 @@ import asyncio
 import re
 from datetime import datetime
 
-from src.config import config
-from src.utils.responses import mark_unread
-from src.utils.str_helpers import Rotor, replace_by_index
 from telethon import events
 
+from bot_s3rius.config import config
+from bot_s3rius.utils.responses import mark_unread
+from bot_s3rius.utils.str_helpers import Rotor, replace_by_index
+
 rotatable_swearing = ["[Бб]ля", "[Сс]ука", "[Ии]ди нахуй", "[Eе]бать", "[Оо]чко"]
 
 rotatable_pattern = f"({'|'.join(rotatable_swearing)})"
diff --git a/bot_s3rius/config.py b/bot_s3rius/config.py
new file mode 100644
index 0000000000000000000000000000000000000000..417c058a87e3314eed90e3dec1307bc868000718
--- /dev/null
+++ b/bot_s3rius/config.py
@@ -0,0 +1,31 @@
+from pathlib import Path
+from typing import List
+
+from pydantic import BaseSettings
+from pydantic.fields import Field
+from telethon import TelegramClient
+
+__all__ = ["config"]
+
+
+class Config(BaseSettings):
+    telegram_app_id: str = Field(None, env="BOT_TELEGRAM_APP_ID", required=True)
+    telegram_api_hash: str = Field(None, env="BOT_TELEGRAM_API_HASH", required=True)
+    libraries_io_token: str = Field(
+        None, env="BOT_LIBRARIES_IO_API_TOKEN", required=True
+    )
+    telegram_account_phone: str = Field(
+        None, env="BOT_TELEGRAM_ACCOUNT_PHONE", required=True
+    )
+    app_mode: str = Field(name="app_mode", default="dev", env="BOT_APP_MODE")
+    debug_mode: bool = False
+    flask_port: str = Field(name="flask_port", default="8080", env="BOT_FLASK_PORT")
+    excluded_chats: List[str] = Field([], env="BOT_EXCLUDED_CHATS")
+    telegram_client: TelegramClient = None
+
+    @property
+    def project_dir(self) -> Path:
+        return Path(__file__).parent
+
+
+config = Config()
diff --git a/src/initializator.py b/bot_s3rius/initializator.py
similarity index 84%
rename from src/initializator.py
rename to bot_s3rius/initializator.py
index 9f04cb172cb07b6749fde75a2e590bad1d85dd60..8f49c73f947f8979b462a7d6fd0511b13856b1dd 100644
--- a/src/initializator.py
+++ b/bot_s3rius/initializator.py
@@ -2,10 +2,11 @@ import asyncio
 import logging
 from multiprocessing import Manager, Process
 
-from src.config import config
-from src.server_app import create_web_app
 from telethon import TelegramClient
 
+from bot_s3rius.config import config
+from bot_s3rius.server_app import create_web_app
+
 logger = logging.getLogger(__name__)
 
 
@@ -40,8 +41,13 @@ def init():
         phone=config.telegram_account_phone, code_callback=get_code_from_web(token)
     )
     config.telegram_client = client
-    from src.actions import finish
+    from bot_s3rius.actions import finish
 
     finish()
 
     return client
+
+
+def main():
+    client = init()
+    client.run_until_disconnected()
diff --git a/src/server_app.py b/bot_s3rius/server_app.py
similarity index 88%
rename from src/server_app.py
rename to bot_s3rius/server_app.py
index 6d447234bef2209746a917163f6ec7cf68a78776..00456d48683ec908abb1499791829e7263dd1fb7 100644
--- a/src/server_app.py
+++ b/bot_s3rius/server_app.py
@@ -3,7 +3,8 @@ import random
 import uuid
 
 from flask import Flask, current_app, render_template, request, send_file
-from src.config import config
+
+from bot_s3rius.config import config
 
 logger = logging.getLogger(__name__)
 
@@ -15,7 +16,9 @@ def form_template():
 
 def girl_image():
     num = random.randint(1, 3)
-    return send_file(f"./templates/static/girl_{num}.png", mimetype="image/png")
+    return send_file(
+        config.project_dir / f"templates/static/girl_{num}.png", mimetype="image/png",
+    )
 
 
 def get_code():
diff --git a/static_messages/help.txt b/bot_s3rius/static_messages/help.txt
similarity index 85%
rename from static_messages/help.txt
rename to bot_s3rius/static_messages/help.txt
index 8f01655b28c2a7951f4991d7c01adb4da0859db5..44a88581abec49308670b32ca88d10c9fcca0b31 100644
--- a/static_messages/help.txt
+++ b/bot_s3rius/static_messages/help.txt
@@ -18,8 +18,6 @@
 `.scc` Посмотреть курсы криптовалют.
 `.rl` Создать бегущую строку из сообщения.
 `.i <запрос>` вернет пачку картинок с интернетиков.
-* `.bl` <любой текст> - заменит все запятые на всякие гадости.
-* `.t` - показать текущее время
-* `@all` -- упомянуть всех в беседе
+`@all` -- упомянуть всех в беседе
 
 И, ко всему прочему, я очень внимательный. Если меня послать на три буквы, либо добавиться или выйти из беседы, то я это замечу и незамедлительно отреагирую.
diff --git a/src/templates/index.html b/bot_s3rius/templates/index.html
similarity index 100%
rename from src/templates/index.html
rename to bot_s3rius/templates/index.html
diff --git a/src/templates/static/girl_1.png b/bot_s3rius/templates/static/girl_1.png
similarity index 100%
rename from src/templates/static/girl_1.png
rename to bot_s3rius/templates/static/girl_1.png
diff --git a/src/templates/static/girl_2.png b/bot_s3rius/templates/static/girl_2.png
similarity index 100%
rename from src/templates/static/girl_2.png
rename to bot_s3rius/templates/static/girl_2.png
diff --git a/src/templates/static/girl_3.png b/bot_s3rius/templates/static/girl_3.png
similarity index 100%
rename from src/templates/static/girl_3.png
rename to bot_s3rius/templates/static/girl_3.png
diff --git a/src/utils/__init__.py b/bot_s3rius/utils/__init__.py
similarity index 100%
rename from src/utils/__init__.py
rename to bot_s3rius/utils/__init__.py
diff --git a/src/utils/converters.py b/bot_s3rius/utils/converters.py
similarity index 100%
rename from src/utils/converters.py
rename to bot_s3rius/utils/converters.py
diff --git a/src/utils/library_package.py b/bot_s3rius/utils/library_package.py
similarity index 93%
rename from src/utils/library_package.py
rename to bot_s3rius/utils/library_package.py
index d84a7f5d5b001c10c5c8483b322a13b86d4217b1..e180ca6325f6fa95ab7a8417dcf7bbc6636ad35a 100644
--- a/src/utils/library_package.py
+++ b/bot_s3rius/utils/library_package.py
@@ -2,8 +2,9 @@ import urllib.parse
 from operator import itemgetter
 
 import httpx
-from src.config import config
-from src.utils.responses import failed_search_answer
+
+from bot_s3rius.config import config
+from bot_s3rius.utils.responses import failed_search_answer
 
 
 def render_package_info(info: dict, add_command: str) -> str:
diff --git a/src/utils/responses.py b/bot_s3rius/utils/responses.py
similarity index 97%
rename from src/utils/responses.py
rename to bot_s3rius/utils/responses.py
index 6a97f5733f7824352ee3a576a67a6cd2afcc91d7..9573c52d20ac4ff44356de0e2620ca257f00cebc 100644
--- a/src/utils/responses.py
+++ b/bot_s3rius/utils/responses.py
@@ -3,9 +3,10 @@ import functools
 import logging
 import random
 
-from src.config import config
 from telethon import events, functions
 
+from bot_s3rius.config import config
+
 logger = logging.getLogger(__name__)
 
 FAILED_SEARCH = [
@@ -33,7 +34,7 @@ def failed_search_answer() -> str:
     return random.choice(FAILED_SEARCH)
 
 
-def thinking(f):
+def thinking(f):  # noqa: C901
     @functools.wraps(f)
     async def updated_function(event: events.NewMessage.Event):
         think_msg = random.choice(THINKING_MSGS)
diff --git a/src/utils/str_helpers.py b/bot_s3rius/utils/str_helpers.py
similarity index 100%
rename from src/utils/str_helpers.py
rename to bot_s3rius/utils/str_helpers.py
diff --git a/deploy.sh b/deploy.sh
deleted file mode 100644
index 30e5461a145d35b7245074d388b93fb6c801c879..0000000000000000000000000000000000000000
--- a/deploy.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-TELEGRAM_APP_ID="${TELEGRM_APP_ID_MASKED//a/}"
-{
-  echo "TELEGRAM_APP_ID=${TELEGRAM_APP_ID}"
-  echo "TELEGRAM_API_HASH=${TELEGRAM_API_HASH}"
-  echo "TELEGRAM_ACCOUNT_PHONE=${TELEGRAM_ACCOUNT_PHONE}"
-  echo "LIBRARIES_IO_API_TOKEN=${LIBRARIES_IO_API_TOKEN}"
-  echo "EXCLUDED_CHATS=${EXCLUDED_CHATS}"
-} >>.env
-
-# Store some info in app.info file
-{
-printf "Maintainer: \`win10@list.ru\`\n"
-printf "Repo url: \`%s\`\n" "$CI_PROJECT_URL"
-printf "Last commit: \`\`\`\n%s \`\`\`\n" "$(git log -1 --pretty=%B)"
-} > ./static_messages/app.info
-
-sed -i "s#WorkingDirectory=.*#WorkingDirectory=${APP_DIR:?}#" -i ./systemd/bot_s3rius_san.service
-
-rm -rf "${APP_DIR:?}/"*
-rsync -av --exclude=".git" . "${APP_DIR}"
-cd "${APP_DIR}" || exit 1
-sudo cp -f "${APP_DIR:?}/systemd/"* /lib/systemd/system/
-sudo systemctl daemon-reload
-sudo systemctl restart bot_s3rius_san.service
diff --git a/deploy/Dockerfiles/Dockerfile b/deploy/Dockerfiles/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..b81f43133928487a40436ec004d1236e72701e19
--- /dev/null
+++ b/deploy/Dockerfiles/Dockerfile
@@ -0,0 +1,36 @@
+FROM python:3.9-alpine3.13
+
+RUN adduser --disabled-password bot
+
+RUN apk add --no-cache curl
+
+ENV POETRY_VERSION 1.1.6
+
+USER bot
+RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
+
+ENV PATH="${PATH}:/home/bot/.poetry/bin:/home/bot/.local/bin"
+RUN source "/home/bot/.poetry/env"
+
+# Installing requirements
+RUN poetry config virtualenvs.create false
+
+COPY pyproject.toml poetry.lock /home/bot/app/
+WORKDIR /home/bot/app/
+
+RUN poetry install --no-dev
+
+# Copying actuall application
+COPY . /home/bot/app/src/
+WORKDIR /home/bot/app/src/
+RUN pip install --use-feature=in-tree-build  .
+
+WORKDIR /home/bot/app
+
+USER root
+RUN rm -rf /home/bot/app/src
+RUN chown -R bot /home/bot
+RUN chmod -R 700 /home/bot
+USER bot
+
+CMD "start_bot"
diff --git a/deploy/Dockerfiles/test.Dockerfile b/deploy/Dockerfiles/test.Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..c0b27c0a6691f3265b5376d77c364ad4a60c9c44
--- /dev/null
+++ b/deploy/Dockerfiles/test.Dockerfile
@@ -0,0 +1,17 @@
+FROM python:3.9-alpine3.13
+
+RUN apk add --no-cache curl gcc musl-dev
+ENV POETRY_VERSION 1.1.6
+
+RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
+
+ENV PATH="${PATH}:/root/.local/bin:/root/.poetry/bin"
+RUN source "/root/.poetry/env"
+
+# Installing requirements
+RUN poetry config virtualenvs.create false
+
+COPY . /app/
+WORKDIR /app/
+
+RUN poetry install
diff --git a/docker-compose.test.yml b/deploy/docker-compose.test.yml
similarity index 62%
rename from docker-compose.test.yml
rename to deploy/docker-compose.test.yml
index 68bd8b5e75f6ed40eb189cbd55547ef79daf3b41..3e2dba770c491ab10377dc620f43e604c1407fde 100644
--- a/docker-compose.test.yml
+++ b/deploy/docker-compose.test.yml
@@ -4,6 +4,5 @@ services:
   test_bot_service:
     container_name: 'bot_s3rius_san_test'
     build:
-      dockerfile: Dockerfiles/test.Dockerfile
+      dockerfile: ./deploy/Dockerfiles/test.Dockerfile
       context: .
-    command: make _test
diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e6ff0b8fc644fc3eaaa3625f19bc84ccd7ec86f3
--- /dev/null
+++ b/deploy/docker-compose.yml
@@ -0,0 +1,33 @@
+version: '3.7'
+networks:
+  memes_network:
+    external:
+      name: memes_network
+
+
+services:
+  bot_service:
+    container_name: 'bot_s3rius_san'
+    build:
+      dockerfile: ./deploy/Dockerfiles/Dockerfile
+      context: .
+    image: docker.le-memese.com/bots/s3rius-bot:${CI_COMMIT_REF_SLUG:-latest}
+    env_file:
+      - .gen.env
+    labels:
+      - traefik.enable=true
+
+      - traefik.http.routers.s3_bot_router.rule=Host('${BOT_HOST}')
+      - traefik.http.routers.s3_bot_router.service=s3_bot
+      - traefik.http.routers.s3_bot_router.tls=true
+      - traefik.http.routers.s3_bot_router.entrypoints=https
+
+      - traefik.http.services.s3_bot.loadbalancer.server.port=${BOT_FLASK_PORT:-8080}
+
+    networks:
+      - traefik-shared
+
+networks:
+  traefik-shared:
+    name: traefik-shared
+    external: true
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 07ce292244d5e55f674c3fe2fdc74ab92687ecff..0000000000000000000000000000000000000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-version: '3.7'
-networks:
-  memes_network:
-    external:
-      name: memes_network
-
-
-services:
-  bot_service:
-    container_name: 'bot_s3rius_san'
-    build:
-      dockerfile: Dockerfiles/Dockerfile
-      context: .
-    env_file:
-      - .env
-    environment:
-      FLASK_PORT: '8080'
-    expose:
-      - 8080
-    networks:
-      - memes_network
diff --git a/main.py b/main.py
deleted file mode 100644
index b2aa467516d8b51141aed6b9be84bbed8e4016b6..0000000000000000000000000000000000000000
--- a/main.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from src.initializator import init
-
-if __name__ == "__main__":
-    client = init()
-    client.run_until_disconnected()
diff --git a/poetry.lock b/poetry.lock
new file mode 100644
index 0000000000000000000000000000000000000000..a904608a9ef9f01dd0c6662d476b6c4952d7c9ee
--- /dev/null
+++ b/poetry.lock
@@ -0,0 +1,951 @@
+[[package]]
+name = "appdirs"
+version = "1.4.4"
+description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "atomicwrites"
+version = "1.4.0"
+description = "Atomic file writes."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "attrs"
+version = "21.2.0"
+description = "Classes Without Boilerplate"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.extras]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
+docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
+
+[[package]]
+name = "black"
+version = "21.5b2"
+description = "The uncompromising code formatter."
+category = "dev"
+optional = false
+python-versions = ">=3.6.2"
+
+[package.dependencies]
+appdirs = "*"
+click = ">=7.1.2"
+mypy-extensions = ">=0.4.3"
+pathspec = ">=0.8.1,<1"
+regex = ">=2020.1.8"
+toml = ">=0.10.1"
+
+[package.extras]
+colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"]
+python2 = ["typed-ast (>=1.4.2)"]
+uvloop = ["uvloop (>=0.15.2)"]
+
+[[package]]
+name = "certifi"
+version = "2021.5.30"
+description = "Python package for providing Mozilla's CA Bundle."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "cfgv"
+version = "3.3.0"
+description = "Validate configuration and produce human readable error messages."
+category = "dev"
+optional = false
+python-versions = ">=3.6.1"
+
+[[package]]
+name = "click"
+version = "8.0.1"
+description = "Composable command line interface toolkit"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.4"
+description = "Cross-platform colored terminal text."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "coverage"
+version = "5.5"
+description = "Code coverage measurement for Python"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
+
+[package.extras]
+toml = ["toml"]
+
+[[package]]
+name = "distlib"
+version = "0.3.2"
+description = "Distribution utilities"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "filelock"
+version = "3.0.12"
+description = "A platform independent file lock."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "flake8"
+version = "3.9.2"
+description = "the modular source code checker: pep8 pyflakes and co"
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+
+[package.dependencies]
+mccabe = ">=0.6.0,<0.7.0"
+pycodestyle = ">=2.7.0,<2.8.0"
+pyflakes = ">=2.3.0,<2.4.0"
+
+[[package]]
+name = "flask"
+version = "1.1.2"
+description = "A simple framework for building complex web applications."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+click = ">=5.1"
+itsdangerous = ">=0.24"
+Jinja2 = ">=2.10.1"
+Werkzeug = ">=0.15"
+
+[package.extras]
+dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
+docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
+dotenv = ["python-dotenv"]
+
+[[package]]
+name = "h11"
+version = "0.12.0"
+description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "httpcore"
+version = "0.13.3"
+description = "A minimal low-level HTTP client."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+h11 = ">=0.11,<0.13"
+sniffio = ">=1.0.0,<2.0.0"
+
+[package.extras]
+http2 = ["h2 (>=3,<5)"]
+
+[[package]]
+name = "httpx"
+version = "0.18.1"
+description = "The next generation HTTP client."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+certifi = "*"
+httpcore = ">=0.13.0,<0.14.0"
+rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]}
+sniffio = "*"
+
+[package.extras]
+brotli = ["brotlicffi (>=1.0.0,<2.0.0)"]
+http2 = ["h2 (>=3.0.0,<4.0.0)"]
+
+[[package]]
+name = "identify"
+version = "2.2.9"
+description = "File identification library for Python"
+category = "dev"
+optional = false
+python-versions = ">=3.6.1"
+
+[package.extras]
+license = ["editdistance-s"]
+
+[[package]]
+name = "idna"
+version = "3.2"
+description = "Internationalized Domain Names in Applications (IDNA)"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+
+[[package]]
+name = "iniconfig"
+version = "1.1.1"
+description = "iniconfig: brain-dead simple config-ini parsing"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "isort"
+version = "5.8.0"
+description = "A Python utility / library to sort Python imports."
+category = "dev"
+optional = false
+python-versions = ">=3.6,<4.0"
+
+[package.extras]
+pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
+requirements_deprecated_finder = ["pipreqs", "pip-api"]
+colors = ["colorama (>=0.4.3,<0.5.0)"]
+
+[[package]]
+name = "itsdangerous"
+version = "2.0.1"
+description = "Safely pass data to untrusted environments and back."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "jinja2"
+version = "3.0.1"
+description = "A very fast and expressive template engine."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
+[[package]]
+name = "markupsafe"
+version = "2.0.1"
+description = "Safely add untrusted strings to HTML/XML markup."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "mccabe"
+version = "0.6.1"
+description = "McCabe checker, plugin for flake8"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "mypy-extensions"
+version = "0.4.3"
+description = "Experimental type system extensions for programs checked with the mypy typechecker."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "nodeenv"
+version = "1.6.0"
+description = "Node.js virtual environment builder"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "packaging"
+version = "20.9"
+description = "Core utilities for Python packages"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.dependencies]
+pyparsing = ">=2.0.2"
+
+[[package]]
+name = "pathspec"
+version = "0.8.1"
+description = "Utility library for gitignore style pattern matching of file paths."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "pluggy"
+version = "0.13.1"
+description = "plugin and hook calling mechanisms for python"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+
+[[package]]
+name = "pre-commit"
+version = "2.13.0"
+description = "A framework for managing and maintaining multi-language pre-commit hooks."
+category = "dev"
+optional = false
+python-versions = ">=3.6.1"
+
+[package.dependencies]
+cfgv = ">=2.0.0"
+identify = ">=1.0.0"
+nodeenv = ">=0.11.1"
+pyyaml = ">=5.1"
+toml = "*"
+virtualenv = ">=20.0.8"
+
+[[package]]
+name = "py"
+version = "1.10.0"
+description = "library with cross-python path, ini-parsing, io, code, log facilities"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pyaes"
+version = "1.6.1"
+description = "Pure-Python Implementation of the AES block-cipher and common modes of operation"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "pyasn1"
+version = "0.4.8"
+description = "ASN.1 types and codecs"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "pycodestyle"
+version = "2.7.0"
+description = "Python style guide checker"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pydantic"
+version = "1.8.2"
+description = "Data validation and settings management using python 3.6 type hinting"
+category = "main"
+optional = false
+python-versions = ">=3.6.1"
+
+[package.dependencies]
+typing-extensions = ">=3.7.4.3"
+
+[package.extras]
+dotenv = ["python-dotenv (>=0.10.4)"]
+email = ["email-validator (>=1.0.3)"]
+
+[[package]]
+name = "pyflakes"
+version = "2.3.1"
+description = "passive checker of Python programs"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pyparsing"
+version = "2.4.7"
+description = "Python parsing module"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "pytest"
+version = "6.2.4"
+description = "pytest: simple powerful testing with Python"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
+attrs = ">=19.2.0"
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=0.12,<1.0.0a1"
+py = ">=1.8.2"
+toml = "*"
+
+[package.extras]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+
+[[package]]
+name = "pytest-asyncio"
+version = "0.15.1"
+description = "Pytest support for asyncio."
+category = "dev"
+optional = false
+python-versions = ">= 3.6"
+
+[package.dependencies]
+pytest = ">=5.4.0"
+
+[package.extras]
+testing = ["coverage", "hypothesis (>=5.7.1)"]
+
+[[package]]
+name = "pytest-cov"
+version = "2.12.1"
+description = "Pytest plugin for measuring coverage."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+coverage = ">=5.2.1"
+pytest = ">=4.6"
+toml = "*"
+
+[package.extras]
+testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"]
+
+[[package]]
+name = "pytz"
+version = "2021.1"
+description = "World timezone definitions, modern and historical"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "pyyaml"
+version = "5.4.1"
+description = "YAML parser and emitter for Python"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+
+[[package]]
+name = "regex"
+version = "2021.4.4"
+description = "Alternative regular expression module, to replace re."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "rfc3986"
+version = "1.5.0"
+description = "Validating URI References per RFC 3986"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+idna = {version = "*", optional = true, markers = "extra == \"idna2008\""}
+
+[package.extras]
+idna2008 = ["idna"]
+
+[[package]]
+name = "rsa"
+version = "4.7.2"
+description = "Pure-Python RSA implementation"
+category = "main"
+optional = false
+python-versions = ">=3.5, <4"
+
+[package.dependencies]
+pyasn1 = ">=0.1.3"
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "sniffio"
+version = "1.2.0"
+description = "Sniff out which async library your code is running under"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+
+[[package]]
+name = "telethon"
+version = "1.14.0"
+description = "Full-featured Telegram client library for Python 3"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+
+[package.dependencies]
+pyaes = "*"
+rsa = "*"
+
+[package.extras]
+cryptg = ["cryptg"]
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+description = "Python Library for Tom's Obvious, Minimal Language"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "typing-extensions"
+version = "3.10.0.0"
+description = "Backported and Experimental Type Hints for Python 3.5+"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "virtualenv"
+version = "20.4.7"
+description = "Virtual Python Environment builder"
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
+
+[package.dependencies]
+appdirs = ">=1.4.3,<2"
+distlib = ">=0.3.1,<1"
+filelock = ">=3.0.0,<4"
+six = ">=1.9.0,<2"
+
+[package.extras]
+docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"]
+testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)", "xonsh (>=0.9.16)"]
+
+[[package]]
+name = "werkzeug"
+version = "2.0.1"
+description = "The comprehensive WSGI web application library."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+watchdog = ["watchdog"]
+
+[metadata]
+lock-version = "1.1"
+python-versions = "^3.9"
+content-hash = "49ee7fc2622e2d548e496f801a6e87d68f8117c8921998687b05c7dd5d9bc070"
+
+[metadata.files]
+appdirs = [
+    {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
+    {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
+]
+atomicwrites = [
+    {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
+    {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
+]
+attrs = [
+    {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
+    {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
+]
+black = [
+    {file = "black-21.5b2-py3-none-any.whl", hash = "sha256:e5cf21ebdffc7a9b29d73912b6a6a9a4df4ce70220d523c21647da2eae0751ef"},
+    {file = "black-21.5b2.tar.gz", hash = "sha256:1fc0e0a2c8ae7d269dfcf0c60a89afa299664f3e811395d40b1922dff8f854b5"},
+]
+certifi = [
+    {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"},
+    {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"},
+]
+cfgv = [
+    {file = "cfgv-3.3.0-py2.py3-none-any.whl", hash = "sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1"},
+    {file = "cfgv-3.3.0.tar.gz", hash = "sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1"},
+]
+click = [
+    {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
+    {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
+]
+colorama = [
+    {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
+    {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
+]
+coverage = [
+    {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"},
+    {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"},
+    {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"},
+    {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"},
+    {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"},
+    {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"},
+    {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"},
+    {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"},
+    {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"},
+    {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"},
+    {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"},
+    {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"},
+    {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"},
+    {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"},
+    {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"},
+    {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"},
+    {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"},
+    {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"},
+    {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"},
+    {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"},
+    {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"},
+    {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"},
+    {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"},
+    {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"},
+    {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"},
+    {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"},
+    {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"},
+    {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"},
+    {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"},
+    {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"},
+    {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"},
+    {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"},
+    {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"},
+    {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"},
+    {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"},
+    {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"},
+    {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"},
+    {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"},
+    {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"},
+    {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"},
+    {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"},
+    {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"},
+    {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"},
+    {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"},
+    {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"},
+    {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"},
+    {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"},
+    {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"},
+    {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"},
+    {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"},
+    {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"},
+    {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"},
+]
+distlib = [
+    {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"},
+    {file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"},
+]
+filelock = [
+    {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
+    {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
+]
+flake8 = [
+    {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
+    {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
+]
+flask = [
+    {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
+    {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
+]
+h11 = [
+    {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"},
+    {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"},
+]
+httpcore = [
+    {file = "httpcore-0.13.3-py3-none-any.whl", hash = "sha256:ff614f0ef875b9e5fe0bdd459b31ea0eea282ff12dc82add83d68b3811ee94ad"},
+    {file = "httpcore-0.13.3.tar.gz", hash = "sha256:5d674b57a11275904d4fd0819ca02f960c538e4472533620f322fc7db1ea0edc"},
+]
+httpx = [
+    {file = "httpx-0.18.1-py3-none-any.whl", hash = "sha256:ad2e3db847be736edc4b272c4d5788790a7e5789ef132fc6b5fef8aeb9e9f6e0"},
+    {file = "httpx-0.18.1.tar.gz", hash = "sha256:0a2651dd2b9d7662c70d12ada5c290abcf57373b9633515fe4baa9f62566086f"},
+]
+identify = [
+    {file = "identify-2.2.9-py2.py3-none-any.whl", hash = "sha256:96c57d493184daecc7299acdeef0ad7771c18a59931ea927942df393688fe849"},
+    {file = "identify-2.2.9.tar.gz", hash = "sha256:3a8493cf49cfe4b28d50865e38f942c11be07a7b0aab8e715073e17f145caacc"},
+]
+idna = [
+    {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"},
+    {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"},
+]
+iniconfig = [
+    {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
+    {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
+]
+isort = [
+    {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"},
+    {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"},
+]
+itsdangerous = [
+    {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"},
+    {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"},
+]
+jinja2 = [
+    {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"},
+    {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"},
+]
+markupsafe = [
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
+    {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
+]
+mccabe = [
+    {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
+    {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
+]
+mypy-extensions = [
+    {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
+    {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
+]
+nodeenv = [
+    {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"},
+    {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
+]
+packaging = [
+    {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"},
+    {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"},
+]
+pathspec = [
+    {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"},
+    {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"},
+]
+pluggy = [
+    {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
+    {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
+]
+pre-commit = [
+    {file = "pre_commit-2.13.0-py2.py3-none-any.whl", hash = "sha256:b679d0fddd5b9d6d98783ae5f10fd0c4c59954f375b70a58cbe1ce9bcf9809a4"},
+    {file = "pre_commit-2.13.0.tar.gz", hash = "sha256:764972c60693dc668ba8e86eb29654ec3144501310f7198742a767bec385a378"},
+]
+py = [
+    {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
+    {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
+]
+pyaes = [
+    {file = "pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"},
+]
+pyasn1 = [
+    {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"},
+    {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"},
+    {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"},
+    {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"},
+    {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"},
+    {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"},
+    {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"},
+    {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"},
+    {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"},
+    {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"},
+    {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"},
+    {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"},
+    {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"},
+]
+pycodestyle = [
+    {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"},
+    {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
+]
+pydantic = [
+    {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"},
+    {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"},
+    {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"},
+    {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"},
+    {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"},
+    {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"},
+    {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"},
+    {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"},
+    {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"},
+    {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"},
+    {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"},
+    {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"},
+    {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"},
+    {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"},
+    {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"},
+    {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"},
+    {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"},
+    {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"},
+    {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"},
+    {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"},
+    {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"},
+    {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"},
+]
+pyflakes = [
+    {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
+    {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
+]
+pyparsing = [
+    {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
+    {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
+]
+pytest = [
+    {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"},
+    {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"},
+]
+pytest-asyncio = [
+    {file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"},
+    {file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"},
+]
+pytest-cov = [
+    {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
+    {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"},
+]
+pytz = [
+    {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"},
+    {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
+]
+pyyaml = [
+    {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"},
+    {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"},
+    {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"},
+    {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"},
+    {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"},
+    {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"},
+    {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"},
+    {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"},
+    {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"},
+    {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"},
+    {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"},
+    {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"},
+    {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"},
+    {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"},
+    {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"},
+    {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"},
+    {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"},
+    {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"},
+    {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"},
+    {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"},
+    {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"},
+]
+regex = [
+    {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"},
+    {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"},
+    {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"},
+    {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"},
+    {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"},
+    {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"},
+    {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"},
+    {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"},
+    {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"},
+    {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"},
+    {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"},
+    {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"},
+    {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"},
+]
+rfc3986 = [
+    {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"},
+    {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"},
+]
+rsa = [
+    {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"},
+    {file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"},
+]
+six = [
+    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+sniffio = [
+    {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"},
+    {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"},
+]
+telethon = [
+    {file = "Telethon-1.14.0-py3-none-any.whl", hash = "sha256:c8b56e26bd4588e8e4e13b7866b86eab360d806358b110066af7a2b25be14fb9"},
+    {file = "Telethon-1.14.0.tar.gz", hash = "sha256:d8bb37f80c4a8befa92d0525f00a578a74064645e48d7aa0cc4731f3d813e1b9"},
+]
+toml = [
+    {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
+    {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
+]
+typing-extensions = [
+    {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
+    {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
+    {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"},
+]
+virtualenv = [
+    {file = "virtualenv-20.4.7-py2.py3-none-any.whl", hash = "sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"},
+    {file = "virtualenv-20.4.7.tar.gz", hash = "sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467"},
+]
+werkzeug = [
+    {file = "Werkzeug-2.0.1-py3-none-any.whl", hash = "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"},
+    {file = "Werkzeug-2.0.1.tar.gz", hash = "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42"},
+]
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..76e10057532760cbee9e9aca4b2cc2a25607e87c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,30 @@
+[tool.poetry]
+name = "bot_s3rius"
+version = "0.1.0"
+description = "Telegram bot for @s3rius_san"
+readme = "README.md"
+authors = ["Pavel Kirilin <win10@list.ru>"]
+
+[tool.poetry.dependencies]
+python = "^3.9"
+Flask = "1.1.2"
+pydantic = "^1.8.2"
+pytz = "^2021.1"
+Telethon = "1.14.0"
+httpx = "^0.18.1"
+
+[tool.poetry.dev-dependencies]
+pytest = "^6.2.4"
+flake8 = "^3.9.2"
+black = "^21.5b2"
+isort = "^5.8.0"
+pre-commit = "^2.13.0"
+pytest-asyncio = "^0.15.1"
+pytest-cov = "^2.12.1"
+
+[tool.poetry.scripts]
+start_bot = "bot_s3rius.initializator:main"
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
diff --git a/requirements/requirements.base.txt b/requirements/requirements.base.txt
deleted file mode 100644
index d23a95b5a25f078d37521cdb4ed0e9fc3a5c4c2f..0000000000000000000000000000000000000000
--- a/requirements/requirements.base.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Flask==1.1.2
-httpx==0.13.*
-pydantic==1.5.1
-pytz==2020.1
-Telethon==1.14.0
diff --git a/requirements/requirements.dev.txt b/requirements/requirements.dev.txt
deleted file mode 100644
index ef00d8b858fd55634821695dead29d5a95a48bdf..0000000000000000000000000000000000000000
--- a/requirements/requirements.dev.txt
+++ /dev/null
@@ -1,8 +0,0 @@
--r requirements.base.txt
-black==19.10b0
-docker-compose==1.26.0
-flake8==3.8.3
-isort==4.3.21
-pre-commit==2.5.1
-pytest==5.4.3
-pytest-asyncio==0.14.0
diff --git a/src/config.py b/src/config.py
deleted file mode 100644
index 938d672357ea1720bcb938cd1c198805ad7d20ca..0000000000000000000000000000000000000000
--- a/src/config.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from typing import List
-
-from pydantic import BaseSettings
-from pydantic.fields import Field
-from telethon import TelegramClient
-
-__all__ = ["config"]
-
-
-class Config(BaseSettings):
-    telegram_app_id: str = Field(None, env="TELEGRAM_APP_ID", required=True)
-
-    telegram_api_hash: str = Field(None, env="TELEGRAM_API_HASH", required=True)
-
-    libraries_io_token: str = Field(None, env="LIBRARIES_IO_API_TOKEN", required=True)
-
-    telegram_account_phone: str = Field(
-        None, env="TELEGRAM_ACCOUNT_PHONE", required=True
-    )
-
-    app_mode: str = Field(name="app_mode", default="dev", env="APP_MODE")
-
-    debug_mode: bool = False
-
-    flask_port: str = Field(name="flask_port", default="8080", env="FLASK_PORT")
-
-    excluded_chats: List[str] = Field([], env="EXCLUDED_CHATS")
-
-    telegram_client: TelegramClient = None
-
-
-config = Config()
diff --git a/static_messages/app.info b/static_messages/app.info
deleted file mode 100644
index 089ee52bf61b65e7375d44eb6389263937843006..0000000000000000000000000000000000000000
--- a/static_messages/app.info
+++ /dev/null
@@ -1,3 +0,0 @@
-Maintainer: `win10@list.ru`
-Repo url: `repo`
-Last commit: ```Nothing to show```
diff --git a/systemd/bot_s3rius_san.service b/systemd/bot_s3rius_san.service
deleted file mode 100644
index 93450b19247009b38430b1fa59d4c7acc49d1a74..0000000000000000000000000000000000000000
--- a/systemd/bot_s3rius_san.service
+++ /dev/null
@@ -1,15 +0,0 @@
-[Unit]
-Description=S3rius's san account bot.
-After=network.target
-
-[Service]
-Type=simple
-User=bots
-WorkingDirectory=
-ExecStart=/bin/bash -c 'make prod'
-ExecStop=/bin/bash -c 'make clean_prod'
-Restart=on-abort
-
-[Install]
-WantedBy=multi-user.target
-
diff --git a/tests/__init__.py b/tests/__init__.py
index e745c0da8959a1c9ccfa23aeb08adabc9032fc31..9dd23369bee510fcfecba3c3b022c81ad81a988c 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -2,7 +2,7 @@ from unittest.mock import MagicMock
 
 
 def patch_client():
-    from src.config import config
+    from bot_s3rius.config import config
 
     client_mock = MagicMock()
     print("Updating config")
diff --git a/tests/test_fun.py b/tests/test_fun.py
index 57757ab064b419b60f67c8c08cc493f0b70e63e4..a546c377218f5afb5ed3c6cc3a67faebdc6e8fec 100644
--- a/tests/test_fun.py
+++ b/tests/test_fun.py
@@ -1,5 +1,6 @@
 import pytest
-from src.actions import fun
+
+from bot_s3rius.actions import fun
 from tests.conftest import NewMessageTestEvent