From 3df4f6d28c1660231d9fc2039b9d9e41d3ab6c85 Mon Sep 17 00:00:00 2001
From: Sergey Klyuykov <onegreyonewhite@mail.ru>
Date: Tue, 6 Dec 2022 14:23:07 +1000
Subject: [PATCH 1/8] Feature(git): Provide to setup config params for git
 operations + werf build images.

---
 .gitlab-ci.yml             | 18 +++++++++++-------
 docker-compose.yml         |  2 +-
 polemarch/main/repo/vcs.py | 12 ++++++++++--
 polemarch/main/settings.py |  7 ++++++-
 requirements.txt           |  2 +-
 setup.py                   |  4 ++++
 tests.py                   |  5 +++++
 werf-giterminism.yaml      |  4 ++++
 werf.yaml                  | 17 +++++++++++++++++
 9 files changed, 59 insertions(+), 12 deletions(-)
 create mode 100644 werf-giterminism.yaml
 create mode 100644 werf.yaml

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 418969fc..b0a541de 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -157,15 +157,19 @@ release_pypi:
 
 publish_docker:
   stage: publish
-  image: vstconsulting/images:ubuntu
-  services:
-    - name: 'docker:19.03-dind'
-      alias: 'docker_service_host'
+  image: registry.werf.io/werf/werf
+  before_script:
+    - type werf && source $(werf ci-env gitlab --as-file)
+    - werf version
   script:
-    - pip install tox
-    - tox -e release-docker
+    - werf cr login -u $POLEMARCH_DOCKER_USER -p $POLEMARCH_DOCKER_PASSWORD index.docker.io
+    - werf export --repo=$WERF_REPO/storage --tag=$WERF_REPO:$CI_COMMIT_TAG --tag=index.docker.io/$POLEMARCH_DOCKER_IMAGE_NAME:$CI_COMMIT_TAG
+    - werf export --repo=$WERF_REPO/storage --tag=$WERF_REPO:latest --tag=index.docker.io/$POLEMARCH_DOCKER_IMAGE_NAME:latest
+  after_script:
+    - werf cr login -u nobody -p ${WERF_IMAGES_CLEANUP_PASSWORD} ${CI_REGISTRY}
+    - werf cleanup --repo=$WERF_REPO/storage
   rules:
-    - if: '$CI_COMMIT_TAG && $POLEMARCH_DOCKER_USER && $POLEMARCH_DOCKER_PASSWORD && $POLEMARCH_DOCKER_IMAGE_NAME'
+    - if: '$CI_COMMIT_TAG && $POLEMARCH_DOCKER_USER && $POLEMARCH_DOCKER_PASSWORD && $POLEMARCH_DOCKER_IMAGE_NAME && $WERF_IMAGES_CLEANUP_PASSWORD'
       when: on_success
     - when: never
 
diff --git a/docker-compose.yml b/docker-compose.yml
index 65e0b232..bcdec15c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -19,7 +19,7 @@ services:
       - "8080:80"
 
   polemarch:
-    image: polemarch
+    image: ${WERF_MAIN_DOCKER_IMAGE_NAME:-polemarch}
     build: .
     restart: unless-stopped
     depends_on:
diff --git a/polemarch/main/repo/vcs.py b/polemarch/main/repo/vcs.py
index a09e2c22..06fffa9c 100644
--- a/polemarch/main/repo/vcs.py
+++ b/polemarch/main/repo/vcs.py
@@ -14,6 +14,8 @@
 
 
 class _VCS(_Base):  # nocv
+    __slots__ = ()
+
     def vcs_clone(self, *args, **kwargs):
         raise NotImplementedError()
 
@@ -25,7 +27,7 @@ def get_repo(self, *args, **kwargs):
 
 
 class Git(_VCS):
-    __slots__ = ('env', '_fetch_map',)
+    __slots__ = ('env', '_fetch_map', 'target_branch', 'persistent_config_options')
 
     _fetch_statuses = [
         "NEW_TAG", "NEW_HEAD", "HEAD_UPTODATE",
@@ -43,13 +45,17 @@ class Git(_VCS):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.env = self.options.get("GIT_ENV", {})
+        self.persistent_config_options = self.options.get("CONFIG_LIST", ())
         self._fetch_map = {
             1 << x: self._fetch_statuses[x] for x in range(8)
         }
         self.target_branch = self.proj.vars.get('repo_branch', None)
 
     def get_repo(self) -> git.Repo:
-        return git.Repo(self.path)
+        repo = git.Repo(self.path)
+        if self.persistent_config_options:
+            repo.git.set_persistent_git_options(c=self.persistent_config_options)
+        return repo
 
     def vcs_clone(self, source: str, destination, **kwargs) -> git.Repo:
         os.makedirs(destination)
@@ -60,6 +66,8 @@ def vcs_clone(self, source: str, destination, **kwargs) -> git.Repo:
                 **kwargs
             )
             repo = git.Repo(destination)
+            if self.persistent_config_options:
+                repo.git.set_persistent_git_options(c=self.persistent_config_options)
             with repo.git.custom_environment(**kwargs.get('env', {})):
                 self._update_submodules(repo, kill_after_timeout=kwargs.get('kill_after_timeout'))
         except git.GitCommandError as error:
diff --git a/polemarch/main/settings.py b/polemarch/main/settings.py
index a8c717fd..3cdd29f0 100644
--- a/polemarch/main/settings.py
+++ b/polemarch/main/settings.py
@@ -176,9 +176,10 @@ class ArchiveSection(BaseAppendSection):
 
 git_fetch = {}
 git_clone = {}
+git_config_list = ()
 
 if TESTS_RUN:
-    config['git'] = dict(fetch=dict(), clone=dict())
+    config['git'] = dict(fetch={}, clone={}, config={'protocol.file.allow': 'always'})
 
 if 'git' in config:
     git = config['git']
@@ -189,6 +190,9 @@ class ArchiveSection(BaseAppendSection):
     if 'clone' in git:
         git_clone = GitCloneSection('git.clone', config, git['clone']).all()
 
+    if 'config' in git:
+        git_config_list = tuple(f'{k}={v}' for k, v in git['config'].items())
+
 
 archive_section = ArchiveSection('archive', config, config['archive']).all()
 
@@ -230,6 +234,7 @@ class PluginOptionsSection(PluginSection):
         "OPTIONS": {
             "CLONE_KWARGS": git_clone,
             "FETCH_KWARGS": git_fetch,
+            "CONFIG_LIST": git_config_list,
             "GIT_ENV": {
                 "GLOBAL": {
                     "GIT_SSL_NO_VERIFY": "true"
diff --git a/requirements.txt b/requirements.txt
index 906635b4..77bc5f0d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
 # Main
-vstutils[rpc,ldap,doc,prod]~=5.1.11
+vstutils[rpc,doc,prod]~=5.1.11
 docutils~=0.16.0
 markdown2~=2.4.0
 
diff --git a/setup.py b/setup.py
index b1c5165f..d56faca3 100644
--- a/setup.py
+++ b/setup.py
@@ -388,6 +388,10 @@ def make_setup(**opts):
     ext_list = []
 
 install_requirements = load_requirements('requirements.txt', os.getcwd())
+install_requirements = [
+    i.replace('prod', 'prod,ldap') if isinstance(i, str) and i.strip().startswith('vstutils') else i
+    for i in install_requirements
+]
 
 kwargs = dict(
     name='polemarch',
diff --git a/tests.py b/tests.py
index 318ad032..11e9253e 100644
--- a/tests.py
+++ b/tests.py
@@ -906,6 +906,7 @@ def test_sync_git(self, temp_dir):
         submodule = git.Repo.init(submodule_dir)
         submodule.git.add('test_module.py')
         submodule.index.commit('Add module')
+        repo.git.set_persistent_git_options(c='protocol.file.allow=always')
         repo.git.submodule('add', '../submodule/.git', 'lib')
         repo.git.submodule('add', f'{submodule_dir}/.git', 'lib2')
         repo.git.add(all=True)
@@ -1746,6 +1747,8 @@ def test_repo_sync_on_run_for_git_project(self, temp_dir):
         submodule = git.Repo.init(submodule_dir)
         submodule.git.add('test_module.py')
         submodule.index.commit('Add module')
+        submodule.git.set_persistent_git_options(c='protocol.file.allow=always')
+        repo.git.set_persistent_git_options(c='protocol.file.allow=always')
         repo.git.submodule('add', '../submodule/.git', 'lib')
         repo.git.submodule('add', f'{submodule_dir}/.git', 'lib2')
 
@@ -1888,6 +1891,8 @@ def do_GET(self, *args, **kwargs):
             submodule = git.Repo.init(submodule_dir)
             submodule.git.add('test_module.py')
             submodule.index.commit('Add module')
+            submodule.git.set_persistent_git_options(c='protocol.file.allow=always')
+            repo.git.set_persistent_git_options(c='protocol.file.allow=always')
             repo.git.submodule('add', '../submodule/.git', 'lib')
             repo.git.submodule('add', f'{submodule_dir}/.git', 'lib2')
 
diff --git a/werf-giterminism.yaml b/werf-giterminism.yaml
new file mode 100644
index 00000000..87129a5e
--- /dev/null
+++ b/werf-giterminism.yaml
@@ -0,0 +1,4 @@
+giterminismConfigVersion: 1
+helm:
+    allowUncommittedFiles:
+        - ../**/*
diff --git a/werf.yaml b/werf.yaml
new file mode 100644
index 00000000..bbc1d26b
--- /dev/null
+++ b/werf.yaml
@@ -0,0 +1,17 @@
+configVersion: 1
+project: polemarch
+cleanup:
+  disableKubernetesBasedPolicy: true
+  disableGitHistoryBasedPolicy: true
+  disableBuiltWithinLastNHoursPolicy: true
+  keepImagesBuiltWithinLastNHours: 1
+  keepPolicies:
+    - references:
+        branch: /.*/
+        limit:
+          last: 1
+
+---
+image: main
+dockerfile: Dockerfile
+context: .

From 989acd09fc2e44cef18cabc66aac683e511ffc77 Mon Sep 17 00:00:00 2001
From: Sergey Klyuykov <onegreyonewhite@mail.ru>
Date: Wed, 7 Dec 2022 14:38:50 +1000
Subject: [PATCH 2/8] Chore: Use schema field inspection for inventory field.

---
 .gitlab-ci.yml                  | 18 ++++++++++++++----
 doc/api_schema.yaml             | 19 +++++++++++--------
 polemarch/__init__.py           |  2 +-
 polemarch/api/schema.py         | 29 +++++++++++++++++++++++++++++
 polemarch/api/v2/serializers.py | 12 ++++++++++++
 polemarch/main/openapi.py       |  2 --
 polemarch/main/settings.py      |  1 +
 tox.ini                         |  2 +-
 8 files changed, 69 insertions(+), 16 deletions(-)
 create mode 100644 polemarch/api/schema.py

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b0a541de..d9ceb130 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -51,6 +51,16 @@ stages:
       when: on_success
     - when: never
 
+
+.js_tests_template: &branch_js_tests
+  <<: *branch_tests
+  image: vstconsulting/images:node
+  before_script:
+    - yarn install
+  script:
+    - yarn test
+
+
 # Branch tests
 ###########################################
 code_style:
@@ -60,12 +70,12 @@ code_style:
     TOX_ENVS: "flake,pylint"
 
 js_style:
-  <<: *branch_tests
+  <<: *branch_js_tests
   stage: code_standarts
-  variables:
-    TOX_ENVS: "js_style"
+  script:
+    - yarn lint
 
-py38-coverage:
+py311-coverage:
   <<: *branch_tests
   variables:
     TOX_ENVS: "$CI_BUILD_NAME"
diff --git a/doc/api_schema.yaml b/doc/api_schema.yaml
index 3f7b4454..9628f948 100644
--- a/doc/api_schema.yaml
+++ b/doc/api_schema.yaml
@@ -24,9 +24,9 @@ info:
       url: https://gitlab.com/vstconsulting/polemarch.git
     Request:
       - name: Question
-        url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Ask&issue%5Btitle%5D=Ask%20about%20version%202.1.2
+        url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Ask&issue%5Btitle%5D=Ask%20about%20version%202.3.0
       - name: Bug report
-        url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Bug&issue%5Btitle%5D=Bug%20in%20version%202.1.2
+        url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Bug&issue%5Btitle%5D=Bug%20in%20version%202.3.0
       - name: Feature request
         url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Feature%20request&issue%5Btitle%5D=
   x-menu:
@@ -67,9 +67,9 @@ info:
     login_url: /account/login/
   x-subscriptions-prefix: polemarch.update
   x-versions:
-    application: 2.1.2
-    library: 2.1.2
-    vstutils: 5.1.10
+    application: 2.3.0
+    library: 2.3.0
+    vstutils: 5.1.11
     django: 3.2.16
     djangorestframework: 3.14.0
     drf_yasg: 1.21.4
@@ -10879,8 +10879,9 @@ definitions:
       inventory:
         title: Inventory
         type: integer
-        x-nullable: true
         format: inventory
+        readOnly: true
+        x-nullable: true
       kind:
         title: Kind
         type: string
@@ -10996,8 +10997,9 @@ definitions:
       inventory:
         title: Inventory
         type: integer
-        x-nullable: true
         format: inventory
+        readOnly: true
+        x-nullable: true
       kind:
         title: Kind
         type: string
@@ -13333,8 +13335,9 @@ definitions:
       inventory:
         title: Inventory
         type: integer
-        x-nullable: true
         format: inventory
+        readOnly: true
+        x-nullable: true
       kind:
         title: Kind
         type: string
diff --git a/polemarch/__init__.py b/polemarch/__init__.py
index 62ff2623..0946948f 100644
--- a/polemarch/__init__.py
+++ b/polemarch/__init__.py
@@ -31,6 +31,6 @@
     "VST_ROOT_URLCONF": os.getenv("VST_ROOT_URLCONF", 'vstutils.urls'),
 }
 
-__version__ = "2.2.0"
+__version__ = "2.3.0"
 
 prepare_environment(**default_settings)
diff --git a/polemarch/api/schema.py b/polemarch/api/schema.py
new file mode 100644
index 00000000..72a5887d
--- /dev/null
+++ b/polemarch/api/schema.py
@@ -0,0 +1,29 @@
+from drf_yasg.inspectors.base import FieldInspector, NotHandled
+from drf_yasg import openapi
+from vstutils.api.schema.schema import VSTAutoSchema
+from vstutils.api.schema.inspectors import field_extra_handler
+
+from .v2.serializers import InventoryAutoCompletionField
+
+
+class InventoryFieldInspector(FieldInspector):
+    def field_to_swagger_object(self, field, swagger_object_type, use_references, **kw):
+        # pylint: disable=invalid-name
+        if not isinstance(field, InventoryAutoCompletionField):
+            return NotHandled
+
+        SwaggerType, _ = self._get_partial_types(
+            field, swagger_object_type, use_references, **kw
+        )
+        kwargs = {
+            'type': openapi.TYPE_INTEGER if field.real_type == int else openapi.TYPE_STRING,
+            'format': 'inventory'
+        }
+
+        return SwaggerType(**field_extra_handler(field, **kwargs))
+
+
+class PolemarchAutoSchema(VSTAutoSchema):
+    field_inspectors = [
+        InventoryFieldInspector,
+    ] + VSTAutoSchema.field_inspectors
diff --git a/polemarch/api/v2/serializers.py b/polemarch/api/v2/serializers.py
index a8da8a20..f53315aa 100644
--- a/polemarch/api/v2/serializers.py
+++ b/polemarch/api/v2/serializers.py
@@ -68,6 +68,9 @@ def to_representation(self, value):
 
 
 class InventoryAutoCompletionField(vst_fields.VSTCharField):
+    def __init__(self, **kwargs):
+        self.real_type = kwargs.pop('real_type', str)
+        super().__init__(**kwargs)
 
     def to_internal_value(self, data):
         inventory = super().to_internal_value(data)
@@ -83,6 +86,14 @@ def to_internal_value(self, data):
                 path_validator(inventory)
         return inventory
 
+    def to_representation(self, value):
+        if self.real_type == int:
+            if isinstance(value, models.Inventory):
+                return value.id
+            elif isinstance(value, int):  # nocv
+                return value
+        return super().to_representation(value)
+
 
 # Serializers
 class FactsSerializer(DataSerializer):
@@ -209,6 +220,7 @@ class Meta:
 
 
 class HistorySerializer(_SignalSerializer):
+    inventory = InventoryAutoCompletionField(allow_null=True, read_only=True, real_type=int)
     status = serializers.ChoiceField(choices=models.History.statuses, required=False)
     executor = vst_fields.DependEnumField(field='initiator_type', types={
         'project': vst_fields.FkModelField(select=UserSerializer,
diff --git a/polemarch/main/openapi.py b/polemarch/main/openapi.py
index 7fab0664..bbcb68c6 100644
--- a/polemarch/main/openapi.py
+++ b/polemarch/main/openapi.py
@@ -71,8 +71,6 @@ def set_inventory(model):
                     for type_field in field['x-options']['types'].values():
                         if isinstance(type_field, dict):
                             type_field['format'] = 'inventory'
-                else:
-                    field['format'] = 'inventory'
 
             elif field.get('format') == 'dynamic':
                 for type_field in field['x-options']['types'].values():
diff --git a/polemarch/main/settings.py b/polemarch/main/settings.py
index 3cdd29f0..bc14e2ba 100644
--- a/polemarch/main/settings.py
+++ b/polemarch/main/settings.py
@@ -77,6 +77,7 @@
 ]
 
 SWAGGER_SETTINGS['DEFAULT_INFO'] = '{}.api.v2.swagger.api_info'.format(VST_PROJECT_LIB_NAME)
+SWAGGER_SETTINGS['DEFAULT_AUTO_SCHEMA_CLASS'] = '{}.api.schema.PolemarchAutoSchema'.format(VST_PROJECT_LIB_NAME)
 
 OPENAPI_EXTRA_LINKS = dict()
 OPENAPI_EXTRA_LINKS['Request'] = [
diff --git a/tox.ini b/tox.ini
index 8b2db20d..7a19f557 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = flake,pylint,py36-coverage,py38-install
+envlist = flake,pylint,py311-coverage,py36-install
 skipsdist = True
 setenv = PIP_CONFIG_FILE=.pip.conf
 whitelist_externals =

From 74055f1540d89bd95f71d78973a2219904706829 Mon Sep 17 00:00:00 2001
From: Sergey Klyuykov <onegreyonewhite@mail.ru>
Date: Fri, 9 Dec 2022 18:24:44 +0400
Subject: [PATCH 3/8] Fix(CI): Migrate to new images.

---
 .gitlab-ci.yml | 16 ++++++++--------
 tox.ini        | 22 +++++++++++-----------
 tox_build.ini  |  2 +-
 3 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d9ceb130..c830fe1c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,6 @@
 # set to local images because too long execution
 default:
-  image: vstconsulting/images:build
+  image: registry.gitlab.com/vstconsulting/images:build
 
 variables:
   GET_SOURCES_ATTEMPTS: 3
@@ -34,7 +34,7 @@ stages:
 ###########################################
 .branch_tests_template: &branch_tests
   stage: test
-  image: vstconsulting/images:tox
+  image: registry.gitlab.com/vstconsulting/images:tox
   coverage: '/\d+\%\s*$/'
   variables:
     TOX_ENVS: ""
@@ -54,7 +54,7 @@ stages:
 
 .js_tests_template: &branch_js_tests
   <<: *branch_tests
-  image: vstconsulting/images:node
+  image: registry.gitlab.com/vstconsulting/images:node-tests
   before_script:
     - yarn install
   script:
@@ -89,7 +89,7 @@ py36-install:
 ###########################################
 #deploy_environment:
 #  stage: release
-#  image: vstconsulting/images:tox
+#  image: registry.gitlab.com/vstconsulting/images:tox
 #  services:
 #    - name: "docker:19.03-dind"
 #      alias: "docker_service_host"
@@ -107,7 +107,7 @@ py36-install:
 #
 #delete_environment:
 #  stage: release
-#  image: vstconsulting/images:tox
+#  image: registry.gitlab.com/vstconsulting/images:tox
 #  script:
 #    - tox -e destroy_env
 #  environment:
@@ -121,7 +121,7 @@ py36-install:
 
 release:
   stage: release
-  image: vstconsulting/images:tox
+  image: registry.gitlab.com/vstconsulting/images:tox
   rules:
     - if: '$CI_COMMIT_BRANCH == "master" && $GIT_ACCESS_USER && $GIT_ACCESS_PASSWORD'
       when: on_success
@@ -149,7 +149,7 @@ pages:
 
 release_pypi:
   stage: release
-  image: vstconsulting/images:build
+  image: registry.gitlab.com/vstconsulting/images:build
   rules:
     - if: '$CI_COMMIT_TAG && $PYPI_UPLOAD_PASSWORD && $PYPI_UPLOAD_NAME'
       when: on_success
@@ -185,7 +185,7 @@ publish_docker:
 
 publish_release:
   stage: publish
-  image: vstconsulting/images:tox
+  image: registry.gitlab.com/vstconsulting/images:tox
   allow_failure: true
   needs: ["release_pypi"]
   rules:
diff --git a/tox.ini b/tox.ini
index 7a19f557..16490e08 100644
--- a/tox.ini
+++ b/tox.ini
@@ -2,7 +2,7 @@
 envlist = flake,pylint,py311-coverage,py36-install
 skipsdist = True
 setenv = PIP_CONFIG_FILE=.pip.conf
-whitelist_externals =
+allowlist_externals =
     rm
     bash
 
@@ -17,7 +17,7 @@ passenv =
     DJANGO_LOG_LEVEL
     CC
     BUILD_COMPILE
-whitelist_externals =
+allowlist_externals =
     rm
     ls
     ln
@@ -73,7 +73,7 @@ commands =
 [testenv:js_style]
 changedir = ./
 deps =
-whitelist_externals = yarn
+allowlist_externals = yarn
 commands =
   yarn install
   yarn lint
@@ -85,7 +85,7 @@ setenv =
     LANG = en_US.UTF-8
 passenv = *
 changedir = .
-whitelist_externals =
+allowlist_externals =
     tox
     rm
 commands =
@@ -98,7 +98,7 @@ changedir = ./doc/
 setenv =
     LC_ALL = en_US.UTF-8
     LANG = en_US.UTF-8
-whitelist_externals =
+allowlist_externals =
     cp
     make
 commands =
@@ -115,7 +115,7 @@ setenv =
     BUILD_OPTIMIZATION = true
     BUILD_COMPILE = true
 passenv = *
-whitelist_externals = *
+allowlist_externals = *
 commands =
     rm -frv {envdir}/dist
     python setup.py compile_docs
@@ -134,7 +134,7 @@ passenv = *
 setenv =
     LC_ALL = en_US.UTF-8
     LANG = en_US.UTF-8
-whitelist_externals =
+allowlist_externals =
     mkdir
     ls
 commands =
@@ -154,7 +154,7 @@ setenv =
     LC_ALL = en_US.UTF-8
     LANG = en_US.UTF-8
 passenv = *
-whitelist_externals = *
+allowlist_externals = *
 commands =
     python setup.py install_egg_info
     pip install -U -e .[test]
@@ -169,7 +169,7 @@ passenv = *
 setenv =
     LC_ALL = en_US.UTF-8
     LANG = en_US.UTF-8
-whitelist_externals =
+allowlist_externals =
     /bin/sh
 commands =
     ansible-playbook -i localhost, --connection local k8s_env_deploy.yaml -vvvv
@@ -185,7 +185,7 @@ passenv = *
 setenv =
     LC_ALL = en_US.UTF-8
     LANG = en_US.UTF-8
-whitelist_externals =
+allowlist_externals =
     /bin/sh
 commands =
     ansible-playbook -i localhost, --connection local k8s_env_destroy.yaml -vvvv
@@ -201,7 +201,7 @@ passenv = *
 setenv =
     LC_ALL = en_US.UTF-8
     LANG = en_US.UTF-8
-whitelist_externals =
+allowlist_externals =
     /usr/bin/bash
     docker
     git
diff --git a/tox_build.ini b/tox_build.ini
index 342370e2..d31bae86 100644
--- a/tox_build.ini
+++ b/tox_build.ini
@@ -5,7 +5,7 @@ skipsdist = True
 [testenv]
 passenv = *
 setenv = CCACHE_DIR = {envdir}/.ccache
-whitelist_externals =
+allowlist_externals =
     ls
     rm
     bash

From 38177888b09d0e3a62f541684e92a055483f0b9c Mon Sep 17 00:00:00 2001
From: Sergey Klyuykov <onegreyonewhite@mail.ru>
Date: Tue, 13 Dec 2022 14:28:30 +1000
Subject: [PATCH 4/8] Feature(backend): Add project and execution metrics.

---
 doc/api_schema.yaml        | 49 +++++++++++++++++++++++++++++++++++++-
 doc/config.rst             |  1 +
 polemarch/__init__.py      |  2 +-
 polemarch/main/settings.py |  2 ++
 polemarch/metrics.py       | 31 ++++++++++++++++++++++++
 requirements.txt           |  2 +-
 test_data/metrics.txt      |  9 +++++++
 tests.py                   | 33 +++++++++++++++++++++++++
 8 files changed, 126 insertions(+), 3 deletions(-)
 create mode 100644 polemarch/metrics.py
 create mode 100644 test_data/metrics.txt

diff --git a/doc/api_schema.yaml b/doc/api_schema.yaml
index 9628f948..813b8bb0 100644
--- a/doc/api_schema.yaml
+++ b/doc/api_schema.yaml
@@ -69,7 +69,7 @@ info:
   x-versions:
     application: 2.3.0
     library: 2.3.0
-    vstutils: 5.1.11
+    vstutils: 5.2.1
     django: 3.2.16
     djangorestframework: 3.14.0
     drf_yasg: 1.21.4
@@ -104,6 +104,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - name
               - -name
@@ -256,6 +257,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -467,6 +469,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -692,6 +695,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -955,6 +959,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -1191,6 +1196,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -1399,6 +1405,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -1642,6 +1649,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -1863,6 +1871,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -2076,6 +2085,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -2290,6 +2300,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -2482,6 +2493,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -2704,6 +2716,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -2897,6 +2910,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -3099,6 +3113,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -3239,6 +3254,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -3400,6 +3416,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -3627,6 +3644,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -3834,6 +3852,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -4097,6 +4116,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -4333,6 +4353,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -4541,6 +4562,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -4784,6 +4806,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -5005,6 +5028,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -5218,6 +5242,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -5478,6 +5503,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -5702,6 +5728,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - name
               - -name
@@ -5923,6 +5950,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -6166,6 +6194,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -6408,6 +6437,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -6560,6 +6590,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -6739,6 +6770,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -6982,6 +7014,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -7199,6 +7232,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -7482,6 +7516,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -7733,6 +7768,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -7951,6 +7987,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -8218,6 +8255,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -8457,6 +8495,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -8640,6 +8679,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -8786,6 +8826,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -9019,6 +9060,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -9234,6 +9276,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -9412,6 +9455,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -9600,6 +9644,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -9840,6 +9885,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
@@ -10189,6 +10235,7 @@ paths:
           type: array
           items:
             type: string
+            format: ordering_choices
             enum:
               - id
               - -id
diff --git a/doc/config.rst b/doc/config.rst
index c3a99405..40bb1481 100644
--- a/doc/config.rst
+++ b/doc/config.rst
@@ -335,6 +335,7 @@ session_timeout, static_files_url or pagination limit.
 * **session_timeout** - Session life-cycle time. ``Default: 2w`` (two weeks).
 * **rest_page_limit** - Default limit of objects in API list. ``Default: 1000``.
 * **public_openapi** - Allow to have access to OpenAPI schema from public. ``Default: false``.
+* **history_metrics_window** - Timeframe in seconds of collecting execution history statuses. ``Default: 1min``.
 
 .. note:: You can find more Web options in :ref:`vstutils:web`.
 
diff --git a/polemarch/__init__.py b/polemarch/__init__.py
index 20da731f..0946948f 100644
--- a/polemarch/__init__.py
+++ b/polemarch/__init__.py
@@ -31,6 +31,6 @@
     "VST_ROOT_URLCONF": os.getenv("VST_ROOT_URLCONF", 'vstutils.urls'),
 }
 
-__version__ = "2.3.1"
+__version__ = "2.3.0"
 
 prepare_environment(**default_settings)
diff --git a/polemarch/main/settings.py b/polemarch/main/settings.py
index bc14e2ba..fadd378d 100644
--- a/polemarch/main/settings.py
+++ b/polemarch/main/settings.py
@@ -301,6 +301,8 @@ class PluginOptionsSection(PluginSection):
 
 PROJECT_REPOSYNC_WAIT_SECONDS = main.getseconds('repo_sync_on_run_timeout', fallback='1:00')
 PROJECT_CI_HANDLER_CLASS = "{}.main.ci.DefaultHandler".format(VST_PROJECT_LIB_NAME)
+METRICS_BACKEND_CLASS = "{}.metrics.PolemarchBackend".format(VST_PROJECT_LIB_NAME)
+HISTORY_METRICS_WINDOW = web.getseconds('history_metrics_window', fallback=600)
 
 
 __PWA_ICONS_SIZES = [
diff --git a/polemarch/metrics.py b/polemarch/metrics.py
new file mode 100644
index 00000000..864acb64
--- /dev/null
+++ b/polemarch/metrics.py
@@ -0,0 +1,31 @@
+from datetime import timedelta
+from django.conf import settings
+from django.utils.timezone import now
+from django.db.models import Count
+from vstutils.api.metrics import DefaultBackend
+from .main.models import History, Project
+
+
+def get_polemarch_metrics():
+    histories = History.objects.\
+        filter(start_time__gte=now()-timedelta(seconds=settings.HISTORY_METRICS_WINDOW)).\
+        values('status').\
+        annotate(total=Count('status')).\
+        values('status', 'total').\
+        order_by('status')
+
+    projects = Project.objects.\
+        values('status'). \
+        annotate(total=Count('status')). \
+        values('status', 'total'). \
+        order_by('status')
+
+    for qs in (histories, projects):
+        for obj in qs:
+            yield '{prefix}_' + qs.model.__name__.lower() + '_total', ({'status': obj['status']}, obj['total'])
+
+
+class PolemarchBackend(DefaultBackend):
+    metrics_list = (
+        (None, get_polemarch_metrics),
+    )
diff --git a/requirements.txt b/requirements.txt
index 77bc5f0d..8cf258ed 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
 # Main
-vstutils[rpc,doc,prod]~=5.1.11
+vstutils[rpc,doc,prod]~=5.2.2
 docutils~=0.16.0
 markdown2~=2.4.0
 
diff --git a/test_data/metrics.txt b/test_data/metrics.txt
new file mode 100644
index 00000000..4ed8787d
--- /dev/null
+++ b/test_data/metrics.txt
@@ -0,0 +1,9 @@
+python_info{version="$VERSION"} 1
+polemarch_database_connections 1
+polemarch_cache_connections 4
+polemarch_history_total{status="ERROR"} 310
+polemarch_history_total{status="OFFLINE"} 110
+polemarch_history_total{status="OK"} 10
+polemarch_project_total{status="ERROR"} 4
+polemarch_project_total{status="NEW"} 1
+polemarch_project_total{status="OK"} 3
diff --git a/tests.py b/tests.py
index ed546f23..da39dfbc 100644
--- a/tests.py
+++ b/tests.py
@@ -2,6 +2,7 @@
 import io
 import os
 import re
+import sys
 import time
 import shutil
 from threading import Thread
@@ -4278,6 +4279,38 @@ def test_menu(self):
         self.assertEqual(reg_schema['info']['x-menu'], PROJECT_MENU + [system_tab_user])
 
 
+class MetricsTestCase(VSTBaseTestCase):
+    def setUp(self):
+        super().setUp()
+        History = self.get_model_class('main.History')
+        Project = self.get_model_class('main.Project')
+
+        self.history_status_count_map = {
+            "OK": 10,
+            'OFFLINE': 110,
+            'ERROR': 310,
+        }
+
+        for status, count in self.history_status_count_map.items():
+            for i in range(count):
+                History.objects.create(status=status)
+
+        Project.objects.create(name=f'test_metrics_{i}')
+        for i in range(3):
+            Project.objects.create(name=f'test_metrics_{i}', status='OK')
+        for i in range(4):
+            Project.objects.create(name=f'test_metrics_{i}', status='ERROR')
+
+    def test_metrics(self):
+        result = self.get_result('get', '/api/metrics/')
+        expected = (Path(Path(__file__).parent) / 'test_data' / 'metrics.txt').read_text('utf-8')
+        expected = expected.replace(
+            '$VERSION',
+            f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}'
+        )
+        self.assertEqual(result, expected)
+
+
 class BaseExecutionPluginUnitTestCase(VSTBaseTestCase):
     plugin_class = None
 

From 503ded3f32d450d0a86583a17561aef561aa3408 Mon Sep 17 00:00:00 2001
From: Vladislav Korenkov <vladnfs3@gmail.com>
Date: Tue, 13 Dec 2022 17:41:19 +1000
Subject: [PATCH 5/8] Chore: Process override field in execute action

---
 doc/api_schema.yaml             |  30 ++++---
 polemarch/api/v2/serializers.py |  11 +--
 polemarch/api/v3/serializers.py |  17 ++--
 polemarch/main/constants.py     |   1 +
 polemarch/main/models/tasks.py  |   2 +
 polemarch/main/openapi.py       |  12 +++
 polemarch/main/settings.py      |   1 +
 tests.py                        | 141 +++++++++++++++++++++++++++++++-
 8 files changed, 181 insertions(+), 34 deletions(-)

diff --git a/doc/api_schema.yaml b/doc/api_schema.yaml
index 813b8bb0..959c6fa7 100644
--- a/doc/api_schema.yaml
+++ b/doc/api_schema.yaml
@@ -69,7 +69,7 @@ info:
   x-versions:
     application: 2.3.0
     library: 2.3.0
-    vstutils: 5.2.1
+    vstutils: 5.2.2
     django: 3.2.16
     djangorestframework: 3.14.0
     drf_yasg: 1.21.4
@@ -195,8 +195,8 @@ paths:
             $ref: '#/definitions/ProjectTemplateCreate'
       tags:
         - community_template
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: id
         in: path
@@ -2203,8 +2203,8 @@ paths:
             $ref: '#/definitions/ActionResponse'
       tags:
         - history
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: id
         in: path
@@ -2221,8 +2221,8 @@ paths:
           description: NO CONTENT
       tags:
         - history
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: id
         in: path
@@ -5415,8 +5415,8 @@ paths:
             $ref: '#/definitions/ExecuteResponse'
       tags:
         - project
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: id
         in: path
@@ -5440,8 +5440,8 @@ paths:
             $ref: '#/definitions/ExecuteResponse'
       tags:
         - project
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: id
         in: path
@@ -5670,8 +5670,8 @@ paths:
             $ref: '#/definitions/ExecuteResponse'
       tags:
         - project
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: execution_templates_id
         in: path
@@ -6082,8 +6082,8 @@ paths:
             $ref: '#/definitions/ActionResponse'
       tags:
         - project
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: history_id
         in: path
@@ -6105,8 +6105,8 @@ paths:
           description: NO CONTENT
       tags:
         - project
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: history_id
         in: path
@@ -9002,8 +9002,8 @@ paths:
             $ref: '#/definitions/ExecuteResponse'
       tags:
         - project
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: id
         in: path
@@ -9403,8 +9403,8 @@ paths:
             $ref: '#/definitions/ActionResponse'
       tags:
         - project
-      x-multiaction: false
       x-require-confirmation: false
+      x-multiaction: false
     parameters:
       - name: id
         in: path
@@ -12605,13 +12605,13 @@ definitions:
         - data
     x-view-field-name: name
   TemplateExec:
-    required:
-      - option
     type: object
     properties:
       option:
         title: Option
-        type: integer
+        type: string
+        minLength: 1
+        x-nullable: true
         format: fk
         x-options:
           dependence: null
@@ -12619,10 +12619,8 @@ definitions:
           makeLink: true
           model:
             $ref: '#/definitions/TemplateOption'
-          usePrefetch: true
           value_field: name
           view_field: name
-        x-nullable: true
     x-properties-groups:
       '':
         - option
diff --git a/polemarch/api/v2/serializers.py b/polemarch/api/v2/serializers.py
index f53315aa..02c69901 100644
--- a/polemarch/api/v2/serializers.py
+++ b/polemarch/api/v2/serializers.py
@@ -14,7 +14,7 @@
 
 from vstutils.api import auth as vst_auth
 from vstutils.api import serializers as vst_serializers, fields as vst_fields
-from vstutils.api.serializers import DataSerializer, EmptySerializer
+from vstutils.api.serializers import DataSerializer, EmptySerializer, BaseSerializer
 
 from .base_serializers import with_signals, UserSerializer, _WithPermissionsSerializer, _SignalSerializer
 from ...main import models
@@ -522,13 +522,8 @@ class Meta:
         )
 
 
-class TemplateExecSerializer(DataSerializer):
-    option = vst_fields.FkField(
-        select='TemplateOption',
-        autocomplete_property='name',
-        autocomplete_represent='name',
-        allow_null=True,
-    )
+class TemplateExecSerializer(BaseSerializer):
+    option = serializers.CharField(allow_null=True, required=False)
 
 
 ###################################
diff --git a/polemarch/api/v3/serializers.py b/polemarch/api/v3/serializers.py
index 01a70533..b3370c91 100644
--- a/polemarch/api/v3/serializers.py
+++ b/polemarch/api/v3/serializers.py
@@ -13,6 +13,7 @@
     OneProjectSerializer as V2OneProjectSerializer,
 )
 from ...main.executions import PLUGIN_HANDLERS
+from ...main.constants import TEMPLATE_KINDS_MAP
 
 
 class TaskTemplateParameters(BaseSerializer):
@@ -39,12 +40,12 @@ class ModuleTemplateParameters(BaseSerializer):
     )(required=False)
 
 
-template_kinds = (
-    ('Task', 'Task'),
-    ('Module', 'Module'),
-) + tuple(
-    (plugin, plugin) for plugin in PLUGIN_HANDLERS.keys()
-    if plugin not in {'PLAYBOOK', 'MODULE'}
+template_kinds = tuple(
+    (
+        TEMPLATE_KINDS_MAP.get(plugin, plugin),
+        TEMPLATE_KINDS_MAP.get(plugin, plugin),
+    )
+    for plugin in PLUGIN_HANDLERS.keys()
 )
 
 template_data_types = {
@@ -54,7 +55,7 @@ class ModuleTemplateParameters(BaseSerializer):
 template_data_types.update({
     plugin: backend.get_serializer_class(exclude_fields=('inventory',))(required=False)
     for plugin, backend in PLUGIN_HANDLERS.items()
-    if plugin not in ('PLAYBOOK, MODULE')
+    if plugin not in TEMPLATE_KINDS_MAP
 })
 
 
@@ -78,7 +79,7 @@ class Meta:
 template_inventory_types.update({
     plugin: InventoryAutoCompletionField(allow_blank=True, required=False) if backend.supports_inventory else 'hidden'
     for plugin, backend in PLUGIN_HANDLERS.items()
-    if plugin not in ('PLAYBOOK', 'MODULE')
+    if plugin not in TEMPLATE_KINDS_MAP
 })
 
 
diff --git a/polemarch/main/constants.py b/polemarch/main/constants.py
index d09a8195..ff5f9834 100644
--- a/polemarch/main/constants.py
+++ b/polemarch/main/constants.py
@@ -6,6 +6,7 @@
 
 CYPHER = '[~~ENCRYPTED~~]'
 ANSIBLE_REFERENCE = AnsibleArgumentsReference()
+TEMPLATE_KINDS_MAP = {'PLAYBOOK': 'Task', 'MODULE': 'Module'}
 
 
 class BaseVariablesEnum(BaseEnum):
diff --git a/polemarch/main/models/tasks.py b/polemarch/main/models/tasks.py
index 2ae76f75..794db313 100644
--- a/polemarch/main/models/tasks.py
+++ b/polemarch/main/models/tasks.py
@@ -93,7 +93,9 @@ def get_data_with_options(self, option: Optional[str], **extra) -> Dict[str, Any
         vars.update(option_vars)
         data.update(option_data)
         data.update(vars)
+        override = extra.pop('override', {})
         data.update(extra)
+        data.update(override)
         return data
 
     def get_plugin(self):
diff --git a/polemarch/main/openapi.py b/polemarch/main/openapi.py
index bbcb68c6..624467be 100644
--- a/polemarch/main/openapi.py
+++ b/polemarch/main/openapi.py
@@ -150,3 +150,15 @@ def set_periodic_task_variable_value_field(request, schema):  # pylint: disable=
         'readOnly': True,
         'x-hidden': True,
     }
+
+
+def set_template_option_field_to_fk(request, schema):
+    schema['definitions']['TemplateExec']['properties']['option']['format'] = 'fk'
+    schema['definitions']['TemplateExec']['properties']['option']['x-options'] = {
+        'model': {'$ref': '#/definitions/TemplateOption'},
+        'value_field': 'name',
+        'view_field': 'name',
+        'makeLink': True,
+        'dependence': None,
+        'filters': None,
+    }
diff --git a/polemarch/main/settings.py b/polemarch/main/settings.py
index fadd378d..79445db7 100644
--- a/polemarch/main/settings.py
+++ b/polemarch/main/settings.py
@@ -74,6 +74,7 @@
     'polemarch.main.openapi.set_gui_menu_ce',
     'polemarch.main.openapi.set_inventory_field',
     'polemarch.main.openapi.set_periodic_task_variable_value_field',
+    'polemarch.main.openapi.set_template_option_field_to_fk',
 ]
 
 SWAGGER_SETTINGS['DEFAULT_INFO'] = '{}.api.v2.swagger.api_info'.format(VST_PROJECT_LIB_NAME)
diff --git a/tests.py b/tests.py
index da39dfbc..d7befd91 100644
--- a/tests.py
+++ b/tests.py
@@ -30,12 +30,12 @@
     from polemarch.main.openapi import PROJECT_MENU
     from polemarch.main.constants import CYPHER
     from polemarch.main.models.utils import ProjectProxy
-    from polemarch.plugins.ansible import BaseAnsiblePlugin, BasePlugin, Module
+    from polemarch.plugins.ansible import BaseAnsiblePlugin, BasePlugin, Module, Playbook
 except ImportError:
     from pmlib.main.tasks import ScheduledTask
     from pmlib.main.models.utils import ProjectProxy
     from pmlib.main.constants import CYPHER
-    from pmlib.plugins.ansible import BaseAnsiblePlugin, BasePlugin, Module
+    from pmlib.plugins.ansible import BaseAnsiblePlugin, BasePlugin, Module, Playbook
 
 
 TEST_DATA_DIR = Path(__file__).parent.absolute()
@@ -4249,6 +4249,8 @@ def test_schema(self):
         with raise_context():
             endpoint_schema['definitions']['PeriodicTaskVariable']['properties']['key']['x-options']['types'] = \
                 yml_schema['definitions']['PeriodicTaskVariable']['properties']['key']['x-options']['types']
+            endpoint_schema['definitions']['TemplateExec']['properties']['override']['x-options']['types'] = \
+                yml_schema['definitions']['TemplateExec']['properties']['override']['x-options']['types']
 
         del yml_schema['definitions']['_MainSettings']
         del endpoint_schema['definitions']['_MainSettings']
@@ -4342,3 +4344,138 @@ def test_put_into_tmpfile(self):
         test_value = 'test_value'
         filepath = instance._put_into_tmpfile(test_value)
         self.assertEqual(Path(filepath).read_text(), test_value)
+        self.assertEqual(Path(filepath).stat().st_mode, 0o100600)
+
+
+class AnsiblePlaybookExecutionPluginUnitTestCase(BaseExecutionPluginUnitTestCase):
+    plugin_class = Playbook
+
+    boolean_args = (
+        'force_handlers',
+        'flush_cache',
+        'become',
+        'check',
+        'syntax_check',
+        'diff',
+        'list_hosts',
+        'list_tasks',
+        'list_tags',
+    )
+    string_args = (
+        'user',
+        'connection',
+        'ssh_common_args',
+        'sftp_extra_args',
+        'scp_extra_args',
+        'ssh_extra_args',
+        'become_method',
+        'become_user',
+        'tags',
+        'skip_tags',
+        'inventory',
+        'limit',
+        'extra_vars',
+        'vault_id',
+        'start_at_task',
+        'args',
+    )
+    int_args = (
+        'timeout',
+        'forks',
+    )
+    file_args = (
+        'private_key',
+        'vault_password_file',
+        'module_path',
+    )
+
+    def test_process_arg(self):
+        instance = self.get_plugin_instance()
+
+        self.assertIsNone(instance._process_arg('unknown', 'unknown'))
+        self.assertEqual(instance._process_arg('verbose', 2), '-vv')
+        self.assertIsNone(instance._process_arg('verbose', 0))
+
+        for arg in self.boolean_args:
+            self.assertIsNone(instance._process_arg(arg, False))
+            self.assertEqual(instance._process_arg(arg, True), f'--{arg.replace("_", "-")}')
+
+        for arg in self.string_args:
+            self.assertIsNone(instance._process_arg(arg, ''))
+            self.assertEqual(instance._process_arg(arg, 'test-value'), f'--{arg.replace("_", "-")}=test-value')
+
+        for arg in self.int_args:
+            self.assertIsNone(instance._process_arg(arg, 0))
+            self.assertEqual(instance._process_arg(arg, 2), f'--{arg.replace("_", "-")}=2')
+
+        for arg in self.file_args:
+            self.assertIsNone(instance._process_arg(arg, ''))
+            processed_arg = instance._process_arg(arg, 'test-value')
+            filepath = processed_arg[processed_arg.index('=') + 1:]
+            self.assertEqual(Path(filepath).read_text(), 'test-value')
+
+
+class AnsibleModuleExecutionPluginUnitTestCase(BaseExecutionPluginUnitTestCase):
+    plugin_class = Module
+
+    boolean_args = (
+        'become',
+        'list_hosts',
+        'one_line',
+        'check',
+        'syntax_check',
+        'diff',
+    )
+    string_args = (
+        'become_method',
+        'become_user',
+        'inventory',
+        'limit',
+        'tree',
+        'user',
+        'connection',
+        'ssh_common_args',
+        'sftp_extra_args',
+        'scp_extra_args',
+        'ssh_extra_args',
+        'extra_vars',
+        'vault_id',
+        'playbook_dir',
+        'args',
+        'group',
+    )
+    int_args = (
+        'poll',
+        'background',
+        'timeout',
+        'forks',
+    )
+    file_args = (
+        'private_key',
+        'vault_password_file'
+    )
+
+    def test_process_arg(self):
+        instance = self.get_plugin_instance()
+
+        self.assertIsNone(instance._process_arg('unknown', 'unknown'))
+        self.assertEqual(instance._process_arg('verbose', 3), '-vvv')
+        self.assertIsNone(instance._process_arg('verbose', 0))
+
+        for arg in self.boolean_args:
+            self.assertIsNone(instance._process_arg(arg, False))
+            self.assertEqual(instance._process_arg(arg, True), f'--{arg.replace("_", "-")}')
+
+        for arg in self.string_args:
+            self.assertIsNone(instance._process_arg(arg, ''))
+            self.assertEqual(instance._process_arg(arg, 'test-value'), f'--{arg.replace("_", "-")}=test-value')
+
+        for arg in self.int_args:
+            self.assertIsNone(instance._process_arg(arg, 0))
+            self.assertEqual(instance._process_arg(arg, 2), f'--{arg.replace("_", "-")}=2')
+
+        for arg in self.file_args:
+            self.assertIsNone(instance._process_arg(arg, ''))
+            processed_arg = instance._process_arg(arg, 'test-value')
+            filepath = processed_arg[processed_arg.index('=') + 1:]
+            self.assertEqual(Path(filepath).read_text(), 'test-value')

From b7086a2dd47947dd46f8be8d206fb980e633b2be Mon Sep 17 00:00:00 2001
From: Sergey Klyuykov <onegreyonewhite@mail.ru>
Date: Fri, 16 Dec 2022 13:01:41 +1000
Subject: [PATCH 6/8] Feature(service): Deploy Polemarch to k8s via werf

---
 .dockerignore                    | 289 ++++++++++++++++++++++++++++-
 .gitignore                       |   3 +
 .helm/Chart.lock                 |  15 ++
 .helm/Chart.yaml                 |  20 ++
 .helm/values.yaml                | 111 ++++++++++++
 Dockerfile                       |   1 +
 Makefile                         | 210 ---------------------
 deb.mk                           | 131 --------------
 environment/all.yml              |  34 ----
 environment/deployment_pm.yml.j2 | 302 -------------------------------
 k8s_env_deploy.yaml              |  43 -----
 k8s_env_destroy.yaml             |  15 --
 rpm.mk                           |  80 --------
 werf.yaml                        |   2 +-
 14 files changed, 439 insertions(+), 817 deletions(-)
 mode change 120000 => 100644 .dockerignore
 create mode 100644 .helm/Chart.lock
 create mode 100644 .helm/Chart.yaml
 create mode 100644 .helm/values.yaml
 delete mode 100644 Makefile
 delete mode 100644 deb.mk
 delete mode 100644 environment/all.yml
 delete mode 100644 environment/deployment_pm.yml.j2
 delete mode 100644 k8s_env_deploy.yaml
 delete mode 100644 k8s_env_destroy.yaml
 delete mode 100755 rpm.mk

diff --git a/.dockerignore b/.dockerignore
deleted file mode 120000
index 3e4e48b0..00000000
--- a/.dockerignore
+++ /dev/null
@@ -1 +0,0 @@
-.gitignore
\ No newline at end of file
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..f0bfbf08
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,288 @@
+### C++ template
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+### C template
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+### Python template
+# 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
+*.sqlite3
+
+# 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
+
+# poetry
+#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+#   This is especially recommended for binary packages to ensure reproducibility, and is more
+#   commonly ignored for libraries.
+#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+#   in version control.
+#   https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__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/
+
+# PyCharm
+#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+#  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
+
+.helm
+.gitlab
+.github
+.coveragerc
+.pep8
+.pylintrc
+ansible.cfg
+docker-compose.yml
+settings.ini
+.gitlab-ci.yml
+autobuild.sh
+autorelease.sh
+traefik_dynamic.yml
+test_fixtures.json
+test_settings.ini
+tox_build.ini
+initbin
+test_data
+test_data_ce
+tests.py
+tests_ce.py
+
+!Dockerfile
+!.dockerignore
+!ce/Dockerfile
+ce
+!ce/polemarch
+!ce/setup.py
+!ce/doc
+!ce/package.json
+!ce/frontend_src
+!ce/webpack.config.js
+!ce/.dockerignore
+!ce/requirements.txt
+!ce/requirements-doc.txt
+!ce/requirements-git.txt
+!ce/requirements-test.txt
diff --git a/.gitignore b/.gitignore
index d43e533e..59f5eeb8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -137,3 +137,6 @@ venv.bak/
 node_modules
 polemarch/static/polemarch
 yarn-error.log
+
+# werf and helm
+.helm/charts
diff --git a/.helm/Chart.lock b/.helm/Chart.lock
new file mode 100644
index 00000000..5ed43231
--- /dev/null
+++ b/.helm/Chart.lock
@@ -0,0 +1,15 @@
+dependencies:
+- name: centrifugo
+  repository: https://centrifugal.github.io/helm-charts
+  version: 7.4.0
+- name: postgresql
+  repository: https://charts.bitnami.com/bitnami
+  version: 12.1.3
+- name: redis
+  repository: https://charts.bitnami.com/bitnami
+  version: 17.3.6
+- name: YAUHC
+  repository: https://gitlab.com/api/v4/projects/40345586/packages/helm/stable
+  version: 0.1.9
+digest: sha256:aa4610033f88728d8ad9e120dd2f84ceffa03525f7767e8a2e0e6b932386765e
+generated: "2022-12-14T19:53:00.009050764+04:00"
diff --git a/.helm/Chart.yaml b/.helm/Chart.yaml
new file mode 100644
index 00000000..edcbee08
--- /dev/null
+++ b/.helm/Chart.yaml
@@ -0,0 +1,20 @@
+apiVersion: v2
+name: polemarch-deployment
+version: 0.1.0
+dependencies:
+- name: centrifugo
+  repository: https://centrifugal.github.io/helm-charts
+  version: 7.4.0
+- name: postgresql
+  repository: https://charts.bitnami.com/bitnami
+  version: 12.1.3
+- name: redis
+  repository: https://charts.bitnami.com/bitnami
+  version: 17.3.6
+- name: YAUHC
+  alias: polemarch
+  repository: https://gitlab.com/api/v4/projects/40345586/packages/helm/stable
+  version: 0.1.9
+  export-values:
+    - parent: werf.image.main
+      child: deployments.polemarch.image
diff --git a/.helm/values.yaml b/.helm/values.yaml
new file mode 100644
index 00000000..b0da2103
--- /dev/null
+++ b/.helm/values.yaml
@@ -0,0 +1,111 @@
+postgresql:
+  commonAnnotations:
+    werf.io/weight: "-10"
+  fullnameOverride: database-server
+  auth:
+    postgresPassword: p@$$w0rD
+    username: polemarch
+    password: polemarch
+    database: polemarch
+redis:
+  commonAnnotations:
+    werf.io/weight: "-10"
+  fullnameOverride: redis-server
+  architecture: standalone
+  auth:
+    enabled: false
+centrifugo:
+  config:
+    admin: false
+    allowed_origins:
+    - '*'
+    engine: redis
+    health: true
+    history_size: 10
+    history_ttl: 300s
+    namespaces: []
+  fullnameOverride: centrifugo
+  image:
+    tag: v3.2
+  ingress:
+    enabled: false
+  secrets:
+    redisAddress: redis-server-master:6379
+    adminPassword: 01a18ca9-9328-4ee7-a8de-7e5b231d1df4
+    adminSecret: 7e91c9c1-6303-42b1-9f28-1cdfbf58dcf9
+    apiKey: a08caef0-f1ad-40de-9e59-dd2cec07e2eb
+    tokenHmacSecretKey: d4074fd2-607c-41b0-ab83-f2bc55fae0ec
+  service:
+    port: 9000
+    useSeparateInternalService: true
+    annotations:
+      werf.io/weight: "-9"
+  podAnnotations:
+    werf.io/weight: "-9"
+polemarch:
+  multi_endpoint:
+    domain: polemarch.example.com
+  deployments:
+    centrifugo:
+      port: 9000
+      endpointPath: /connection/
+      external: true
+    polemarch:
+      port: 8080
+      endpointPath: /
+      env:
+        DATABASE_URL: 'postgres://polemarch:polemarch@database-server:5432/polemarch'
+        RPC_ENGINE: 'redis://redis-server-master:6379/0'
+        CACHE_URL: 'redis://redis-server-master:6379/1'
+        LOCK_CACHE_URL: 'redis://redis-server-master:6379/2'
+        SESSION_CACHE_URL: 'redis://redis-server-master:6379/3'
+        ETAG_CACHE_URL: 'redis://redis-server-master:6379/4'
+        RPC_CONCURRENCY: 32
+      volumes:
+        storage: '/storage'
+      volumeSpec:
+        resources:
+          requests:
+            storage: 5Gi
+      livenessProbe:
+        exec:
+          command:
+            - /bin/sh
+            - -c
+            - "ps -A | grep uwsgi"
+        initialDelaySeconds: 10
+        periodSeconds: 20
+        timeoutSeconds: 15
+      readinessProbe:
+        httpGet:
+          httpHeaders:
+            - name: Connection
+              value: keep-alive
+          path: /api/health/
+          port: 8080
+        initialDelaySeconds: 5
+        periodSeconds: 20
+      configPath: '/etc/polemarch'
+      configs:
+        settings.ini: |
+          [docker]
+          override_uwsgi = false
+          migrate_lock_id = polemarch
+
+          [main]
+          auth-cache-user = True
+          log_level = warning
+          debug = false
+          projects_dir = /storage/projects
+          hooks_dir = /storage/hooks
+
+          [uwsgi]
+          daemon = false
+          pidfile = /tmp/web.pid
+          addrport = 0.0.0.0:8080
+
+          [centrifugo]
+          address = http://centrifugo:9000/api
+          public_address = /
+          token_hmac_secret_key = d4074fd2-607c-41b0-ab83-f2bc55fae0ec
+          api_key = a08caef0-f1ad-40de-9e59-dd2cec07e2eb
diff --git a/Dockerfile b/Dockerfile
index 05612ccc..2193aff6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -57,6 +57,7 @@ RUN --mount=type=cache,target=/var/cache/apt \
         sudo \
         sshpass \
         libmysqlclient21 \
+        libpq5 \
         libpcre3 \
         libldap-2.4-2 \
         libsasl2-2 \
diff --git a/Makefile b/Makefile
deleted file mode 100644
index e27430a8..00000000
--- a/Makefile
+++ /dev/null
@@ -1,210 +0,0 @@
-PY = python
-PIP = $(PY) -m pip
-PY_VERSION = $(shell $(PY) --version 2>&1 | tail -c +8)
-PYTHON_BIN = $(shell $(PY) -c 'import sys, os; print(os.path.dirname(sys.executable))')
-RELOCATE_BIN = $(PYTHON_BIN)/venvctrl-relocate
-LOC_TEST_ENVS = py27-install,py36-install,flake,pylint
-ENVS = $(LOC_TEST_ENVS)
-ifndef TOX_ARGS
-	TOX_ARGS =
-endif
-TESTS =
-NAMEBASE = polemarch
-USER = $(NAMEBASE)
-NAME = $(NAMEBASE)
-VER = $(shell $(PY) setup.py --version | tr -d '\n')
-PROJECT_CTL = $(NAME)ctl
-MAIN_APP = main
-VSTUTILS_REQ = $(shell cat requirements-doc.txt | grep vstutils | sed 's/\[.*\]/[doc]/')
-VSTUTILS = $(VSTUTILS_REQ)
-PIPARGS = $(shell echo -n "--cache-dir=$$(pwd)/.pip-cache")
-ARCHIVE = $(NAME)-$(VER).tar.gz
-LICENSE = AGPL-3+
-define DESCRIPTION
- Polemarch is service for orchestration infrastructure by ansible.
- Simply WEB gui for orchestration infrastructure by ansible playbooks.
-endef
-export DESCRIPTION
-SUMMARY = Infrastructure Heat Service for orchestration infrastructure by ansible.
-VENDOR = VST Consulting <sergey.k@vstconsulting.net>
-RELEASE = 0
-DEFAULT_PREFIX = /opt
-INSTALL_PREFIX = $(shell if [[ ! -z "${prefix}" ]]; then echo -n $(prefix); else echo -n $(DEFAULT_PREFIX); fi)
-INSTALL_DIR = $(INSTALL_PREFIX)/${NAME}
-INSTALL_BINDIR = $(INSTALL_DIR)/bin
-INSTALL_PY = $(PY)
-REQUIREMENTS = -r requirements.txt -r requirements-doc.txt
-TMPDIR := $(shell mktemp -d)
-RPM_BUILD = /tmp/rpmbuild_$(NAME)_$(VER)_$(RELEASE)
-BUILD_DIR= $(TMPDIR)
-PREBUILD_DIR = $(BUILD_DIR)/$(INSTALL_DIR)
-PREBUILD_BINDIR = $(BUILD_DIR)/$(INSTALL_BINDIR)
-SOURCE_DIR = $(shell pwd)
-COMPILE_DIR = $(shell echo -n "$$(pwd)/dist")
-define VARS_STR
-PY=$(PY)
-PY_VERSION=$(PY_VERSION)
-PIP=$(PIP)
-PYTHON_BIN=$(PYTHON_BIN)
-RELOCATE_BIN=$(RELOCATE_BIN)
-NAMEBASE=$(NAMEBASE)
-USER=$(USER)
-NAME=$(NAME)
-VER=$(VER)
-RELEASE=$(RELEASE)
-PROJECT_CTL=$(PROJECT_CTL)
-MAIN_APP=$(MAIN_APP)
-VSTUTILS=$(VSTUTILS)
-BUILD_DIR=$(BUILD_DIR)
-RPM_BUILD=$(RPM_BUILD)
-INSTALL_DIR=$(INSTALL_DIR)
-endef
-export VARS_STR
-
-include rpm.mk
-include deb.mk
-
-all: compile clean_prebuild prebuild
-
-
-print_vars:
-	echo "$$VARS_STR"
-	which $(PY)
-
-docs: print_vars
-	-rm -rf doc/_build
-	mkdir -p doc/_static
-	$(PY) setup.py build_sphinx --build-dir doc/_build -W
-
-test:
-	tox $(TOX_ARGS) -e $(ENVS) $(TESTS)
-
-flake:
-	tox -e flake
-
-pylint:
-	tox -e pylint
-
-build: build-clean print_vars
-	# -rm -rf dist
-	$(PY) setup.py sdist -v
-
-pre_compile: build-clean print_vars
-	find ./$(NAME) -name "*.c" -print0 | xargs -0 rm -rf
-	-rm -rf polemarch/doc/*
-	$(PIP) install -U $(VSTUTILS)
-
-compile: pre_compile
-	# -rm -rf dist
-	$(PY) setup.py compile -v
-
-wheel: pre_compile
-	$(PY) setup.py compile_docs -v
-	$(PY) setup.py bdist_wheel -v --dist-dir $(COMPILE_DIR) --bdist-dir /tmp/build_$(NAME)/$(PY_VERSION)/
-
-prebuild: print_vars
-	# Create virtualenv
-	$(PY) -m virtualenv -p $(INSTALL_PY) --download --no-site-packages $(PREBUILD_DIR)
-	# Install required packages
-	$(PREBUILD_BINDIR)/pip install -U pip
-	$(PREBUILD_BINDIR)/pip install -U dist/$(NAME)-$(VER).tar.gz $(REQUIREMENTS)
-	$(PREBUILD_BINDIR)/pip install -U -r requirements-git.txt
-	# RECORD files are used by wheels for checksum. They contain path names which
-	# match the buildroot and must be removed or the package will fail to build.
-	# find $(PREBUILD_DIR) -name "RECORD" -exec rm -rf {} \;
-	# Change the virtualenv path to the target installation direcotry.
-	$(RELOCATE_BIN) --source=$(PREBUILD_DIR) --destination=$(INSTALL_DIR)
-	# Remove sources for Clang
-	find $(PREBUILD_DIR)/lib -type f -name "*.c" -print0 | xargs -0 rm -rf
-	# Remove broken link
-	-rm -rf $(PREBUILD_DIR)/local
-	# Install settings
-	-install -Dm 755 $(NAME)/$(MAIN_APP)/settings.ini $(BUILD_DIR)/etc/$(USER)/settings.ini.template
-	# Install systemd services
-	-install -Dm 755 initbin/$(NAME).service  $(BUILD_DIR)/etc/systemd/system/$(NAME).service
-	# Install tmpdirs config
-	-install -Dm 755 initbin/$(NAMEBASE).conf  $(BUILD_DIR)/etc/tmpfiles.d/$(NAMEBASE).conf
-	# Create tmpdirs
-	-mkdir -p $(BUILD_DIR)/var/log/$(NAMEBASE)
-	-mkdir -p $(BUILD_DIR)/var/run/$(NAMEBASE)
-	-mkdir -p $(BUILD_DIR)/var/lock/$(NAMEBASE)
-
-localinstall: print_vars
-	$(PY) -m virtualenv --no-site-packages $(INSTALL_DIR)
-	$(INSTALL_BINDIR)/pip install -U pip
-	$(INSTALL_BINDIR)/pip install -U $(VSTUTILS)
-	$(INSTALL_BINDIR)/pip install -U dist/$(NAME)-$(VER).tar.gz $(REQUIREMENTS)
-	$(INSTALL_BINDIR)/pip install -U -r requirements-git.txt
-	find $(INSTALL_DIR)/lib -type f -name "*.c" -print0 | xargs -0 rm -rf
-	$(MAKE) prebuild_deps BUILD_DIR=$(INSTALL_DIR)
-
-install:
-	# Change owner for packages
-	-chown -R $(USER):$(USER) $(PREBUILD_DIR) $(BUILD_DIR)/var/{log,run,lock}/$(NAMEBASE) $(BUILD_DIR)/etc/$(USER)
-	# Copy build
-	cp -rf $(BUILD_DIR)/* /
-	$(MAKE) clean_prebuild
-
-uninstall:
-	-rm -rf $(INSTALL_DIR)
-
-clean_prebuild:
-	-rm -rf $(BUILD_DIR)/*
-
-clean: build-clean
-	-rm -rf htmlcov
-	-rm -rf .coverage
-	-rm -rf dist
-	-rm -rf build
-	-rm -rf *.egg-info
-
-build-clean:
-	-rm pylint_* || true
-	find ./$(NAME) -name '__pycache__' -print0 | xargs -0 rm -rf
-	find ./$(NAME) -name "*.pyc" -print0 | xargs -0 rm -rf
-	-rm -rf build
-	-rm -rf *.egg-info
-
-fclean: clean
-	find ./$(NAME) -name "*.c" -print0 | xargs -0 rm -rf
-	-rm -rf .tox
-
-rpm: print_vars
-	echo "$$RPM_SPEC" > $(NAME).spec
-	rm -rf $(RPM_BUILD)
-	mkdir -p $(RPM_BUILD)/SOURCES/
-	ls -la
-	rpmbuild --verbose -bb $(NAME).spec --define "_rpmdir ${RPM_BUILD}" --define "_topdir ${RPM_BUILD}"
-	mkdir -p dist
-	cp -v $(RPM_BUILD)/x86_64/*.rpm dist/
-	rm -rf $(NAME).spec $(RPM_BUILD)
-
-deb: print_vars
-	rm -rf debian
-	mkdir debian
-	# create needed files
-	echo 9 > debian/compat
-	echo "$$DEBIAN_CONTROL" > debian/control
-	echo "$$DEBIAN_COPYRIGHT" > debian/copyright
-	echo "$$DEBIAN_RULES" > debian/rules
-	echo "$$DEBIAN_PREINST" > debian/preinst
-	echo "$$DEBIAN_POSTINST" > debian/postinst
-	echo "$$DEBIAN_PRERM" > debian/prerm
-	echo "$$DEBIAN_POSTRM" > debian/postrm
-	echo "$$DEBIAN_CHANGELOG" > debian/changelog
-	chmod +x debian/rules
-	chmod +x debian/preinst
-	chmod +x debian/postinst
-	chmod +x debian/prerm
-	chmod +x debian/postrm
-	# build
-	dpkg-buildpackage -d -uc -us -j4
-	mv -v ../$(NAME)_$(VER)*.deb dist/
-	# cleanup
-	rm -rf debian
-
-# twine:
-# 	for file in $(shell find dist/*.{tar.gz,whl} | grep ${NAME} | grep ${VER}); do \
-# 		echo $$file; \
-# 		twine upload -u $(PYPI_UPLOAD_NAME) -p $(PYPI_UPLOAD_PASSWORD) $$file || echo "Filed to upload ${file}"; \
-# 	done
diff --git a/deb.mk b/deb.mk
deleted file mode 100644
index 4c9f3464..00000000
--- a/deb.mk
+++ /dev/null
@@ -1,131 +0,0 @@
-define DEBIAN_CONTROL
-Source: $(NAME)
-Section: unknown
-Priority: optional
-Maintainer: $(VENDOR)
-Build-Depends: debhelper (>= 9), python-virtualenv, python-pip, python-dev, gcc, libffi-dev, libssl-dev, libyaml-dev, libkrb5-dev, libssl-dev, libsasl2-dev, libldap2-dev
-Standards-Version: 3.9.5
-Homepage: https://gitlab.com/vstconsulting/polemarch
-Vcs-Git: git@gitlab.com:vstconsulting/polemarch.git
-Vcs-Browser: https://gitlab.com/vstconsulting/polemarch.git
-
-Package: $(NAME)
-Architecture: amd64
-Depends: $${shlibs:Depends}, $${misc:Depends}, python-virtualenv, libffi6, libssl-dev, sshpass, libpython2.7, git, libyaml-dev, libkrb5-dev, libssl-dev, libsasl2-dev, libldap2-dev, mime-support
-Description: $(SUMMARY)
-$(DESCRIPTION)
-endef
-export DEBIAN_CONTROL
-
-define DEBIAN_COPYRIGHT
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: $(NAME)
-Source: <url://example.com>
-
-Files: *
-Copyright: 2017 VST Consulting
-License: ${LICENSE}
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU Affero Public License for more details.
-
- You should have received a copy of the GNU Affero Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
-endef
-export DEBIAN_COPYRIGHT
-
-# paths and executables variables
-BUILDROOT = debian/$(NAME)
-define DEBIAN_RULES
-#!/usr/bin/make -f
-# maximum verbosity during deb build
-DH_VERBOSE = 1
-export DH_OPTIONS=-v
-# targets, that we want to override with no actions
-override_dh_auto_build:
-	# don't need becouse all makes in 'override_dh_auto_install' target
-override_dh_auto_test:
-	# don't want to test during package build
-override_dh_strip:
-	# it is broken for some unknown reason
-override_dh_link:
-	# it is replacing python in virtualenv with system python
-override_dh_shlibdeps:
-	# it generates dependency which breaks compartibility with newer distros:
-	# libssl with exact version 1.0.0
-# real install
-override_dh_auto_install:
-	# create taget directory and clear it in case of some files exist from
-	# previous build
-	mkdir -p $(BUILDROOT)
-	touch $(BUILDROOT)/dummy
-	rm -rf $(BUILDROOT)/*
-	make BUILD_DIR=$(BUILDROOT)
-%:
-	dh $$@ 
-endef
-export DEBIAN_RULES
-
-define DEBIAN_PREINST
-#!/bin/bash
-# making sure user created
-id -u $(USER) &>/dev/null || useradd -m $(USER)
-id -g $(USER) &>/dev/null || groupadd $(USER)
-endef
-export DEBIAN_PREINST
-
-define DEBIAN_POSTINST
-#!/bin/bash
-# change owner of all dirs
-chown -R $(USER):$(USER) /opt/$(NAME)
-chown -R $(USER):$(USER) /var/log/$(NAMEBASE)
-chown -R $(USER):$(USER) /var/run/$(NAMEBASE)
-chown -R $(USER):$(USER) /var/lock/$(NAMEBASE)
-# making migration and activate services
-# sudo -H -u $(USER) /opt/$(NAME)/bin/polemarchctl migrate
-su - $(USER) -c "/opt/$(NAME)/bin/$(PROJECT_CTL) migrate"
-systemctl daemon-reload || true
-systemctl enable $(NAME).service || true
-endef
-export DEBIAN_POSTINST
-
-define DEBIAN_PRERM
-#!/bin/bash
-case "$$1" in
-  remove)
-    # deactivating services
-    systemctl disable $(NAME).service > /dev/null 2>&1
-    service $(NAME) stop >/dev/null 2>&1
-  ;;
-esac
-# cleaning after yourself
-rm -r /opt/$(NAME)/lib/python2.7/site-packages/$(NAME)/projects/
-rm -rf /opt/$(NAME)/httpd/
-endef
-export DEBIAN_PRERM
-
-define DEBIAN_POSTRM
-#!/bin/bash
-# remove whole /opt/polemarch (database included) if purge called
-case "$$1" in
-  purge)
-    rm -rf /opt/$(NAME)
-  ;;
-esac
-endef
-export DEBIAN_POSTRM
-
-define DEBIAN_CHANGELOG
-$(NAME) ($(VER)-$(RELEASE)) unstable; urgency=low
-
-  * this changelog is generated automatically. See official site for actual list of changes.
-
- -- Sergey K. <sergey.k@vstconsulting.net>  Wed, 19 Jul 2017 6:41:48 +0000
-endef
-export DEBIAN_CHANGELOG
diff --git a/environment/all.yml b/environment/all.yml
deleted file mode 100644
index e1b4a6c0..00000000
--- a/environment/all.yml
+++ /dev/null
@@ -1,34 +0,0 @@
----
-##### VARS FOR REGISTRY / DOCKER / DOCKERHUB
-k8s_path_deployment_template: "{{ lookup('env', 'PATH_DEPLOYMENT_TEMPLATE') or './environment/deployment_pm.yml.j2' }}"
-k8s_registry_image_name: "{{ lookup('env', 'REGISTRY_IMAGE') }}"
-k8s_registry_image_tag: "{{ lookup('env', 'REGISTRY_IMAGE_TAG') }}"
-k8s_registry_user: "{{ lookup('env', 'REGISTRY_USER') }}"
-k8s_registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
-k8s_registry_url: "{{ lookup('env', 'REGISTRY_URL') or 'https://index.docker.io/v1/' }}"
-k8s_docker_host: "{{ lookup ('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock' }}"
-k8s_status_project: "{{ lookup ('env', 'K8S_STATUS_PROJECT') }}"
-
-##### VARS FOR KUBE
-k8s_kubeconfig: "{{ lookup('env', 'KUBECONFIG') or '~/.kube/config' }}"
-k8s_env_namespace: "{{ lookup('env', 'KUBE_NAMESPACE') }}"
-k8s_kube_pm_ingress_domain: "{{ lookup('env', 'K8S_INGRESS_DOMAIN') }}"
-k8s_pm_playbook_template: "{{ lookup('template', k8s_path_deployment_template) }}"
-
-###### if kubernetes in rancher -> "true"
-k8s_kube_in_rancher: "{{ lookup('env', 'K8S_KUBE_IN_RANCHER') or 'true' }}"
-
-########## block SECRET for local registry --->>>
-k8s_registry_dockerconfig_auth: "{{ k8s_registry_user }}:{{ k8s_registry_password }}"
-k8s_registry_dockerconfig_base64: '{"auths":{"{{ k8s_registry_url }}":{"username":"{{ k8s_registry_user }}","password":"{{ k8s_registry_password }}","auth":"{{ k8s_registry_dockerconfig_auth | b64encode }}"}}}'
-
-########## ENV K8S POLEMARCH --->>>
-kube_pm_replilica_vol: 1
-kube_pm_log_level: "{{ lookup('env', 'K8S_PM_LOG_LEVEL') or 'WARNING' }}"
-kube_pm_debug: "{{ lookup('env', 'K8S_PM_DEBUG') or 'false' }}"
-kube_pm_timezone: "{{ lookup('env', 'K8S_PM_TIMEZONE') or 'UTC' }}"
-kube_pm_label: "{{ lookup('env', 'CI_COMMIT_SHORT_SHA') }}"
-
-########## TLS CRT AND KEY POLEMARCH --->>>
-k8s_tls_crt: "{{ lookup('env', 'K8S_TLS_CRT') or 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZuVENDQTRXZ0F3SUJBZ0lJSXpNYmVpWUY5QkV3RFFZSktvWklodmNOQVFFTEJRQXdnZjR4Q3pBSkJnTlYKQkFZVEFsSlZNUmN3RlFZRFZRUUlFdzVRY21sdGIzSnphM2tnUzNKaGVURVVNQklHQTFVRUJ4TUxWbXhoWkdsMgpiM04wYjJzeEd6QVpCZ05WQkFvVEVrOVBUeUJXVTFRZ1EyOXVjM1ZzZEdsdVp6RUxNQWtHQTFVRUN4TUNTVlF4CkdqQVlCZ05WQkFNVEVWWlRWQ0JEYjI1emRXeDBhVzVuSUVOQk1Ta3dKd1lKS29aSWh2Y05BUWtCRmhwelpYSm4KWlhrdWEwQjJjM1JqYjI1emRXeDBhVzVuTG01bGRERVBNQTBHQTFVRUVSTUdOamt3TURBd01SQXdEZ1lEVlFRTQpFd2ROWVdsdUlFTkJNU3d3S2dZRFZRUU5FeU5OWVdsdUlFTkJJR1p2Y2lCaGRYUm9iM0pwZEhrZ1lXNTVJSE5sCmNuWnBZMlZ6TGpBZUZ3MHhPVEV5TVRZd056TXlNREJhRncweU5ERXlNVFl3TnpNeU1EQmFNSUd4TVFzd0NRWUQKVlFRR0V3SlNWVEVYTUJVR0ExVUVDQk1PVUhKcGJXOXljMnQ1SUV0eVlYa3hGREFTQmdOVkJBY1RDMVpzWVdScApkbTl6ZEc5ck1Sc3dHUVlEVlFRS0V4SlBUMDhnVmxOVUlFTnZibk4xYkhScGJtY3hHakFZQmdOVkJBc1RFVWxVCklFbHVabkpoYzNSeWRXTjBkWEpsTVNrd0p3WUpLb1pJaHZjTkFRa0JGaHB6WlhKblpYa3VhMEIyYzNSamIyNXoKZFd4MGFXNW5MbTVsZERFUE1BMEdBMVVFRVJNR05qa3dNREF3TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQwpBUThBTUlJQkNnS0NBUUVBMkZVVHZ5ZHl6TTY1RFBvTW9pb3hPSk5RbmIzK2RyVmtuU2gvMm03cWlNOW9GcFNECkVHUm5yZm5rS0RxSlh0cjNtMWZzcXIzZWpMTjhJQVdnOEF0N3FQVXNuOXYweTRTZkh2S1lQUUhwU2VtUGhCMnUKWUxtTTF2WXhWWVJIMXhOeEFXZmg2N3hOSUorLzN0dnc1ZUR5V0NCb2dOUUJubWEvSTdKa2dHOG1xYTRlektERwpPLzRvUHRRanBEL0lrdVpBRm5vRVpmQm5ZWThwTUwwQ1M2U0RHNTVob3h3TTJVeHVKUDVnbEpJS0JhdUhTZFNTCmlvQ1lkTi9UZzRIaVc2K21OWGtIdENmNjhUc0xkK0dIYi9tNm5JT1dySllhY3Fxb3hGSWpGdXNMUjdXd1hyTE0KbUxpYy95LzJZZ3RqeWhEMTJZbDEwRi9WN1N2a1R4cFczNitYOHdJREFRQUJvMm93YURBTUJnTlZIUk1CQWY4RQpBakFBTUIwR0ExVWREZ1FXQkJSa3BlOUpETSthS2JuQVBqZTkvQzBiUnd2M0pqQU9CZ05WSFE4QkFmOEVCQU1DCkJhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUhBd0V3RkFZRFZSMFJCQTB3QzRJSktpNTJjM1F1YkdGdU1BMEcKQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUURGMGFSeUdBSVNZQW8zSzRtNGw5Nzc5ZHkwWGNpeUl2WTh3ckZTaXFDSgpFdGhUSWRZZXJwK2JmTjBUbkd4eEtmRVJJZFRKb2xyZ2V4RUY3SEZsaTlMQXg2R0RuVjhQbU1CVThWU0I5cHlHCldVK05BNVVuaTNDa0xtSUFJRlFVOEtBbGlycHhWbkdVMy90VGxlaWZFR2pFNGptM2xLM1VRMDEwYnpYY2hSckwKNTZUeGRQK0hidjFQZHBLSlc1ajMwQ3ZCMHdMWEFNMlJaRXlub25ydUhsMnBSdmh3WEI2Uy9Oc1cyc05tYzd1awpWa0F3TUtEV3kzTE5QeHl1dTRna1hBSmp6Mnd2aGRQTG81LzVoWWRFNEtYMHkvWXhleTg5S2w4ZDArUDdhS2c2CitlWlZRNER5c0JBSG1Tcmh6Q3JTSDRWZE0xbmZvUzNGQmt4c0dYQkRhd3dXNmM4ZloxYnZMcmV4Vmh0OFhVMkMKQmNkYnAzZGpGM3RwdVF2dFYzZXUzUldJRGpNWjNwYUJwYTc1aWNQTFJRZ1BZY1NrMzdjUXhQbFFZL05VYStZUQpaT0JJVTF4Ny8wSG5XY1g1UURnSEpBZEdSdmZBSTRhNlNjQjQ2V2MyOEtYVit2aG0zYXF3MSt3RXlRaWR2djZBCk9HdU00Rnp1aTFHandjWkdhNU45c0hCcGtBYlp1ckxabWVJN21ESXl6cUp1aVlVd2JwUm9pMW9kMUd2MVZRZG0KdEJQTlhmUEhjcmt5NHZjdUhVUkZtVC9JN1I1bXRWd01mc3daSVR1S21CeU4ydHB0Y0l1Zy9pdW52eElKZWxWdwpsd2ozT1UzeFZGcVVUVEVTby9IQTUxdmYrb1A1N2xDUlBpMTByTmVRbk43WHRTNDhjUmw4V2I1RXhCRk1NT1JPCmRBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=' }}"
-k8s_tls_key: "{{ lookup('env', 'K8S_TLS_KEY') or 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBMkZVVHZ5ZHl6TTY1RFBvTW9pb3hPSk5RbmIzK2RyVmtuU2gvMm03cWlNOW9GcFNECkVHUm5yZm5rS0RxSlh0cjNtMWZzcXIzZWpMTjhJQVdnOEF0N3FQVXNuOXYweTRTZkh2S1lQUUhwU2VtUGhCMnUKWUxtTTF2WXhWWVJIMXhOeEFXZmg2N3hOSUorLzN0dnc1ZUR5V0NCb2dOUUJubWEvSTdKa2dHOG1xYTRlektERwpPLzRvUHRRanBEL0lrdVpBRm5vRVpmQm5ZWThwTUwwQ1M2U0RHNTVob3h3TTJVeHVKUDVnbEpJS0JhdUhTZFNTCmlvQ1lkTi9UZzRIaVc2K21OWGtIdENmNjhUc0xkK0dIYi9tNm5JT1dySllhY3Fxb3hGSWpGdXNMUjdXd1hyTE0KbUxpYy95LzJZZ3RqeWhEMTJZbDEwRi9WN1N2a1R4cFczNitYOHdJREFRQUJBb0lCQUVTbU10NzlLTHYvZWMrNQpaZHJzSXJSK1l4MjdsZzJib0hNUzBBZkVITjhQV2t1WUUwTlhhV05YSW1UMXRuUUlibnk0V1IwUnBaYm11aVA3ClJVZ0hqTlZnQUNvMmhhY3p6YjduWXhJeEVoUG5ieWlRdHE1eEUxVi95TVlIZFRpMkxhMHhod3JrdFdEOThNaEsKNlZZNW5RNEVNc1YzQVpCL3NIWW1mU2dZblo5SVVVUC9KYXpjTWM1UVpzT3Q0YmZEQU5MZXpwQkd0aDVjU3U5SgpSc2VoTENMeWs1L1FqelIzU0VjdDBYaVlFVGNpbEJITFNLVnJ5dGtyYm4rYjg1enZYblR5S1liWGlHci8yK21kClF4Y0FObG1kRTFTeDAzNzlGSG8yMGFJYnc4ZllFUUFldHovcm8wRWZoY01qK01Va2FMNG1TNlhZRkZDR2ZDbHIKOG83Q1RvRUNnWUVBKzNGWGlGejd5VWYzQWQxMTNFQldGQ2Jta2VmRXhqNlRJYUJMSmhBL0JCYlZ2TkFvaFI3QQorU0pGOThxdlhjTkt4VExjeTZ3d2tUNVhrQ3NqbVlQbWhsS2FyRFdXTWVZR1ZmeHFQWCtGeHRDcFBid2RGYlRpCmwra3g0aU15WGhNb0ZkZEJ2cmcwVXo5cHZtajFYOUpnbk5jNzh5T2tSWXZRVFIxS2hrN0Z4VE1DZ1lFQTNFRFQKOWd1WWczNFgwcEJvN3BSY1YzQm1LdXl4bWMvSG5Ma21TcWxTRXgvdC92eHVrMHlkZmx3eVdlbm9kZTlqMjQydApFTFJJWGsyUFVnck5BV1p3dHBBQmhRMFdkMFB5K2ptUEZpL2hRWTZ1azF6bnAxYmhLK0pKVlJFTXlkM1Z0dU5HCkU4cEFGRVIxOWxyNVlvQzZXMUQ0M0ZqMU1lajJHbGMrVjNnWllrRUNnWUJ5ek9Mc0xaZi81RTJRbW01UGEwaGgKMXdqNm9Oa2tzamsyNXhxb2ZFNXBMWXZVc3kxczZnZXROOHErUWRvamN5RFdQRXkyNlIwYmsxMGpRNjd6VGxlWQpDR3I2S1ZVejN4UVJlamQvY0pQQm5FOUpFblF0RHZOTjdIaU1DUW5jRGQ4RmFjeG9xVzJxZkk5cEVqN0Z5eVcxCk5rZjIwTlVWczZvZEt6eDFhYzIrSlFLQmdRQ005Mnp4NkFBSUFMY01qR0tzZUFZVjdKbG5WYkJoeWt0dXNrMmcKc1hnWFIzTlNwSXU4K09kQURaQW9YZjNySlhsYTl2VlNZS0NFd3MwODdDN0RlNlllSWxMbXJqYTN4S1NKcERkQgpNd25QcEp0MU01d01UUjIyc1pEUHdpYldPSVhsRk5jd0tWMFQyN0ZJS0hlK3BMY2haTlN5YXJrYjVZZEYycHJLCjd0SUlRUUtCZ0Y3azdhS0ZZVFowc0NwRUUxQzYrSmp2WVBkMmZ4blVkTy9MWEFoUW1CZG1jYkhHK2J6dytReUcKWGhGTHVya3BsK01rU1U0elRGdEtsbDVCT1RwdzVaa01nNm1rTGhrck1ER1YrNlJFL2k4U21lMU5hcXlxK28xKwppeWtKYlV1WWlkOUpvZ3dHTmFlZWFNWUpCMHVSS3JOMjljajA1dnJxb2trM3hBaUorZjROCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==' }}"
diff --git a/environment/deployment_pm.yml.j2 b/environment/deployment_pm.yml.j2
deleted file mode 100644
index 63aa2512..00000000
--- a/environment/deployment_pm.yml.j2
+++ /dev/null
@@ -1,302 +0,0 @@
-##### FAQ
-# 1. Namespace is indicated when the playbook starts
-# 2. For stable work in Rancher, additional annotations and labels are used
-# 3. The next step will need to deal with NFS and PV
-#####   MySQL
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: mysql
-{% if k8s_kube_in_rancher=="true" %}
-  annotations:
-    field.cattle.io/targetWorkloadIds: '["deployment:{{ k8s_env_namespace }}:mysql"]'
-  labels:
-    workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-mysql
-{% endif %}
-spec:
-  selector:
-    matchLabels:
-{% if k8s_kube_in_rancher=="true" %}
-      workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-mysql
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-      app: polemarch
-{% endif %}
-  template:
-    metadata:
-      labels:
-{% if k8s_kube_in_rancher=="true" %}
-        workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-mysql
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-        app: polemarch
-{% endif %}
-    spec:
-      containers:
-        - image: mysql:5.7
-          name: mysql
-          env:
-            - name: MYSQL_USER
-              value: 'polemarch-user'
-            - name: MYSQL_PASSWORD
-              value: 'polemarch-pas'
-            - name: MYSQL_DATABASE
-              value: 'polemarch-db'
-            - name: MYSQL_ROOT_PASSWORD
-              value: 'polemarch-root'
-          ports:
-            - containerPort: 3306
-          tty: true
-          stdin: true
-
----
-apiVersion: v1
-kind: Service
-metadata:
-{% if k8s_kube_in_rancher=="true" %}
-  annotations:
-    field.cattle.io/targetWorkloadIds: '["deployment:{{ k8s_env_namespace }}:mysql"]'
-{% endif %}
-  name: mysql-svc
-spec:
-  ports:
-    - name: mysql
-      port: 3306
-      targetPort: 3306
-      protocol: TCP
-{% if k8s_kube_in_rancher=="false" or k8s_kube_in_rancher is not defined %}
-  selector:
-    app: polemarch
-{% endif %}
-  sessionAffinity: None
-  clusterIP: None
-
-######   Redis
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-{% if k8s_kube_in_rancher=="true" %}
-  annotations:
-    field.cattle.io/targetWorkloadIds: '["deployment:{{ k8s_env_namespace }}:redis"]'
-  labels:
-    workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-redis
-{% endif %}
-  name: redis
-spec:
-  selector:
-    matchLabels:
-{% if k8s_kube_in_rancher=="true" %}
-      workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-redis
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-      app: polemarch
-{% endif %}
-  template:
-    metadata:
-      labels:
-{% if k8s_kube_in_rancher=="true" %}
-        workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-redis
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-        app: polemarch
-{% endif %}
-    spec:
-      containers:
-        - image: redis:latest
-          name: redis
-          ports:
-            - containerPort: 6379
-              name: redis
-          tty: true
-          stdin: true
-
----
-apiVersion: v1
-kind: Service
-metadata:
-{% if k8s_kube_in_rancher=="true" %}
-  annotations:
-    field.cattle.io/targetWorkloadIds: '["deployment:{{ k8s_env_namespace }}:redis"]'
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-  labels:
-    app: polemarch
-{% endif %}
-  name: redis-svc
-spec:
-  ports:
-    - name: redis
-      port: 6379
-      targetPort: 6379
-      protocol: TCP
-{% if k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-  selector:
-    app: polemarch
-{% endif %}
-  sessionAffinity: None
-  clusterIP: None
-
-#####   Polemarch
----
-apiVersion: v1
-data:
-  .dockerconfigjson: "{{ k8s_registry_dockerconfig_base64 | to_json | b64encode  }}"
-kind: Secret
-metadata:
-  name: gitlab-registry
-  labels:
-    appselector: polemarch
-type: kubernetes.io/dockerconfigjson
-
----
-apiVersion: v1
-kind: Secret
-metadata:
-  name: secretkeyvst
-data:
-  tls.crt: "{{ k8s_tls_crt }}"
-  tls.key: "{{ k8s_tls_key }}"
-type: kubernetes.io/tls
-
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: polemarch
-  labels:
-{% if k8s_kube_in_rancher=="true" %}
-    workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-polemarch
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-    app: polemarch
-{% endif %}
-    appselector: polemarch
-    comshort: "{{ kube_pm_label }}"
-{% if k8s_kube_in_rancher=="true" %}
-  annotations:
-    field.cattle.io/targetWorkloadIds: '["deployment:{{ k8s_env_namespace }}:polemarch"]'
-{% endif %}
-spec:
-  replicas: {{ kube_pm_replilica_vol }}
-  selector:
-    matchLabels:
-{% if k8s_kube_in_rancher=="true" %}
-      workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-polemarch
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-      app: polemarch
-{% endif %}
-  template:
-    metadata:
-      labels:
-{% if k8s_kube_in_rancher=="true" %}
-        workload.user.cattle.io/workloadselector: deployment-{{ k8s_env_namespace}}-polemarch
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-        app: polemarch
-{% endif %}
-        appselector: polemarch
-        comshort: "{{ kube_pm_label }}"
-    spec:
-{% if (k8s_registry_user is defined) and (k8s_registry_password is defined) and (k8s_registry_url is defined) %}
-      imagePullSecrets:
-        - name: gitlab-registry
-{% endif %}
-      containers:
-        - name: polemarch
-{% if (k8s_registry_user is defined) and (k8s_registry_password is defined) and (k8s_registry_url is defined) %}
-          image: {{ k8s_registry_image_name }}:{{ k8s_registry_image_tag }}
-{% endif %}
-          imagePullPolicy: Always
-          env:
-            - name: POLEMARCH_DB_TYPE
-              value: 'mysql'
-            - name: POLEMARCH_DB_NAME
-              value: 'polemarch-db'
-            - name: POLEMARCH_DB_USER
-              value: 'polemarch-user'
-            - name: POLEMARCH_DB_PASSWORD
-              value: 'polemarch-pas'
-            - name: POLEMARCH_DB_PORT
-              value: '3306'
-            - name: POLEMARCH_DB_HOST
-              value: 'mysql-svc'
-            - name: DB_INIT_CMD
-              value: "SET sql_mode='STRICT_TRANS_TABLES', default_storage_engine=INNODB, NAMES 'utf8', CHARACTER SET 'utf8', SESSION collation_connection = 'utf8_unicode_ci'"
-            - name: CACHE_LOCATION
-              value: 'redis://redis:6379/0'
-            - name: RPC_ENGINE
-              value: 'redis://redis:6379/1'
-            - name: RPC_CONCURRENCY
-              value: '15'
-            - name: POLEMARCH_LOG_LEVEL
-              value: '{{ kube_pm_log_level }}'
-            - name: POLEMARCH_DEBUG
-              value: '{{ kube_pm_debug }}'
-            - name: TIMEZONE
-              value: '{{ kube_pm_timezone }}'
-          ports:
-            - containerPort: 8080
-              name: 8080tcp
-              protocol: TCP
-          tty: true
-          stdin: true
-
----
-apiVersion: v1
-kind: Service
-metadata:
-{% if k8s_kube_in_rancher=="true" %}
-  annotations:
-    field.cattle.io/targetWorkloadIds: '["deployment:{{ k8s_env_namespace }}:polemarch"]'
-{% endif %}
-  name: polemarch-svc
-spec:
-  ports:
-    - name: 8080tcp
-      port: 8080
-      targetPort: 8080
-      protocol: TCP
-  selector:
-    appselector: polemarch
-  sessionAffinity: None
-  type: ClusterIP
-
-#####   Ingress
----
-apiVersion: extensions/v1beta1
-kind: Ingress
-metadata:
-{% if k8s_kube_in_rancher=="true" %}
-  annotations:
-    field.cattle.io/targetWorkloadIds: '["deployment:{{ k8s_env_namespace }}:polemarch"]'
-{% endif %}
-  name: polemarch-ingress
-spec:
-  tls:
-  - hosts: 
-    - {{ k8s_kube_pm_ingress_domain }}
-    secretName: secretkeyvst
-  rules:
-    - host: {{ k8s_kube_pm_ingress_domain }}
-      http:
-        paths:
-          - path: /
-            backend:
-{% if k8s_kube_in_rancher=="true" %}
-              serviceName: polemarch-ingress-svc
-{% elif k8s_kube_in_rancher=="false" or  k8s_kube_in_rancher is not defined %}
-              serviceName: polemarch-svc
-{% endif %}
-              servicePort: 8080
-
-{% if k8s_kube_in_rancher=="true" %}
----
-apiVersion: v1
-kind: Service
-metadata:
-  annotations:
-    field.cattle.io/targetWorkloadIds: '["deployment:{{ k8s_env_namespace }}:polemarch"]'
-  name: polemarch-ingress-svc
-spec:
-  ports:
-    - port: 8080
-      targetPort: 8080
-      protocol: TCP
-  type: ClusterIP
-  sessionAffinity: None
-{% endif %}
diff --git a/k8s_env_deploy.yaml b/k8s_env_deploy.yaml
deleted file mode 100644
index d14bcb78..00000000
--- a/k8s_env_deploy.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-- hosts: all
-  become: yes
-  vars_files:
-    - ./environment/all.yml
-
-  vars:
-    ansible_python_interpreter: "{{ ansible_playbook_python }}"
-
-  tasks:
-  
-    - name: GitLab registry LoginIN
-      docker_login:
-        username: "{{ k8s_registry_user }}"
-        password: "{{ k8s_registry_password }}"
-        registry_url: "{{ k8s_registry_url }}"
-        docker_host: "{{ k8s_docker_host }}"
-        reauthorize: yes
-
-    - name: Build Docker image to registry
-      docker_image:
-        build:
-          path: ./
-          pull: yes
-          dockerfile: ./Dockerfile
-        source: build
-        docker_host: "{{ k8s_docker_host }}"
-        name: "{{ k8s_registry_image_name }}"
-        tag: "{{ k8s_registry_image_tag }}"
-        push: yes 
-
-    - name: Check docker image to registry
-      docker_image_info:
-        name: "{{ k8s_registry_image_name }}:{{ k8s_registry_image_tag }}"
-        docker_host: "{{ k8s_docker_host }}"
-        timeout: 300
-
-    - name: Create template YAML file - Polemarch
-      k8s:
-        kubeconfig: "{{ k8s_kubeconfig }}"
-        namespace: "{{ k8s_env_namespace }}"
-        state: present
-        definition: "{{ k8s_pm_playbook_template }}"
-        wait: yes
diff --git a/k8s_env_destroy.yaml b/k8s_env_destroy.yaml
deleted file mode 100644
index c2ac1a1e..00000000
--- a/k8s_env_destroy.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-- hosts: all
-  become: yes
-  vars_files:
-    - ./environment/all.yml
-  vars:
-    ansible_python_interpreter: "{{ ansible_playbook_python }}"
-
-  tasks:
-
-    - name: Destroy template YAML file - Polemarch
-      k8s:
-        kubeconfig: "{{ k8s_kubeconfig }}"
-        namespace: "{{ k8s_env_namespace }}"
-        state: absent
-        definition: "{{ k8s_pm_playbook_template }}"
diff --git a/rpm.mk b/rpm.mk
deleted file mode 100755
index f1d9377c..00000000
--- a/rpm.mk
+++ /dev/null
@@ -1,80 +0,0 @@
-define RPM_SPEC
-# Macros
-%define name $(NAME)
-%define shortname $(NAME)
-%define namebase $(NAMEBASE)
-%define user $(USER)
-%define version $(VER)
-%define release $(RELEASE)
-%define __prelink_undo_cmd %{nil}
-%define _binaries_in_noarch_packages_terminate_build   0
-%define unmangled_version %{version}
-# Globals
-%global __os_install_post %(echo '%{__os_install_post}' | sed -e 's!/usr/lib[^[:space:]]*/brp-python-bytecompile[[:space:]].*$$!!g')
-
-
-# Tags
-Name: %{name}
-Version: %{version}
-Release: %{release}
-Summary: $(SUMMARY)
-Group: Application/System
-Vendor: $(VENDOR)
-License: ${LICENSE}
-AutoReq: No
-AutoProv: No
-BuildRequires: python, openssl-devel, libyaml-devel
-Requires: python, openssl-devel
-Requires: python-virtualenv
-Requires: git
-Requires: libyaml-devel
-Requires: krb5-devel, krb5-libs, openldap-devel
-Requires: mailcap
-
-
-%description
-$(DESCRIPTION)
-
-
-
-# Blocks
-%files
-%defattr(-,%{user},%{user},-)
-$(INSTALL_DIR)
-/etc/%{namebase}
-/var/log/%{namebase}
-/var/run/%{namebase}
-/var/lock/%{namebase}
-%attr(755,root,root) /etc/systemd/system/%{shortname}.service
-%attr(755,root,root) /etc/tmpfiles.d/%{namebase}.conf
-
-%pre
-id -u %{user} || useradd %{user}
-id -g %{user} || groupadd %{user}
-
-%install
-make BUILD_DIR=%{buildroot}
-
-cd %{buildroot}
-cd -
-
-%post
-su - %{user} -c "/opt/%{name}/bin/%{shortname}ctl migrate"
-/usr/bin/systemctl daemon-reload
-/usr/bin/systemctl enable %{shortname}.service
-
-%preun
-/usr/bin/systemctl disable %{shortname}.service > /dev/null 2>&1
-if [ "$$1" = "0" ]; then
-	service %{shortname} stop >/dev/null 2>&1
-fi
-
-%prep
-rm -rf %{buildroot}/*
-cd %{_topdir}/BUILD
-cp -rf $(SOURCE_DIR)/* .
-
-%clean
-rm -rf %{buildroot}
-endef
-export RPM_SPEC
diff --git a/werf.yaml b/werf.yaml
index bbc1d26b..b9a9504a 100644
--- a/werf.yaml
+++ b/werf.yaml
@@ -1,7 +1,7 @@
 configVersion: 1
 project: polemarch
 cleanup:
-  disableKubernetesBasedPolicy: true
+  disableKubernetesBasedPolicy: false
   disableGitHistoryBasedPolicy: true
   disableBuiltWithinLastNHoursPolicy: true
   keepImagesBuiltWithinLastNHours: 1

From da8e8bc2ae1a67588c930b9683916af235b0fcf1 Mon Sep 17 00:00:00 2001
From: Vladislav Korenkov <vladnfs3@gmail.com>
Date: Tue, 20 Dec 2022 15:40:46 +1000
Subject: [PATCH 7/8] Refactoring: Remove ACL handlers

---
 .gitlab-ci.yml                    |    2 +-
 doc/api_schema.yaml               | 1760 ++++++++++++++---------------
 polemarch/api/v2/permissions.py   |   20 +-
 polemarch/api/v2/serializers.py   |   40 +-
 polemarch/api/v2/views.py         |   88 +-
 polemarch/api/v3/views.py         |    2 +
 polemarch/main/acl/__init__.py    |    0
 polemarch/main/acl/handlers.py    |   39 -
 polemarch/main/constants.py       |    5 +
 polemarch/main/models/__init__.py |    8 +-
 polemarch/main/models/base.py     |   82 +-
 polemarch/main/models/hooks.py    |    3 +-
 polemarch/main/models/projects.py |    4 +-
 polemarch/main/models/tasks.py    |    9 +-
 polemarch/main/models/users.py    |   56 +-
 polemarch/main/models/utils.py    |   13 +
 polemarch/main/models/vars.py     |    5 +-
 polemarch/main/settings.py        |   12 +-
 polemarch/translations/en.py      |    3 +
 polemarch/translations/ru.py      |    2 +
 requirements.txt                  |    2 +-
 setup.py                          |    6 +-
 tests.py                          |   47 +-
 yarn.lock                         |  504 +++++----
 24 files changed, 1389 insertions(+), 1323 deletions(-)
 delete mode 100644 polemarch/main/acl/__init__.py
 delete mode 100644 polemarch/main/acl/handlers.py

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c830fe1c..ae46ffb1 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -56,7 +56,7 @@ stages:
   <<: *branch_tests
   image: registry.gitlab.com/vstconsulting/images:node-tests
   before_script:
-    - yarn install
+    - yarn install --pure-lockfile --mutex network
   script:
     - yarn test
 
diff --git a/doc/api_schema.yaml b/doc/api_schema.yaml
index 959c6fa7..2389f1f8 100644
--- a/doc/api_schema.yaml
+++ b/doc/api_schema.yaml
@@ -69,7 +69,7 @@ info:
   x-versions:
     application: 2.3.0
     library: 2.3.0
-    vstutils: 5.2.2
+    vstutils: 5.2.5
     django: 3.2.16
     djangorestframework: 3.14.0
     drf_yasg: 1.21.4
@@ -11504,14 +11504,11 @@ definitions:
           usePrefetch: true
           value_field: name
           view_field: path
-      args:
-        title: Args
-        description: host pattern
-        type: string
-      background:
-        title: Background
-        description: run asynchronously, failing after X seconds (default=N/A)
+      verbose:
+        title: Verbose
+        description: verbose mode (-vvv for more, -vvvv to enable connection debugging)
         type: integer
+        maximum: 4
       become:
         title: Become
         description: run operations with become (does not imply password prompting)
@@ -11521,57 +11518,36 @@ definitions:
         description: privilege escalation method to use (default=sudo), use `ansible-doc
           -t become -l` to list valid choices.
         type: string
-      check:
-        title: Check
-        description: don't make any changes; instead, try to predict some of the changes
-          that may occur
-        type: boolean
-      connection:
-        title: Connection
-        description: connection type to use (default=smart)
-        type: string
-      diff:
-        title: Diff
-        description: when changing (small) files and templates, show the differences
-          in those files; works great with --check
-        type: boolean
-      extra_vars:
-        title: Extra vars
-        description: set additional variables as key=value or YAML/JSON, if filename
-          prepend with @
-        type: string
-      forks:
-        title: Forks
-        description: specify number of parallel processes to use (default=5)
-        type: integer
       inventory:
         title: Inventory
         description: specify inventory host path or comma separated host list. --inventory-file
           is deprecated
         type: string
         format: inventory
-      limit:
-        title: Limit
-        description: further limit selected hosts to an additional pattern
-        type: string
       list_hosts:
         title: List hosts
         description: outputs a list of matching hosts; does not execute anything else
         type: boolean
-      one_line:
-        title: One line
-        description: condense output
-        type: boolean
-      playbook_dir:
-        title: Playbook dir
-        description: Since this tool does not use playbooks, use this as a substitute
-          playbook directory.This sets the relative path for many features including
-          roles/ group_vars/ etc.
+      limit:
+        title: Limit
+        description: further limit selected hosts to an additional pattern
         type: string
       poll:
         title: Poll
         description: set the poll interval if using -B (default=15)
         type: integer
+      background:
+        title: Background
+        description: run asynchronously, failing after X seconds (default=N/A)
+        type: integer
+      one_line:
+        title: One line
+        description: condense output
+        type: boolean
+      tree:
+        title: Tree
+        description: log output to this directory
+        type: string
       private_key:
         title: Private key
         description: use this file to authenticate the connection
@@ -11580,37 +11556,52 @@ definitions:
         x-options:
           media_types:
             - '*/*'
-      scp_extra_args:
-        title: Scp extra args
-        description: specify extra arguments to pass to scp only (e.g. -l)
+      user:
+        title: User
+        description: connect as this user (default=None)
         type: string
-      sftp_extra_args:
-        title: Sftp extra args
-        description: specify extra arguments to pass to sftp only (e.g. -f, -l)
+      connection:
+        title: Connection
+        description: connection type to use (default=smart)
         type: string
+      timeout:
+        title: Timeout
+        description: override the connection timeout in seconds (default=10)
+        type: integer
       ssh_common_args:
         title: Ssh common args
         description: specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)
         type: string
+      sftp_extra_args:
+        title: Sftp extra args
+        description: specify extra arguments to pass to sftp only (e.g. -f, -l)
+        type: string
+      scp_extra_args:
+        title: Scp extra args
+        description: specify extra arguments to pass to scp only (e.g. -l)
+        type: string
       ssh_extra_args:
         title: Ssh extra args
         description: specify extra arguments to pass to ssh only (e.g. -R)
         type: string
+      check:
+        title: Check
+        description: don't make any changes; instead, try to predict some of the changes
+          that may occur
+        type: boolean
       syntax_check:
         title: Syntax check
         description: perform a syntax check on the playbook, but do not execute it
         type: boolean
-      timeout:
-        title: Timeout
-        description: override the connection timeout in seconds (default=10)
-        type: integer
-      tree:
-        title: Tree
-        description: log output to this directory
-        type: string
-      user:
-        title: User
-        description: connect as this user (default=None)
+      diff:
+        title: Diff
+        description: when changing (small) files and templates, show the differences
+          in those files; works great with --check
+        type: boolean
+      extra_vars:
+        title: Extra vars
+        description: set additional variables as key=value or YAML/JSON, if filename
+          prepend with @
         type: string
       vault_password_file:
         title: Vault password file
@@ -11620,11 +11611,20 @@ definitions:
         x-options:
           media_types:
             - '*/*'
-      verbose:
-        title: Verbose
-        description: verbose mode (-vvv for more, -vvvv to enable connection debugging)
+      forks:
+        title: Forks
+        description: specify number of parallel processes to use (default=5)
         type: integer
-        maximum: 4
+      playbook_dir:
+        title: Playbook dir
+        description: Since this tool does not use playbooks, use this as a substitute
+          playbook directory.This sets the relative path for many features including
+          roles/ group_vars/ etc.
+        type: string
+      args:
+        title: Args
+        description: host pattern
+        type: string
       group:
         title: Group
         type: string
@@ -11632,34 +11632,34 @@ definitions:
     x-properties-groups:
       '':
         - module
-        - args
-        - background
+        - verbose
         - become
         - become_method
-        - check
-        - connection
-        - diff
-        - extra_vars
-        - forks
         - inventory
-        - limit
         - list_hosts
-        - one_line
-        - playbook_dir
+        - limit
         - poll
+        - background
+        - one_line
+        - tree
         - private_key
-        - scp_extra_args
-        - sftp_extra_args
+        - user
+        - connection
+        - timeout
         - ssh_common_args
+        - sftp_extra_args
+        - scp_extra_args
         - ssh_extra_args
+        - check
         - syntax_check
-        - timeout
-        - tree
-        - user
+        - diff
+        - extra_vars
         - vault_password_file
-        - verbose
+        - forks
+        - playbook_dir
+        - args
         - group
-    x-view-field-name: args
+    x-view-field-name: verbose
   ExecuteResponse:
     required:
       - detail
@@ -11703,10 +11703,55 @@ definitions:
           usePrefetch: true
           value_field: playbook
           view_field: name
-      args:
-        title: Args
-        description: Playbook(s)
+      verbose:
+        title: Verbose
+        description: verbose mode (-vvv for more, -vvvv to enable connection debugging)
+        type: integer
+        maximum: 4
+      private_key:
+        title: Private key
+        description: use this file to authenticate the connection
+        type: string
+        format: secretfile
+        x-options:
+          media_types:
+            - '*/*'
+      user:
+        title: User
+        description: connect as this user (default=None)
+        type: string
+      connection:
+        title: Connection
+        description: connection type to use (default=smart)
+        type: string
+      timeout:
+        title: Timeout
+        description: override the connection timeout in seconds (default=10)
+        type: integer
+      ssh_common_args:
+        title: Ssh common args
+        description: specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)
+        type: string
+      sftp_extra_args:
+        title: Sftp extra args
+        description: specify extra arguments to pass to sftp only (e.g. -f, -l)
+        type: string
+      scp_extra_args:
+        title: Scp extra args
+        description: specify extra arguments to pass to scp only (e.g. -l)
+        type: string
+      ssh_extra_args:
+        title: Ssh extra args
+        description: specify extra arguments to pass to ssh only (e.g. -R)
         type: string
+      force_handlers:
+        title: Force handlers
+        description: run handlers even if a task fails
+        type: boolean
+      flush_cache:
+        title: Flush cache
+        description: clear the fact cache for every host in inventory
+        type: boolean
       become:
         title: Become
         description: run operations with become (does not imply password prompting)
@@ -11716,110 +11761,46 @@ definitions:
         description: privilege escalation method to use (default=sudo), use `ansible-doc
           -t become -l` to list valid choices.
         type: string
+      tags:
+        title: Tags
+        description: only run plays and tasks tagged with these values
+        type: string
+      skip_tags:
+        title: Skip tags
+        description: only run plays and tasks whose tags do not match these values
+        type: string
       check:
         title: Check
         description: don't make any changes; instead, try to predict some of the changes
           that may occur
         type: boolean
-      connection:
-        title: Connection
-        description: connection type to use (default=smart)
-        type: string
+      syntax_check:
+        title: Syntax check
+        description: perform a syntax check on the playbook, but do not execute it
+        type: boolean
       diff:
         title: Diff
         description: when changing (small) files and templates, show the differences
           in those files; works great with --check
         type: boolean
-      extra_vars:
-        title: Extra vars
-        description: set additional variables as key=value or YAML/JSON, if filename
-          prepend with @
-        type: string
-      flush_cache:
-        title: Flush cache
-        description: clear the fact cache for every host in inventory
-        type: boolean
-      force_handlers:
-        title: Force handlers
-        description: run handlers even if a task fails
-        type: boolean
-      forks:
-        title: Forks
-        description: specify number of parallel processes to use (default=5)
-        type: integer
       inventory:
         title: Inventory
         description: specify inventory host path or comma separated host list. --inventory-file
           is deprecated
         type: string
         format: inventory
-      limit:
-        title: Limit
-        description: further limit selected hosts to an additional pattern
-        type: string
       list_hosts:
         title: List hosts
         description: outputs a list of matching hosts; does not execute anything else
         type: boolean
-      list_tags:
-        title: List tags
-        description: list all available tags
-        type: boolean
-      list_tasks:
-        title: List tasks
-        description: list all tasks that would be executed
-        type: boolean
-      private_key:
-        title: Private key
-        description: use this file to authenticate the connection
-        type: string
-        format: secretfile
-        x-options:
-          media_types:
-            - '*/*'
-      scp_extra_args:
-        title: Scp extra args
-        description: specify extra arguments to pass to scp only (e.g. -l)
-        type: string
-      sftp_extra_args:
-        title: Sftp extra args
-        description: specify extra arguments to pass to sftp only (e.g. -f, -l)
-        type: string
-      skip_tags:
-        title: Skip tags
-        description: only run plays and tasks whose tags do not match these values
-        type: string
-      ssh_common_args:
-        title: Ssh common args
-        description: specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)
-        type: string
-      ssh_extra_args:
-        title: Ssh extra args
-        description: specify extra arguments to pass to ssh only (e.g. -R)
-        type: string
-      start_at_task:
-        title: Start at task
-        description: start the playbook at the task matching this name
-        type: string
-      step:
-        title: Step
-        description: 'one-step-at-a-time: confirm each task before running'
-        type: boolean
-      syntax_check:
-        title: Syntax check
-        description: perform a syntax check on the playbook, but do not execute it
-        type: boolean
-      tags:
-        title: Tags
-        description: only run plays and tasks tagged with these values
+      limit:
+        title: Limit
+        description: further limit selected hosts to an additional pattern
         type: string
-      timeout:
-        title: Timeout
-        description: override the connection timeout in seconds (default=10)
-        type: integer
-      user:
-        title: User
-        description: connect as this user (default=None)
+      extra_vars:
+        title: Extra vars
+        description: set additional variables as key=value or YAML/JSON, if filename
+          prepend with @
         type: string
       vault_password_file:
         title: Vault password file
@@ -11829,44 +11810,63 @@ definitions:
         x-options:
           media_types:
             - '*/*'
-      verbose:
-        title: Verbose
-        description: verbose mode (-vvv for more, -vvvv to enable connection debugging)
+      forks:
+        title: Forks
+        description: specify number of parallel processes to use (default=5)
         type: integer
-        maximum: 4
+      list_tasks:
+        title: List tasks
+        description: list all tasks that would be executed
+        type: boolean
+      list_tags:
+        title: List tags
+        description: list all available tags
+        type: boolean
+      step:
+        title: Step
+        description: 'one-step-at-a-time: confirm each task before running'
+        type: boolean
+      start_at_task:
+        title: Start at task
+        description: start the playbook at the task matching this name
+        type: string
+      args:
+        title: Args
+        description: Playbook(s)
+        type: string
     x-properties-groups:
       '':
         - playbook
-        - args
+        - verbose
+        - private_key
+        - user
+        - connection
+        - timeout
+        - ssh_common_args
+        - sftp_extra_args
+        - scp_extra_args
+        - ssh_extra_args
+        - force_handlers
+        - flush_cache
         - become
         - become_method
+        - tags
+        - skip_tags
         - check
-        - connection
+        - syntax_check
         - diff
-        - extra_vars
-        - flush_cache
-        - force_handlers
-        - forks
         - inventory
-        - limit
         - list_hosts
-        - list_tags
+        - limit
+        - extra_vars
+        - vault_password_file
+        - forks
         - list_tasks
-        - private_key
-        - scp_extra_args
-        - sftp_extra_args
-        - skip_tags
-        - ssh_common_args
-        - ssh_extra_args
-        - start_at_task
+        - list_tags
         - step
-        - syntax_check
-        - tags
-        - timeout
-        - user
-        - vault_password_file
-        - verbose
-    x-view-field-name: args
+        - start_at_task
+        - args
+    x-view-field-name: verbose
   ExecutionTemplate:
     required:
       - name
@@ -11969,10 +11969,12 @@ definitions:
                 vars:
                   type: object
                   properties:
-                    background:
-                      title: Background
-                      description: run asynchronously, failing after X seconds (default=N/A)
+                    verbose:
+                      title: Verbose
+                      description: verbose mode (-vvv for more, -vvvv to enable connection
+                        debugging)
                       type: integer
+                      maximum: 4
                     become:
                       title: Become
                       description: run operations with become (does not imply password
@@ -11983,52 +11985,31 @@ definitions:
                       description: privilege escalation method to use (default=sudo),
                         use `ansible-doc -t become -l` to list valid choices.
                       type: string
-                    check:
-                      title: Check
-                      description: don't make any changes; instead, try to predict
-                        some of the changes that may occur
-                      type: boolean
-                    connection:
-                      title: Connection
-                      description: connection type to use (default=smart)
-                      type: string
-                    diff:
-                      title: Diff
-                      description: when changing (small) files and templates, show
-                        the differences in those files; works great with --check
-                      type: boolean
-                    extra_vars:
-                      title: Extra vars
-                      description: set additional variables as key=value or YAML/JSON,
-                        if filename prepend with @
-                      type: string
-                    forks:
-                      title: Forks
-                      description: specify number of parallel processes to use (default=5)
-                      type: integer
-                    limit:
-                      title: Limit
-                      description: further limit selected hosts to an additional pattern
-                      type: string
                     list_hosts:
                       title: List hosts
                       description: outputs a list of matching hosts; does not execute
                         anything else
                       type: boolean
-                    one_line:
-                      title: One line
-                      description: condense output
-                      type: boolean
-                    playbook_dir:
-                      title: Playbook dir
-                      description: Since this tool does not use playbooks, use this
-                        as a substitute playbook directory.This sets the relative
-                        path for many features including roles/ group_vars/ etc.
+                    limit:
+                      title: Limit
+                      description: further limit selected hosts to an additional pattern
                       type: string
                     poll:
                       title: Poll
                       description: set the poll interval if using -B (default=15)
                       type: integer
+                    background:
+                      title: Background
+                      description: run asynchronously, failing after X seconds (default=N/A)
+                      type: integer
+                    one_line:
+                      title: One line
+                      description: condense output
+                      type: boolean
+                    tree:
+                      title: Tree
+                      description: log output to this directory
+                      type: string
                     private_key:
                       title: Private key
                       description: use this file to authenticate the connection
@@ -12037,42 +12018,57 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    scp_extra_args:
-                      title: Scp extra args
-                      description: specify extra arguments to pass to scp only (e.g.
-                        -l)
+                    user:
+                      title: User
+                      description: connect as this user (default=None)
                       type: string
-                    sftp_extra_args:
-                      title: Sftp extra args
-                      description: specify extra arguments to pass to sftp only (e.g.
-                        -f, -l)
+                    connection:
+                      title: Connection
+                      description: connection type to use (default=smart)
                       type: string
+                    timeout:
+                      title: Timeout
+                      description: override the connection timeout in seconds (default=10)
+                      type: integer
                     ssh_common_args:
                       title: Ssh common args
                       description: specify common arguments to pass to sftp/scp/ssh
                         (e.g. ProxyCommand)
                       type: string
+                    sftp_extra_args:
+                      title: Sftp extra args
+                      description: specify extra arguments to pass to sftp only (e.g.
+                        -f, -l)
+                      type: string
+                    scp_extra_args:
+                      title: Scp extra args
+                      description: specify extra arguments to pass to scp only (e.g.
+                        -l)
+                      type: string
                     ssh_extra_args:
                       title: Ssh extra args
                       description: specify extra arguments to pass to ssh only (e.g.
                         -R)
                       type: string
+                    check:
+                      title: Check
+                      description: don't make any changes; instead, try to predict
+                        some of the changes that may occur
+                      type: boolean
                     syntax_check:
                       title: Syntax check
                       description: perform a syntax check on the playbook, but do
                         not execute it
                       type: boolean
-                    timeout:
-                      title: Timeout
-                      description: override the connection timeout in seconds (default=10)
-                      type: integer
-                    tree:
-                      title: Tree
-                      description: log output to this directory
-                      type: string
-                    user:
-                      title: User
-                      description: connect as this user (default=None)
+                    diff:
+                      title: Diff
+                      description: when changing (small) files and templates, show
+                        the differences in those files; works great with --check
+                      type: boolean
+                    extra_vars:
+                      title: Extra vars
+                      description: set additional variables as key=value or YAML/JSON,
+                        if filename prepend with @
                       type: string
                     vault_password_file:
                       title: Vault password file
@@ -12082,12 +12078,16 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    verbose:
-                      title: Verbose
-                      description: verbose mode (-vvv for more, -vvvv to enable connection
-                        debugging)
+                    forks:
+                      title: Forks
+                      description: specify number of parallel processes to use (default=5)
                       type: integer
-                      maximum: 4
+                    playbook_dir:
+                      title: Playbook dir
+                      description: Since this tool does not use playbooks, use this
+                        as a substitute playbook directory.This sets the relative
+                        path for many features including roles/ group_vars/ etc.
+                      type: string
             Task:
               required:
                 - playbook
@@ -12106,10 +12106,60 @@ definitions:
                 vars:
                   type: object
                   properties:
-                    args:
-                      title: Args
-                      description: Playbook(s)
-                      type: string
+                    verbose:
+                      title: Verbose
+                      description: verbose mode (-vvv for more, -vvvv to enable connection
+                        debugging)
+                      type: integer
+                      maximum: 4
+                    private_key:
+                      title: Private key
+                      description: use this file to authenticate the connection
+                      type: string
+                      format: secretfile
+                      x-options:
+                        media_types:
+                          - '*/*'
+                    user:
+                      title: User
+                      description: connect as this user (default=None)
+                      type: string
+                    connection:
+                      title: Connection
+                      description: connection type to use (default=smart)
+                      type: string
+                    timeout:
+                      title: Timeout
+                      description: override the connection timeout in seconds (default=10)
+                      type: integer
+                    ssh_common_args:
+                      title: Ssh common args
+                      description: specify common arguments to pass to sftp/scp/ssh
+                        (e.g. ProxyCommand)
+                      type: string
+                    sftp_extra_args:
+                      title: Sftp extra args
+                      description: specify extra arguments to pass to sftp only (e.g.
+                        -f, -l)
+                      type: string
+                    scp_extra_args:
+                      title: Scp extra args
+                      description: specify extra arguments to pass to scp only (e.g.
+                        -l)
+                      type: string
+                    ssh_extra_args:
+                      title: Ssh extra args
+                      description: specify extra arguments to pass to ssh only (e.g.
+                        -R)
+                      type: string
+                    force_handlers:
+                      title: Force handlers
+                      description: run handlers even if a task fails
+                      type: boolean
+                    flush_cache:
+                      title: Flush cache
+                      description: clear the fact cache for every host in inventory
+                      type: boolean
                     become:
                       title: Become
                       description: run operations with become (does not imply password
@@ -12120,126 +12170,76 @@ definitions:
                       description: privilege escalation method to use (default=sudo),
                         use `ansible-doc -t become -l` to list valid choices.
                       type: string
+                    tags:
+                      title: Tags
+                      description: only run plays and tasks tagged with these values
+                      type: string
+                    skip_tags:
+                      title: Skip tags
+                      description: only run plays and tasks whose tags do not match
+                        these values
+                      type: string
                     check:
                       title: Check
                       description: don't make any changes; instead, try to predict
                         some of the changes that may occur
                       type: boolean
-                    connection:
-                      title: Connection
-                      description: connection type to use (default=smart)
-                      type: string
+                    syntax_check:
+                      title: Syntax check
+                      description: perform a syntax check on the playbook, but do
+                        not execute it
+                      type: boolean
                     diff:
                       title: Diff
                       description: when changing (small) files and templates, show
                         the differences in those files; works great with --check
                       type: boolean
+                    list_hosts:
+                      title: List hosts
+                      description: outputs a list of matching hosts; does not execute
+                        anything else
+                      type: boolean
+                    limit:
+                      title: Limit
+                      description: further limit selected hosts to an additional pattern
+                      type: string
                     extra_vars:
                       title: Extra vars
                       description: set additional variables as key=value or YAML/JSON,
                         if filename prepend with @
                       type: string
-                    flush_cache:
-                      title: Flush cache
-                      description: clear the fact cache for every host in inventory
-                      type: boolean
-                    force_handlers:
-                      title: Force handlers
-                      description: run handlers even if a task fails
-                      type: boolean
+                    vault_password_file:
+                      title: Vault password file
+                      description: vault password file
+                      type: string
+                      format: secretfile
+                      x-options:
+                        media_types:
+                          - '*/*'
                     forks:
                       title: Forks
                       description: specify number of parallel processes to use (default=5)
                       type: integer
-                    limit:
-                      title: Limit
-                      description: further limit selected hosts to an additional pattern
-                      type: string
-                    list_hosts:
-                      title: List hosts
-                      description: outputs a list of matching hosts; does not execute
-                        anything else
+                    list_tasks:
+                      title: List tasks
+                      description: list all tasks that would be executed
                       type: boolean
                     list_tags:
                       title: List tags
                       description: list all available tags
                       type: boolean
-                    list_tasks:
-                      title: List tasks
-                      description: list all tasks that would be executed
-                      type: boolean
-                    private_key:
-                      title: Private key
-                      description: use this file to authenticate the connection
-                      type: string
-                      format: secretfile
-                      x-options:
-                        media_types:
-                          - '*/*'
-                    scp_extra_args:
-                      title: Scp extra args
-                      description: specify extra arguments to pass to scp only (e.g.
-                        -l)
-                      type: string
-                    sftp_extra_args:
-                      title: Sftp extra args
-                      description: specify extra arguments to pass to sftp only (e.g.
-                        -f, -l)
-                      type: string
-                    skip_tags:
-                      title: Skip tags
-                      description: only run plays and tasks whose tags do not match
-                        these values
-                      type: string
-                    ssh_common_args:
-                      title: Ssh common args
-                      description: specify common arguments to pass to sftp/scp/ssh
-                        (e.g. ProxyCommand)
-                      type: string
-                    ssh_extra_args:
-                      title: Ssh extra args
-                      description: specify extra arguments to pass to ssh only (e.g.
-                        -R)
-                      type: string
-                    start_at_task:
-                      title: Start at task
-                      description: start the playbook at the task matching this name
-                      type: string
                     step:
                       title: Step
                       description: 'one-step-at-a-time: confirm each task before running'
                       type: boolean
-                    syntax_check:
-                      title: Syntax check
-                      description: perform a syntax check on the playbook, but do
-                        not execute it
-                      type: boolean
-                    tags:
-                      title: Tags
-                      description: only run plays and tasks tagged with these values
-                      type: string
-                    timeout:
-                      title: Timeout
-                      description: override the connection timeout in seconds (default=10)
-                      type: integer
-                    user:
-                      title: User
-                      description: connect as this user (default=None)
+                    start_at_task:
+                      title: Start at task
+                      description: start the playbook at the task matching this name
                       type: string
-                    vault_password_file:
-                      title: Vault password file
-                      description: vault password file
+                    args:
+                      title: Args
+                      description: Playbook(s)
                       type: string
-                      format: secretfile
-                      x-options:
-                        media_types:
-                          - '*/*'
-                    verbose:
-                      title: Verbose
-                      description: verbose mode (-vvv for more, -vvvv to enable connection
-                        debugging)
-                      type: integer
-                      maximum: 4
     x-properties-groups:
       '':
         - id
@@ -12324,10 +12324,12 @@ definitions:
                 vars:
                   type: object
                   properties:
-                    background:
-                      title: Background
-                      description: run asynchronously, failing after X seconds (default=N/A)
+                    verbose:
+                      title: Verbose
+                      description: verbose mode (-vvv for more, -vvvv to enable connection
+                        debugging)
                       type: integer
+                      maximum: 4
                     become:
                       title: Become
                       description: run operations with become (does not imply password
@@ -12338,52 +12340,31 @@ definitions:
                       description: privilege escalation method to use (default=sudo),
                         use `ansible-doc -t become -l` to list valid choices.
                       type: string
-                    check:
-                      title: Check
-                      description: don't make any changes; instead, try to predict
-                        some of the changes that may occur
-                      type: boolean
-                    connection:
-                      title: Connection
-                      description: connection type to use (default=smart)
-                      type: string
-                    diff:
-                      title: Diff
-                      description: when changing (small) files and templates, show
-                        the differences in those files; works great with --check
-                      type: boolean
-                    extra_vars:
-                      title: Extra vars
-                      description: set additional variables as key=value or YAML/JSON,
-                        if filename prepend with @
-                      type: string
-                    forks:
-                      title: Forks
-                      description: specify number of parallel processes to use (default=5)
-                      type: integer
-                    limit:
-                      title: Limit
-                      description: further limit selected hosts to an additional pattern
-                      type: string
                     list_hosts:
                       title: List hosts
                       description: outputs a list of matching hosts; does not execute
                         anything else
                       type: boolean
-                    one_line:
-                      title: One line
-                      description: condense output
-                      type: boolean
-                    playbook_dir:
-                      title: Playbook dir
-                      description: Since this tool does not use playbooks, use this
-                        as a substitute playbook directory.This sets the relative
-                        path for many features including roles/ group_vars/ etc.
+                    limit:
+                      title: Limit
+                      description: further limit selected hosts to an additional pattern
                       type: string
                     poll:
                       title: Poll
                       description: set the poll interval if using -B (default=15)
                       type: integer
+                    background:
+                      title: Background
+                      description: run asynchronously, failing after X seconds (default=N/A)
+                      type: integer
+                    one_line:
+                      title: One line
+                      description: condense output
+                      type: boolean
+                    tree:
+                      title: Tree
+                      description: log output to this directory
+                      type: string
                     private_key:
                       title: Private key
                       description: use this file to authenticate the connection
@@ -12392,42 +12373,57 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    scp_extra_args:
-                      title: Scp extra args
-                      description: specify extra arguments to pass to scp only (e.g.
-                        -l)
-                      type: string
-                    sftp_extra_args:
-                      title: Sftp extra args
-                      description: specify extra arguments to pass to sftp only (e.g.
-                        -f, -l)
+                    user:
+                      title: User
+                      description: connect as this user (default=None)
                       type: string
-                    ssh_common_args:
+                    connection:
+                      title: Connection
+                      description: connection type to use (default=smart)
+                      type: string
+                    timeout:
+                      title: Timeout
+                      description: override the connection timeout in seconds (default=10)
+                      type: integer
+                    ssh_common_args:
                       title: Ssh common args
                       description: specify common arguments to pass to sftp/scp/ssh
                         (e.g. ProxyCommand)
                       type: string
+                    sftp_extra_args:
+                      title: Sftp extra args
+                      description: specify extra arguments to pass to sftp only (e.g.
+                        -f, -l)
+                      type: string
+                    scp_extra_args:
+                      title: Scp extra args
+                      description: specify extra arguments to pass to scp only (e.g.
+                        -l)
+                      type: string
                     ssh_extra_args:
                       title: Ssh extra args
                       description: specify extra arguments to pass to ssh only (e.g.
                         -R)
                       type: string
+                    check:
+                      title: Check
+                      description: don't make any changes; instead, try to predict
+                        some of the changes that may occur
+                      type: boolean
                     syntax_check:
                       title: Syntax check
                       description: perform a syntax check on the playbook, but do
                         not execute it
                       type: boolean
-                    timeout:
-                      title: Timeout
-                      description: override the connection timeout in seconds (default=10)
-                      type: integer
-                    tree:
-                      title: Tree
-                      description: log output to this directory
-                      type: string
-                    user:
-                      title: User
-                      description: connect as this user (default=None)
+                    diff:
+                      title: Diff
+                      description: when changing (small) files and templates, show
+                        the differences in those files; works great with --check
+                      type: boolean
+                    extra_vars:
+                      title: Extra vars
+                      description: set additional variables as key=value or YAML/JSON,
+                        if filename prepend with @
                       type: string
                     vault_password_file:
                       title: Vault password file
@@ -12437,12 +12433,16 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    verbose:
-                      title: Verbose
-                      description: verbose mode (-vvv for more, -vvvv to enable connection
-                        debugging)
+                    forks:
+                      title: Forks
+                      description: specify number of parallel processes to use (default=5)
                       type: integer
-                      maximum: 4
+                    playbook_dir:
+                      title: Playbook dir
+                      description: Since this tool does not use playbooks, use this
+                        as a substitute playbook directory.This sets the relative
+                        path for many features including roles/ group_vars/ etc.
+                      type: string
             Task:
               required:
                 - playbook
@@ -12461,10 +12461,60 @@ definitions:
                 vars:
                   type: object
                   properties:
-                    args:
-                      title: Args
-                      description: Playbook(s)
+                    verbose:
+                      title: Verbose
+                      description: verbose mode (-vvv for more, -vvvv to enable connection
+                        debugging)
+                      type: integer
+                      maximum: 4
+                    private_key:
+                      title: Private key
+                      description: use this file to authenticate the connection
+                      type: string
+                      format: secretfile
+                      x-options:
+                        media_types:
+                          - '*/*'
+                    user:
+                      title: User
+                      description: connect as this user (default=None)
+                      type: string
+                    connection:
+                      title: Connection
+                      description: connection type to use (default=smart)
+                      type: string
+                    timeout:
+                      title: Timeout
+                      description: override the connection timeout in seconds (default=10)
+                      type: integer
+                    ssh_common_args:
+                      title: Ssh common args
+                      description: specify common arguments to pass to sftp/scp/ssh
+                        (e.g. ProxyCommand)
+                      type: string
+                    sftp_extra_args:
+                      title: Sftp extra args
+                      description: specify extra arguments to pass to sftp only (e.g.
+                        -f, -l)
                       type: string
+                    scp_extra_args:
+                      title: Scp extra args
+                      description: specify extra arguments to pass to scp only (e.g.
+                        -l)
+                      type: string
+                    ssh_extra_args:
+                      title: Ssh extra args
+                      description: specify extra arguments to pass to ssh only (e.g.
+                        -R)
+                      type: string
+                    force_handlers:
+                      title: Force handlers
+                      description: run handlers even if a task fails
+                      type: boolean
+                    flush_cache:
+                      title: Flush cache
+                      description: clear the fact cache for every host in inventory
+                      type: boolean
                     become:
                       title: Become
                       description: run operations with become (does not imply password
@@ -12475,126 +12525,76 @@ definitions:
                       description: privilege escalation method to use (default=sudo),
                         use `ansible-doc -t become -l` to list valid choices.
                       type: string
+                    tags:
+                      title: Tags
+                      description: only run plays and tasks tagged with these values
+                      type: string
+                    skip_tags:
+                      title: Skip tags
+                      description: only run plays and tasks whose tags do not match
+                        these values
+                      type: string
                     check:
                       title: Check
                       description: don't make any changes; instead, try to predict
                         some of the changes that may occur
                       type: boolean
-                    connection:
-                      title: Connection
-                      description: connection type to use (default=smart)
-                      type: string
+                    syntax_check:
+                      title: Syntax check
+                      description: perform a syntax check on the playbook, but do
+                        not execute it
+                      type: boolean
                     diff:
                       title: Diff
                       description: when changing (small) files and templates, show
                         the differences in those files; works great with --check
                       type: boolean
+                    list_hosts:
+                      title: List hosts
+                      description: outputs a list of matching hosts; does not execute
+                        anything else
+                      type: boolean
+                    limit:
+                      title: Limit
+                      description: further limit selected hosts to an additional pattern
+                      type: string
                     extra_vars:
                       title: Extra vars
                       description: set additional variables as key=value or YAML/JSON,
                         if filename prepend with @
                       type: string
-                    flush_cache:
-                      title: Flush cache
-                      description: clear the fact cache for every host in inventory
-                      type: boolean
-                    force_handlers:
-                      title: Force handlers
-                      description: run handlers even if a task fails
-                      type: boolean
+                    vault_password_file:
+                      title: Vault password file
+                      description: vault password file
+                      type: string
+                      format: secretfile
+                      x-options:
+                        media_types:
+                          - '*/*'
                     forks:
                       title: Forks
                       description: specify number of parallel processes to use (default=5)
                       type: integer
-                    limit:
-                      title: Limit
-                      description: further limit selected hosts to an additional pattern
-                      type: string
-                    list_hosts:
-                      title: List hosts
-                      description: outputs a list of matching hosts; does not execute
-                        anything else
+                    list_tasks:
+                      title: List tasks
+                      description: list all tasks that would be executed
                       type: boolean
                     list_tags:
                       title: List tags
                       description: list all available tags
                       type: boolean
-                    list_tasks:
-                      title: List tasks
-                      description: list all tasks that would be executed
-                      type: boolean
-                    private_key:
-                      title: Private key
-                      description: use this file to authenticate the connection
-                      type: string
-                      format: secretfile
-                      x-options:
-                        media_types:
-                          - '*/*'
-                    scp_extra_args:
-                      title: Scp extra args
-                      description: specify extra arguments to pass to scp only (e.g.
-                        -l)
-                      type: string
-                    sftp_extra_args:
-                      title: Sftp extra args
-                      description: specify extra arguments to pass to sftp only (e.g.
-                        -f, -l)
-                      type: string
-                    skip_tags:
-                      title: Skip tags
-                      description: only run plays and tasks whose tags do not match
-                        these values
-                      type: string
-                    ssh_common_args:
-                      title: Ssh common args
-                      description: specify common arguments to pass to sftp/scp/ssh
-                        (e.g. ProxyCommand)
-                      type: string
-                    ssh_extra_args:
-                      title: Ssh extra args
-                      description: specify extra arguments to pass to ssh only (e.g.
-                        -R)
-                      type: string
-                    start_at_task:
-                      title: Start at task
-                      description: start the playbook at the task matching this name
-                      type: string
                     step:
                       title: Step
                       description: 'one-step-at-a-time: confirm each task before running'
                       type: boolean
-                    syntax_check:
-                      title: Syntax check
-                      description: perform a syntax check on the playbook, but do
-                        not execute it
-                      type: boolean
-                    tags:
-                      title: Tags
-                      description: only run plays and tasks tagged with these values
-                      type: string
-                    timeout:
-                      title: Timeout
-                      description: override the connection timeout in seconds (default=10)
-                      type: integer
-                    user:
-                      title: User
-                      description: connect as this user (default=None)
+                    start_at_task:
+                      title: Start at task
+                      description: start the playbook at the task matching this name
                       type: string
-                    vault_password_file:
-                      title: Vault password file
-                      description: vault password file
+                    args:
+                      title: Args
+                      description: Playbook(s)
                       type: string
-                      format: secretfile
-                      x-options:
-                        media_types:
-                          - '*/*'
-                    verbose:
-                      title: Verbose
-                      description: verbose mode (-vvv for more, -vvvv to enable connection
-                        debugging)
-                      type: integer
-                      maximum: 4
     x-properties-groups:
       '':
         - id
@@ -12701,10 +12701,12 @@ definitions:
                 vars:
                   type: object
                   properties:
-                    background:
-                      title: Background
-                      description: run asynchronously, failing after X seconds (default=N/A)
+                    verbose:
+                      title: Verbose
+                      description: verbose mode (-vvv for more, -vvvv to enable connection
+                        debugging)
                       type: integer
+                      maximum: 4
                     become:
                       title: Become
                       description: run operations with become (does not imply password
@@ -12715,52 +12717,31 @@ definitions:
                       description: privilege escalation method to use (default=sudo),
                         use `ansible-doc -t become -l` to list valid choices.
                       type: string
-                    check:
-                      title: Check
-                      description: don't make any changes; instead, try to predict
-                        some of the changes that may occur
-                      type: boolean
-                    connection:
-                      title: Connection
-                      description: connection type to use (default=smart)
-                      type: string
-                    diff:
-                      title: Diff
-                      description: when changing (small) files and templates, show
-                        the differences in those files; works great with --check
-                      type: boolean
-                    extra_vars:
-                      title: Extra vars
-                      description: set additional variables as key=value or YAML/JSON,
-                        if filename prepend with @
-                      type: string
-                    forks:
-                      title: Forks
-                      description: specify number of parallel processes to use (default=5)
-                      type: integer
-                    limit:
-                      title: Limit
-                      description: further limit selected hosts to an additional pattern
-                      type: string
                     list_hosts:
                       title: List hosts
                       description: outputs a list of matching hosts; does not execute
                         anything else
                       type: boolean
-                    one_line:
-                      title: One line
-                      description: condense output
-                      type: boolean
-                    playbook_dir:
-                      title: Playbook dir
-                      description: Since this tool does not use playbooks, use this
-                        as a substitute playbook directory.This sets the relative
-                        path for many features including roles/ group_vars/ etc.
+                    limit:
+                      title: Limit
+                      description: further limit selected hosts to an additional pattern
                       type: string
                     poll:
                       title: Poll
                       description: set the poll interval if using -B (default=15)
                       type: integer
+                    background:
+                      title: Background
+                      description: run asynchronously, failing after X seconds (default=N/A)
+                      type: integer
+                    one_line:
+                      title: One line
+                      description: condense output
+                      type: boolean
+                    tree:
+                      title: Tree
+                      description: log output to this directory
+                      type: string
                     private_key:
                       title: Private key
                       description: use this file to authenticate the connection
@@ -12769,42 +12750,57 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    scp_extra_args:
-                      title: Scp extra args
-                      description: specify extra arguments to pass to scp only (e.g.
-                        -l)
+                    user:
+                      title: User
+                      description: connect as this user (default=None)
                       type: string
-                    sftp_extra_args:
-                      title: Sftp extra args
-                      description: specify extra arguments to pass to sftp only (e.g.
-                        -f, -l)
+                    connection:
+                      title: Connection
+                      description: connection type to use (default=smart)
                       type: string
+                    timeout:
+                      title: Timeout
+                      description: override the connection timeout in seconds (default=10)
+                      type: integer
                     ssh_common_args:
                       title: Ssh common args
                       description: specify common arguments to pass to sftp/scp/ssh
                         (e.g. ProxyCommand)
                       type: string
+                    sftp_extra_args:
+                      title: Sftp extra args
+                      description: specify extra arguments to pass to sftp only (e.g.
+                        -f, -l)
+                      type: string
+                    scp_extra_args:
+                      title: Scp extra args
+                      description: specify extra arguments to pass to scp only (e.g.
+                        -l)
+                      type: string
                     ssh_extra_args:
                       title: Ssh extra args
                       description: specify extra arguments to pass to ssh only (e.g.
                         -R)
                       type: string
+                    check:
+                      title: Check
+                      description: don't make any changes; instead, try to predict
+                        some of the changes that may occur
+                      type: boolean
                     syntax_check:
                       title: Syntax check
                       description: perform a syntax check on the playbook, but do
                         not execute it
                       type: boolean
-                    timeout:
-                      title: Timeout
-                      description: override the connection timeout in seconds (default=10)
-                      type: integer
-                    tree:
-                      title: Tree
-                      description: log output to this directory
-                      type: string
-                    user:
-                      title: User
-                      description: connect as this user (default=None)
+                    diff:
+                      title: Diff
+                      description: when changing (small) files and templates, show
+                        the differences in those files; works great with --check
+                      type: boolean
+                    extra_vars:
+                      title: Extra vars
+                      description: set additional variables as key=value or YAML/JSON,
+                        if filename prepend with @
                       type: string
                     vault_password_file:
                       title: Vault password file
@@ -12814,12 +12810,16 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    verbose:
-                      title: Verbose
-                      description: verbose mode (-vvv for more, -vvvv to enable connection
-                        debugging)
+                    forks:
+                      title: Forks
+                      description: specify number of parallel processes to use (default=5)
                       type: integer
-                      maximum: 4
+                    playbook_dir:
+                      title: Playbook dir
+                      description: Since this tool does not use playbooks, use this
+                        as a substitute playbook directory.This sets the relative
+                        path for many features including roles/ group_vars/ etc.
+                      type: string
             Task:
               required:
                 - playbook
@@ -12838,10 +12838,60 @@ definitions:
                 vars:
                   type: object
                   properties:
-                    args:
-                      title: Args
-                      description: Playbook(s)
+                    verbose:
+                      title: Verbose
+                      description: verbose mode (-vvv for more, -vvvv to enable connection
+                        debugging)
+                      type: integer
+                      maximum: 4
+                    private_key:
+                      title: Private key
+                      description: use this file to authenticate the connection
+                      type: string
+                      format: secretfile
+                      x-options:
+                        media_types:
+                          - '*/*'
+                    user:
+                      title: User
+                      description: connect as this user (default=None)
                       type: string
+                    connection:
+                      title: Connection
+                      description: connection type to use (default=smart)
+                      type: string
+                    timeout:
+                      title: Timeout
+                      description: override the connection timeout in seconds (default=10)
+                      type: integer
+                    ssh_common_args:
+                      title: Ssh common args
+                      description: specify common arguments to pass to sftp/scp/ssh
+                        (e.g. ProxyCommand)
+                      type: string
+                    sftp_extra_args:
+                      title: Sftp extra args
+                      description: specify extra arguments to pass to sftp only (e.g.
+                        -f, -l)
+                      type: string
+                    scp_extra_args:
+                      title: Scp extra args
+                      description: specify extra arguments to pass to scp only (e.g.
+                        -l)
+                      type: string
+                    ssh_extra_args:
+                      title: Ssh extra args
+                      description: specify extra arguments to pass to ssh only (e.g.
+                        -R)
+                      type: string
+                    force_handlers:
+                      title: Force handlers
+                      description: run handlers even if a task fails
+                      type: boolean
+                    flush_cache:
+                      title: Flush cache
+                      description: clear the fact cache for every host in inventory
+                      type: boolean
                     become:
                       title: Become
                       description: run operations with become (does not imply password
@@ -12852,126 +12902,76 @@ definitions:
                       description: privilege escalation method to use (default=sudo),
                         use `ansible-doc -t become -l` to list valid choices.
                       type: string
+                    tags:
+                      title: Tags
+                      description: only run plays and tasks tagged with these values
+                      type: string
+                    skip_tags:
+                      title: Skip tags
+                      description: only run plays and tasks whose tags do not match
+                        these values
+                      type: string
                     check:
                       title: Check
                       description: don't make any changes; instead, try to predict
                         some of the changes that may occur
                       type: boolean
-                    connection:
-                      title: Connection
-                      description: connection type to use (default=smart)
-                      type: string
+                    syntax_check:
+                      title: Syntax check
+                      description: perform a syntax check on the playbook, but do
+                        not execute it
+                      type: boolean
                     diff:
                       title: Diff
                       description: when changing (small) files and templates, show
                         the differences in those files; works great with --check
                       type: boolean
+                    list_hosts:
+                      title: List hosts
+                      description: outputs a list of matching hosts; does not execute
+                        anything else
+                      type: boolean
+                    limit:
+                      title: Limit
+                      description: further limit selected hosts to an additional pattern
+                      type: string
                     extra_vars:
                       title: Extra vars
                       description: set additional variables as key=value or YAML/JSON,
                         if filename prepend with @
                       type: string
-                    flush_cache:
-                      title: Flush cache
-                      description: clear the fact cache for every host in inventory
-                      type: boolean
-                    force_handlers:
-                      title: Force handlers
-                      description: run handlers even if a task fails
-                      type: boolean
+                    vault_password_file:
+                      title: Vault password file
+                      description: vault password file
+                      type: string
+                      format: secretfile
+                      x-options:
+                        media_types:
+                          - '*/*'
                     forks:
                       title: Forks
                       description: specify number of parallel processes to use (default=5)
                       type: integer
-                    limit:
-                      title: Limit
-                      description: further limit selected hosts to an additional pattern
-                      type: string
-                    list_hosts:
-                      title: List hosts
-                      description: outputs a list of matching hosts; does not execute
-                        anything else
+                    list_tasks:
+                      title: List tasks
+                      description: list all tasks that would be executed
                       type: boolean
                     list_tags:
                       title: List tags
                       description: list all available tags
                       type: boolean
-                    list_tasks:
-                      title: List tasks
-                      description: list all tasks that would be executed
-                      type: boolean
-                    private_key:
-                      title: Private key
-                      description: use this file to authenticate the connection
-                      type: string
-                      format: secretfile
-                      x-options:
-                        media_types:
-                          - '*/*'
-                    scp_extra_args:
-                      title: Scp extra args
-                      description: specify extra arguments to pass to scp only (e.g.
-                        -l)
-                      type: string
-                    sftp_extra_args:
-                      title: Sftp extra args
-                      description: specify extra arguments to pass to sftp only (e.g.
-                        -f, -l)
-                      type: string
-                    skip_tags:
-                      title: Skip tags
-                      description: only run plays and tasks whose tags do not match
-                        these values
-                      type: string
-                    ssh_common_args:
-                      title: Ssh common args
-                      description: specify common arguments to pass to sftp/scp/ssh
-                        (e.g. ProxyCommand)
-                      type: string
-                    ssh_extra_args:
-                      title: Ssh extra args
-                      description: specify extra arguments to pass to ssh only (e.g.
-                        -R)
-                      type: string
-                    start_at_task:
-                      title: Start at task
-                      description: start the playbook at the task matching this name
-                      type: string
                     step:
                       title: Step
                       description: 'one-step-at-a-time: confirm each task before running'
                       type: boolean
-                    syntax_check:
-                      title: Syntax check
-                      description: perform a syntax check on the playbook, but do
-                        not execute it
-                      type: boolean
-                    tags:
-                      title: Tags
-                      description: only run plays and tasks tagged with these values
-                      type: string
-                    timeout:
-                      title: Timeout
-                      description: override the connection timeout in seconds (default=10)
-                      type: integer
-                    user:
-                      title: User
-                      description: connect as this user (default=None)
+                    start_at_task:
+                      title: Start at task
+                      description: start the playbook at the task matching this name
                       type: string
-                    vault_password_file:
-                      title: Vault password file
-                      description: vault password file
+                    args:
+                      title: Args
+                      description: Playbook(s)
                       type: string
-                      format: secretfile
-                      x-options:
-                        media_types:
-                          - '*/*'
-                    verbose:
-                      title: Verbose
-                      description: verbose mode (-vvv for more, -vvvv to enable connection
-                        debugging)
-                      type: integer
-                      maximum: 4
     x-properties-groups:
       '':
         - id
@@ -13034,10 +13034,12 @@ definitions:
                 vars:
                   type: object
                   properties:
-                    background:
-                      title: Background
-                      description: run asynchronously, failing after X seconds (default=N/A)
+                    verbose:
+                      title: Verbose
+                      description: verbose mode (-vvv for more, -vvvv to enable connection
+                        debugging)
                       type: integer
+                      maximum: 4
                     become:
                       title: Become
                       description: run operations with become (does not imply password
@@ -13048,52 +13050,31 @@ definitions:
                       description: privilege escalation method to use (default=sudo),
                         use `ansible-doc -t become -l` to list valid choices.
                       type: string
-                    check:
-                      title: Check
-                      description: don't make any changes; instead, try to predict
-                        some of the changes that may occur
-                      type: boolean
-                    connection:
-                      title: Connection
-                      description: connection type to use (default=smart)
-                      type: string
-                    diff:
-                      title: Diff
-                      description: when changing (small) files and templates, show
-                        the differences in those files; works great with --check
-                      type: boolean
-                    extra_vars:
-                      title: Extra vars
-                      description: set additional variables as key=value or YAML/JSON,
-                        if filename prepend with @
-                      type: string
-                    forks:
-                      title: Forks
-                      description: specify number of parallel processes to use (default=5)
-                      type: integer
-                    limit:
-                      title: Limit
-                      description: further limit selected hosts to an additional pattern
-                      type: string
                     list_hosts:
                       title: List hosts
                       description: outputs a list of matching hosts; does not execute
                         anything else
                       type: boolean
-                    one_line:
-                      title: One line
-                      description: condense output
-                      type: boolean
-                    playbook_dir:
-                      title: Playbook dir
-                      description: Since this tool does not use playbooks, use this
-                        as a substitute playbook directory.This sets the relative
-                        path for many features including roles/ group_vars/ etc.
+                    limit:
+                      title: Limit
+                      description: further limit selected hosts to an additional pattern
                       type: string
                     poll:
                       title: Poll
                       description: set the poll interval if using -B (default=15)
                       type: integer
+                    background:
+                      title: Background
+                      description: run asynchronously, failing after X seconds (default=N/A)
+                      type: integer
+                    one_line:
+                      title: One line
+                      description: condense output
+                      type: boolean
+                    tree:
+                      title: Tree
+                      description: log output to this directory
+                      type: string
                     private_key:
                       title: Private key
                       description: use this file to authenticate the connection
@@ -13102,137 +13083,100 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    scp_extra_args:
-                      title: Scp extra args
-                      description: specify extra arguments to pass to scp only (e.g.
-                        -l)
+                    user:
+                      title: User
+                      description: connect as this user (default=None)
                       type: string
-                    sftp_extra_args:
-                      title: Sftp extra args
-                      description: specify extra arguments to pass to sftp only (e.g.
-                        -f, -l)
+                    connection:
+                      title: Connection
+                      description: connection type to use (default=smart)
                       type: string
+                    timeout:
+                      title: Timeout
+                      description: override the connection timeout in seconds (default=10)
+                      type: integer
                     ssh_common_args:
                       title: Ssh common args
                       description: specify common arguments to pass to sftp/scp/ssh
                         (e.g. ProxyCommand)
                       type: string
+                    sftp_extra_args:
+                      title: Sftp extra args
+                      description: specify extra arguments to pass to sftp only (e.g.
+                        -f, -l)
+                      type: string
+                    scp_extra_args:
+                      title: Scp extra args
+                      description: specify extra arguments to pass to scp only (e.g.
+                        -l)
+                      type: string
                     ssh_extra_args:
                       title: Ssh extra args
                       description: specify extra arguments to pass to ssh only (e.g.
                         -R)
                       type: string
-                    syntax_check:
-                      title: Syntax check
-                      description: perform a syntax check on the playbook, but do
-                        not execute it
-                      type: boolean
-                    timeout:
-                      title: Timeout
-                      description: override the connection timeout in seconds (default=10)
-                      type: integer
-                    tree:
-                      title: Tree
-                      description: log output to this directory
-                      type: string
-                    user:
-                      title: User
-                      description: connect as this user (default=None)
-                      type: string
-                    vault_password_file:
-                      title: Vault password file
-                      description: vault password file
-                      type: string
-                      format: secretfile
-                      x-options:
-                        media_types:
-                          - '*/*'
-                    verbose:
-                      title: Verbose
-                      description: verbose mode (-vvv for more, -vvvv to enable connection
-                        debugging)
-                      type: integer
-                      maximum: 4
-            Task:
-              required:
-                - playbook
-              type: object
-              properties:
-                playbook:
-                  title: Playbook
-                  type: string
-                  format: fk_autocomplete
-                  x-options:
-                    model:
-                      $ref: '#/definitions/Playbook'
-                    usePrefetch: true
-                    value_field: playbook
-                    view_field: playbook
-                vars:
-                  type: object
-                  properties:
-                    args:
-                      title: Args
-                      description: Playbook(s)
-                      type: string
-                    become:
-                      title: Become
-                      description: run operations with become (does not imply password
-                        prompting)
-                      type: boolean
-                    become_method:
-                      title: Become method
-                      description: privilege escalation method to use (default=sudo),
-                        use `ansible-doc -t become -l` to list valid choices.
-                      type: string
                     check:
                       title: Check
                       description: don't make any changes; instead, try to predict
                         some of the changes that may occur
                       type: boolean
-                    connection:
-                      title: Connection
-                      description: connection type to use (default=smart)
-                      type: string
+                    syntax_check:
+                      title: Syntax check
+                      description: perform a syntax check on the playbook, but do
+                        not execute it
+                      type: boolean
                     diff:
                       title: Diff
-                      description: when changing (small) files and templates, show
-                        the differences in those files; works great with --check
-                      type: boolean
-                    extra_vars:
-                      title: Extra vars
-                      description: set additional variables as key=value or YAML/JSON,
-                        if filename prepend with @
-                      type: string
-                    flush_cache:
-                      title: Flush cache
-                      description: clear the fact cache for every host in inventory
-                      type: boolean
-                    force_handlers:
-                      title: Force handlers
-                      description: run handlers even if a task fails
+                      description: when changing (small) files and templates, show
+                        the differences in those files; works great with --check
                       type: boolean
+                    extra_vars:
+                      title: Extra vars
+                      description: set additional variables as key=value or YAML/JSON,
+                        if filename prepend with @
+                      type: string
+                    vault_password_file:
+                      title: Vault password file
+                      description: vault password file
+                      type: string
+                      format: secretfile
+                      x-options:
+                        media_types:
+                          - '*/*'
                     forks:
                       title: Forks
                       description: specify number of parallel processes to use (default=5)
                       type: integer
-                    limit:
-                      title: Limit
-                      description: further limit selected hosts to an additional pattern
+                    playbook_dir:
+                      title: Playbook dir
+                      description: Since this tool does not use playbooks, use this
+                        as a substitute playbook directory.This sets the relative
+                        path for many features including roles/ group_vars/ etc.
                       type: string
-                    list_hosts:
-                      title: List hosts
-                      description: outputs a list of matching hosts; does not execute
-                        anything else
-                      type: boolean
-                    list_tags:
-                      title: List tags
-                      description: list all available tags
-                      type: boolean
-                    list_tasks:
-                      title: List tasks
-                      description: list all tasks that would be executed
-                      type: boolean
+            Task:
+              required:
+                - playbook
+              type: object
+              properties:
+                playbook:
+                  title: Playbook
+                  type: string
+                  format: fk_autocomplete
+                  x-options:
+                    model:
+                      $ref: '#/definitions/Playbook'
+                    usePrefetch: true
+                    value_field: playbook
+                    view_field: playbook
+                vars:
+                  type: object
+                  properties:
+                    verbose:
+                      title: Verbose
+                      description: verbose mode (-vvv for more, -vvvv to enable connection
+                        debugging)
+                      type: integer
+                      maximum: 4
                     private_key:
                       title: Private key
                       description: use this file to authenticate the connection
@@ -13241,55 +13185,93 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    scp_extra_args:
-                      title: Scp extra args
-                      description: specify extra arguments to pass to scp only (e.g.
-                        -l)
-                      type: string
-                    sftp_extra_args:
-                      title: Sftp extra args
-                      description: specify extra arguments to pass to sftp only (e.g.
-                        -f, -l)
+                    user:
+                      title: User
+                      description: connect as this user (default=None)
                       type: string
-                    skip_tags:
-                      title: Skip tags
-                      description: only run plays and tasks whose tags do not match
-                        these values
+                    connection:
+                      title: Connection
+                      description: connection type to use (default=smart)
                       type: string
+                    timeout:
+                      title: Timeout
+                      description: override the connection timeout in seconds (default=10)
+                      type: integer
                     ssh_common_args:
                       title: Ssh common args
                       description: specify common arguments to pass to sftp/scp/ssh
                         (e.g. ProxyCommand)
                       type: string
+                    sftp_extra_args:
+                      title: Sftp extra args
+                      description: specify extra arguments to pass to sftp only (e.g.
+                        -f, -l)
+                      type: string
+                    scp_extra_args:
+                      title: Scp extra args
+                      description: specify extra arguments to pass to scp only (e.g.
+                        -l)
+                      type: string
                     ssh_extra_args:
                       title: Ssh extra args
                       description: specify extra arguments to pass to ssh only (e.g.
                         -R)
                       type: string
-                    start_at_task:
-                      title: Start at task
-                      description: start the playbook at the task matching this name
+                    force_handlers:
+                      title: Force handlers
+                      description: run handlers even if a task fails
+                      type: boolean
+                    flush_cache:
+                      title: Flush cache
+                      description: clear the fact cache for every host in inventory
+                      type: boolean
+                    become:
+                      title: Become
+                      description: run operations with become (does not imply password
+                        prompting)
+                      type: boolean
+                    become_method:
+                      title: Become method
+                      description: privilege escalation method to use (default=sudo),
+                        use `ansible-doc -t become -l` to list valid choices.
                       type: string
-                    step:
-                      title: Step
-                      description: 'one-step-at-a-time: confirm each task before running'
+                    tags:
+                      title: Tags
+                      description: only run plays and tasks tagged with these values
+                      type: string
+                    skip_tags:
+                      title: Skip tags
+                      description: only run plays and tasks whose tags do not match
+                        these values
+                      type: string
+                    check:
+                      title: Check
+                      description: don't make any changes; instead, try to predict
+                        some of the changes that may occur
                       type: boolean
                     syntax_check:
                       title: Syntax check
                       description: perform a syntax check on the playbook, but do
                         not execute it
                       type: boolean
-                    tags:
-                      title: Tags
-                      description: only run plays and tasks tagged with these values
+                    diff:
+                      title: Diff
+                      description: when changing (small) files and templates, show
+                        the differences in those files; works great with --check
+                      type: boolean
+                    list_hosts:
+                      title: List hosts
+                      description: outputs a list of matching hosts; does not execute
+                        anything else
+                      type: boolean
+                    limit:
+                      title: Limit
+                      description: further limit selected hosts to an additional pattern
                       type: string
-                    timeout:
-                      title: Timeout
-                      description: override the connection timeout in seconds (default=10)
-                      type: integer
-                    user:
-                      title: User
-                      description: connect as this user (default=None)
+                    extra_vars:
+                      title: Extra vars
+                      description: set additional variables as key=value or YAML/JSON,
+                        if filename prepend with @
                       type: string
                     vault_password_file:
                       title: Vault password file
@@ -13299,12 +13281,30 @@ definitions:
                       x-options:
                         media_types:
                           - '*/*'
-                    verbose:
-                      title: Verbose
-                      description: verbose mode (-vvv for more, -vvvv to enable connection
-                        debugging)
+                    forks:
+                      title: Forks
+                      description: specify number of parallel processes to use (default=5)
                       type: integer
-                      maximum: 4
+                    list_tasks:
+                      title: List tasks
+                      description: list all tasks that would be executed
+                      type: boolean
+                    list_tags:
+                      title: List tags
+                      description: list all available tags
+                      type: boolean
+                    step:
+                      title: Step
+                      description: 'one-step-at-a-time: confirm each task before running'
+                      type: boolean
+                    start_at_task:
+                      title: Start at task
+                      description: start the playbook at the task matching this name
+                      type: string
+                    args:
+                      title: Args
+                      description: Playbook(s)
+                      type: string
     x-properties-groups:
       '':
         - id
@@ -13794,63 +13794,63 @@ definitions:
           types:
             MODULE:
               enum:
-                - args
-                - background
+                - verbose
                 - become
                 - become_method
-                - check
-                - connection
-                - diff
-                - extra_vars
-                - forks
-                - limit
                 - list_hosts
-                - one_line
-                - playbook_dir
+                - limit
                 - poll
+                - background
+                - one_line
+                - tree
                 - private_key
-                - scp_extra_args
-                - sftp_extra_args
+                - user
+                - connection
+                - timeout
                 - ssh_common_args
+                - sftp_extra_args
+                - scp_extra_args
                 - ssh_extra_args
+                - check
                 - syntax_check
-                - timeout
-                - tree
-                - user
+                - diff
+                - extra_vars
                 - vault_password_file
-                - verbose
+                - forks
+                - playbook_dir
+                - args
                 - group
               type: string
             PLAYBOOK:
               enum:
-                - args
+                - verbose
+                - private_key
+                - user
+                - connection
+                - timeout
+                - ssh_common_args
+                - sftp_extra_args
+                - scp_extra_args
+                - ssh_extra_args
+                - force_handlers
+                - flush_cache
                 - become
                 - become_method
+                - tags
+                - skip_tags
                 - check
-                - connection
+                - syntax_check
                 - diff
+                - list_hosts
+                - limit
                 - extra_vars
-                - flush_cache
-                - force_handlers
+                - vault_password_file
                 - forks
-                - limit
-                - list_hosts
-                - list_tags
                 - list_tasks
-                - private_key
-                - scp_extra_args
-                - sftp_extra_args
-                - skip_tags
-                - ssh_common_args
-                - ssh_extra_args
-                - start_at_task
+                - list_tags
                 - step
-                - syntax_check
-                - tags
-                - timeout
-                - user
-                - vault_password_file
-                - verbose
+                - start_at_task
+                - args
               type: string
       value:
         format: dynamic
diff --git a/polemarch/api/v2/permissions.py b/polemarch/api/v2/permissions.py
index 00900562..4f886c75 100644
--- a/polemarch/api/v2/permissions.py
+++ b/polemarch/api/v2/permissions.py
@@ -1,21 +1,19 @@
 from rest_framework import permissions
+from vstutils.utils import lazy_translate as __
 
 
-class ModelPermission(permissions.IsAuthenticated):
+class CreateTeamPermission(permissions.IsAuthenticated):
     def has_permission(self, request, view):
-        # pylint: disable=useless-super-delegation
-        return super().has_permission(request, view)
-
-    def get_user_permission(self, request, view, obj):  # nocv
-        # pylint: disable=unused-argument
-        if hasattr(obj, 'owner') and obj.owner == request.user:
+        if request.method == 'GET':
             return True
-        return False
+        return request.user.is_superuser or request.user.is_staff
+
+
+class SetOwnerPermission(permissions.IsAuthenticated):
+    message = __('Only owner can change owner.')
 
     def has_object_permission(self, request, view, obj):
-        if request.user.is_staff:
-            return True
-        return self.get_user_permission(request, view, obj)  # nocv
+        return request.user.is_superuser or obj.owner == request.user
 
 
 class InventoryItemsPermission(permissions.IsAuthenticated):
diff --git a/polemarch/api/v2/serializers.py b/polemarch/api/v2/serializers.py
index 02c69901..c4f4a8c7 100644
--- a/polemarch/api/v2/serializers.py
+++ b/polemarch/api/v2/serializers.py
@@ -10,7 +10,7 @@
 
 from django.contrib.auth import get_user_model
 from django.db import transaction
-from rest_framework import serializers, exceptions
+from rest_framework import serializers
 
 from vstutils.api import auth as vst_auth
 from vstutils.api import serializers as vst_serializers, fields as vst_fields
@@ -76,11 +76,6 @@ def to_internal_value(self, data):
         inventory = super().to_internal_value(data)
         try:
             inventory = models.Inventory.objects.get(id=int(inventory))
-            user = self.context['request'].user
-            if not inventory.acl_handler.viewable_by(user):
-                raise exceptions.PermissionDenied(
-                    "You don't have permission to inventory."
-                )  # noce
         except (ValueError, KeyError):
             if ',' not in inventory:
                 path_validator(inventory)
@@ -109,30 +104,13 @@ class ExecuteResponseSerializer(ActionResponseSerializer):
     executor = serializers.IntegerField(default=None, allow_null=True)
 
 
-class SetOwnerSerializer(DataSerializer):
-    perms_msg = 'Permission denied. Only owner can change owner.'
-    user_id = vst_fields.FkField(required=True, select='User',
-                                 label='New owner',
-                                 autocomplete_represent='username')
-
-    def update(self, instance, validated_data):
-        if not self.instance.acl_handler.owned_by(self.current_user()):  # noce
-            raise exceptions.PermissionDenied(self.perms_msg)
-        user = self.get_user(validated_data)
-        self.instance.acl_handler.set_owner(user)
-        return user
-
-    def get_user(self, validated_data: dict):
-        return User.objects.get(**validated_data)
-
-    def current_user(self) -> User:
-        return self.context['request'].user
-
-    def to_representation(self, value: User):  # pylint: disable=arguments-renamed
-        return dict(user_id=value.pk)
-
-    def to_internal_value(self, data: dict):
-        return dict(pk=data['user_id'])
+class SetOwnerSerializer(BaseSerializer):
+    user_id = vst_fields.FkField(
+        required=True,
+        select='User',
+        label='New owner',
+        autocomplete_represent='username'
+    )
 
 
 class CreateUserSerializer(vst_auth.CreateUserSerializer):  # noee
@@ -860,7 +838,7 @@ class DashboardJobsSerializer(DataSerializer):
     year = YearDashboardJobSerializer(many=True)
 
 
-class DashboardStatisticSerializer(DataSerializer):
+class DashboardStatisticsSerializer(DataSerializer):
     projects = serializers.IntegerField()
     templates = serializers.IntegerField()
     inventories = serializers.IntegerField()
diff --git a/polemarch/api/v2/views.py b/polemarch/api/v2/views.py
index c8f8e450..1ebd0479 100644
--- a/polemarch/api/v2/views.py
+++ b/polemarch/api/v2/views.py
@@ -1,5 +1,4 @@
 # pylint: disable=unused-argument,protected-access,too-many-ancestors
-from collections import OrderedDict
 
 from django.db import transaction
 from django.http.response import HttpResponse
@@ -14,10 +13,16 @@
 from vstutils.api.responses import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT
 
 from . import filters
-from .permissions import InventoryItemsPermission, CreateUsersPermission
+from .permissions import (
+    InventoryItemsPermission,
+    CreateUsersPermission,
+    SetOwnerPermission,
+    CreateTeamPermission,
+)
 from . import serializers as sers
 from ..v3 import serializers as sers3
 from ...main import utils
+from ...main.models.base import ACLModel
 
 yes = True
 no = False
@@ -55,18 +60,22 @@ def copy_instance(self, instance):
 class OwnedView(base.ModelViewSet, base.CopyMixin):
     POST_WHITE_LIST = []
 
-    @deco.action(methods=["post"], detail=True, serializer_class=sers.SetOwnerSerializer)
+    @deco.action(
+        methods=["post"],
+        detail=True,
+        serializer_class=sers.SetOwnerSerializer,
+        permission_classes=(SetOwnerPermission,)
+    )
     def set_owner(self, request, **kwargs):
         # pylint: disable=unused-argument
         """
         Change instance owner.
         """
-        serializer = sers.SetOwnerSerializer(
-            self.get_object(), data=request.data, context=self.get_serializer_context()
-        )
+        serializer = self.get_serializer(data=request.data)
+        instance: ACLModel = self.get_object()
         serializer.is_valid(raise_exception=True)
-        serializer.save()
-        return HTTP_201_CREATED(serializer.data)
+        instance.set_owner(serializer.validated_data['user_id'])
+        return HTTP_201_CREATED(serializer.validated_data)
 
 
 class __VarsViewSet(base.ModelViewSet):
@@ -240,6 +249,7 @@ class TeamViewSet(OwnedView):
     serializer_class_one = sers.OneTeamSerializer
     filterset_class = filters.TeamFilter
     copy_related = ['users']
+    permission_classes = list(OwnedView.permission_classes) + [CreateTeamPermission]
 
 
 class __HistoryLineViewSet(base.ReadOnlyModelViewSet):
@@ -760,36 +770,44 @@ class HookViewSet(base.ModelViewSet):
 
 
 @method_decorator(name='list', decorator=swagger_auto_schema(
-    operation_description='Dashboard statistic.',
-    responses={status.HTTP_200_OK: sers.DashboardStatisticSerializer(), }
+    operation_description='Dashboard statistics.',
+    responses={status.HTTP_200_OK: sers.DashboardStatisticsSerializer()}
 ))
-class StatisticViewSet(base.ListNonModelViewSet):
+class StatisticsViewSet(base.ListNonModelViewSet):
     base_name = "stats"
 
-    def _get_by_user(self, model):
-        user = self.request.user
-        filter_models = (sers.User,)
-        if model not in filter_models:
-            return model.objects.all().user_filter(user)
-        return model.objects.all()
+    def _get_projects_count(self):  # noee
+        return sers.models.Project.objects.count()
 
-    def _get_history_stats(self, request):
-        qs = sers.models.History.objects.all()
-        qs = qs.user_filter(self.request.user)
-        return qs.stats(int(request.query_params.get("last", "14")))
+    def _get_templates_count(self):  # noee
+        return sers.models.Template.objects.count()
 
-    def _get_by_user_projects(self, model):
-        return model.objects.filter(project__in=self._get_by_user(sers.models.Project).values('id'))
+    def _get_inventories_count(self):  # noee
+        return sers.models.Inventory.objects.count()
 
-    def list(self, request, *args, **kwargs):
-        # pylint: disable=unused-argument
-        stats = OrderedDict()
-        stats['projects'] = self._get_by_user(sers.models.Project).count()
-        stats['templates'] = self._get_by_user_projects(sers.models.Template).count()
-        stats['inventories'] = self._get_by_user(sers.models.Inventory).count()
-        stats['groups'] = self._get_by_user(sers.models.Group).count()
-        stats['hosts'] = self._get_by_user(sers.models.Host).count()
-        stats['teams'] = self._get_by_user(sers.models.UserGroup).count()
-        stats['users'] = self._get_by_user(sers.User).count()
-        stats['jobs'] = self._get_history_stats(request)
-        return HTTP_200_OK(stats)
+    def _get_groups_count(self):  # noee
+        return sers.models.Group.objects.count()
+
+    def _get_hosts_count(self):  # noee
+        return sers.models.Host.objects.count()
+
+    def _get_teams_count(self):  # noee
+        return sers.models.UserGroup.objects.count()
+
+    def _get_users_count(self):  # noee
+        return sers.User.objects.count()
+
+    def _get_history_stats(self):  # noee
+        return sers.models.History.objects.stats(int(self.request.query_params.get("last", "14")))
+
+    def list(self, *args, **kwargs):
+        return HTTP_200_OK({
+            'projects': self._get_projects_count(),
+            'templates': self._get_templates_count(),
+            'inventories': self._get_inventories_count(),
+            'groups': self._get_groups_count(),
+            'hosts': self._get_hosts_count(),
+            'teams': self._get_teams_count(),
+            'users': self._get_users_count(),
+            'jobs': self._get_history_stats(),
+        })
diff --git a/polemarch/api/v3/views.py b/polemarch/api/v3/views.py
index f88fd690..d7cc4295 100644
--- a/polemarch/api/v3/views.py
+++ b/polemarch/api/v3/views.py
@@ -6,6 +6,7 @@
 from vstutils.api.responses import HTTP_201_CREATED
 from vstutils.utils import create_view, translate as _
 
+from ...main.models.utils import ensure_inventory_is_from_project
 from ...main.models import TemplateOption, Group, Project
 from ...main.executions import PLUGIN_HANDLERS
 from ..v2.filters import variables_filter, vars_help
@@ -128,6 +129,7 @@ def action(self, request, plugin=plugin, *args, **kwargs):
                 project: Project = self.get_object()
 
                 data = serializer.validated_data
+                ensure_inventory_is_from_project(data.get('inventory'), project)
                 history_id = project.execute(plugin, executor=request.user, execute_args=data)
 
                 response_serializer = ExecuteResponseSerializer(instance={
diff --git a/polemarch/main/acl/__init__.py b/polemarch/main/acl/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/polemarch/main/acl/handlers.py b/polemarch/main/acl/handlers.py
deleted file mode 100644
index 4300548a..00000000
--- a/polemarch/main/acl/handlers.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from typing import Optional, Type
-from django.db.models import Model
-
-
-class Default:
-    # pylint: disable=unused-argument
-    qs_methods = []
-
-    def __init__(self, model: Optional[Type[Model]] = None, instance=None):
-        self.instance = instance
-        self.model = model
-
-    def set_owner(self, user):
-        '''
-        Set object owner.
-
-        :param user:
-        :return:
-        '''
-        self.instance.owner = user
-        self.instance.save()
-
-    def owned_by(self, user):
-        return user.is_staff or (getattr(self.instance, 'owner', None) == user)
-
-    def manageable_by(self, user):  # nocv
-        return True
-
-    def editable_by(self, user):  # nocv
-        return True
-
-    def viewable_by(self, user):
-        return True
-
-    def user_filter(self, qs, user, role=None):
-        return qs
-
-    def qs_create(self, original_method, **kwargs):
-        return original_method(**kwargs)
diff --git a/polemarch/main/constants.py b/polemarch/main/constants.py
index ff5f9834..593f3f54 100644
--- a/polemarch/main/constants.py
+++ b/polemarch/main/constants.py
@@ -9,6 +9,11 @@
 TEMPLATE_KINDS_MAP = {'PLAYBOOK': 'Task', 'MODULE': 'Module'}
 
 
+class MemberType(BaseEnum):
+    USER = BaseEnum.LOWER
+    TEAM = BaseEnum.LOWER
+
+
 class BaseVariablesEnum(BaseEnum):
     @classmethod
     @lru_cache()
diff --git a/polemarch/main/models/__init__.py b/polemarch/main/models/__init__.py
index 11254efd..c5e10abb 100644
--- a/polemarch/main/models/__init__.py
+++ b/polemarch/main/models/__init__.py
@@ -26,6 +26,7 @@
 from ..validators import RegexValidator, validate_hostname, path_validator
 from ..exceptions import UnknownTypeException, Conflict
 from ..utils import CmdExecutor
+from .utils import ensure_inventory_is_from_project
 from ...main.constants import ProjectVariablesEnum, ANSIBLE_REFERENCE
 
 
@@ -149,12 +150,10 @@ def check_circular_deps(instance: Group, action: Text, pk_set: Iterable, *args,
 
 
 @receiver(signals.pre_save, sender=PeriodicTask)
-def validate_types(instance: PeriodicTask, **kwargs) -> None:
+def validate_inventory(instance: PeriodicTask, **kwargs) -> None:
     if 'loaddata' in sys.argv or kwargs.get('raw', False):  # nocv
         return
-    if (instance.kind not in instance.kinds) or (instance.type not in instance.types):
-        # Deprecated, because moved to serializers
-        raise UnknownTypeException(instance.kind, "Unknown kind {}.")  # nocv
+    ensure_inventory_is_from_project(instance.inventory, instance.project)
 
 
 @receiver(signals.pre_save, sender=PeriodicTask)
@@ -200,6 +199,7 @@ def validate_template_keys(instance: Template, **kwargs) -> None:
 def validate_template_args(instance: Template, **kwargs) -> None:
     if 'loaddata' in sys.argv or kwargs.get('raw', False):  # nocv
         return
+    ensure_inventory_is_from_project(instance.inventory, instance.project)
     if instance.kind in ["Host", "Group"]:
         return  # nocv
     ansible_args = dict(instance.data['vars'])
diff --git a/polemarch/main/models/base.py b/polemarch/main/models/base.py
index f1affeb6..f5833b46 100644
--- a/polemarch/main/models/base.py
+++ b/polemarch/main/models/base.py
@@ -1,82 +1,16 @@
 # pylint: disable=no-name-in-module
 from __future__ import unicode_literals
-from typing import Callable, Any
+from typing import Any
 from django.db import models
-from django.conf import settings
 from django.contrib.auth import get_user_model
-from django.utils.module_loading import import_string
-from vstutils.utils import classproperty
-from vstutils.models import BQuerySet as _BQSet, BaseModel as _BM, Manager as _BManager
+from vstutils.models import BModel
 
 
-def first_staff_user() -> int:
-    return get_user_model().objects.filter(is_staff=True).first().id
-
-
-class BQuerySet(_BQSet):
-    use_for_related_fields = True
-
-    def __decorator(self, func: Callable) -> Callable:  # noce
-        def wrapper(*args, **kwargs):
-            return func(self, *args, **kwargs)
-
-        return wrapper
-
-    def __getattribute__(self, item: str) -> Any:
-        try:
-            return super().__getattribute__(item)
-        except:
-            model = super().__getattribute__("model")
-            if model and item in model.acl_handler.qs_methods:  # noce
-                return self.__decorator(getattr(model.acl_handler, "qs_{}".format(item)))
-            raise
+User = get_user_model()
 
-    def create(self, **kwargs) -> _BM:
-        return self.model.acl_handler.qs_create(super().create, **kwargs)
 
-    def user_filter(self, user, *args, **kwargs) -> _BQSet:
-        # pylint: disable=unused-argument
-        return self.model.acl_handler.user_filter(self, user, *args, **kwargs)
-
-
-class Manager(_BManager.from_queryset(BQuerySet)):
-    '''
-    Polemarch model manager.
-    '''
-
-
-class BaseModel(_BM):
-    # pylint: disable=no-member
-    objects = BQuerySet.as_manager()
-
-    class Meta:
-        abstract = True
-
-    @staticmethod
-    def get_acl(cls, obj=None) -> Any:
-        # pylint: disable=bad-staticmethod-argument
-        handler_class_name = settings.ACL['MODEL_HANDLERS'].get(
-            cls.__name__, settings.ACL['MODEL_HANDLERS'].get("Default")
-        )
-        return import_string(handler_class_name)(cls, obj)
-
-    @classproperty
-    def acl_handler(self) -> Any:
-        if isinstance(self, BaseModel):
-            classObj = self.__class__
-            return classObj.get_acl(classObj, self)
-        return self.get_acl(self)
-
-
-class BModel(BaseModel):
-    id = models.AutoField(primary_key=True, max_length=20)
-    hidden = models.BooleanField(default=False)
-
-    class Meta:
-        abstract = True
-
-    def __unicode__(self):
-        return "<{}>".format(self.id)  # nocv
+def first_staff_user() -> int:
+    return User.objects.filter(is_staff=True).first().id
 
 
 class BGroupedModel(BModel):
@@ -115,7 +49,7 @@ class ACLModel(BModel):
     notes = models.TextField(default="")
     acl = models.ManyToManyField("main.ACLPermission", blank=True)
     owner = models.ForeignKey(
-        get_user_model(),
+        User,
         on_delete=models.SET_DEFAULT,
         default=first_staff_user,
         related_name="polemarch_%(class)s_set"
@@ -123,3 +57,7 @@ class ACLModel(BModel):
 
     class Meta:
         abstract = True
+
+    def set_owner(self, new_owner_id):
+        self.owner = User.objects.get(id=new_owner_id)
+        self.save(update_fields=('owner',))
diff --git a/polemarch/main/models/hooks.py b/polemarch/main/models/hooks.py
index 35f6e9ac..76a025f9 100644
--- a/polemarch/main/models/hooks.py
+++ b/polemarch/main/models/hooks.py
@@ -3,8 +3,9 @@
 import logging
 import collections
 import uuid
+from django.db import models
 from vstutils.utils import raise_context, ModelHandlers
-from .base import BModel, BQuerySet, models
+from vstutils.models import BModel, BQuerySet
 
 
 logger = logging.getLogger('polemarch')
diff --git a/polemarch/main/models/projects.py b/polemarch/main/models/projects.py
index 5fbe1682..b60b265b 100644
--- a/polemarch/main/models/projects.py
+++ b/polemarch/main/models/projects.py
@@ -15,6 +15,7 @@
 from vstutils.utils import ModelHandlers, raise_context_decorator_with_default, classproperty
 # pylint: disable=no-name-in-module
 from vstutils import custom_model
+from vstutils.models import BQuerySet, BModel
 from yaml import load
 
 try:
@@ -26,7 +27,7 @@
 from ..validators import path_validator
 from .vars import AbstractModel, AbstractVarsQuerySet, models
 from ..exceptions import PMException
-from .base import ManyToManyFieldACL, BQuerySet, BModel
+from .base import ManyToManyFieldACL
 from .hooks import Hook
 from ..utils import AnsibleModules, AnsibleConfigParser, SubCacheInterface
 
@@ -265,7 +266,6 @@ def hook(self, when, msg) -> None:
 
     def execute(self, plugin: str, execute_args, **kwargs) -> HISTORY_ID:
         from ..executions import PLUGIN_HANDLERS  # pylint: disable=import-outside-toplevel
-
         return PLUGIN_HANDLERS.execute(
             plugin,
             self,
diff --git a/polemarch/main/models/tasks.py b/polemarch/main/models/tasks.py
index 794db313..79fe75c5 100644
--- a/polemarch/main/models/tasks.py
+++ b/polemarch/main/models/tasks.py
@@ -11,19 +11,19 @@
 from celery.schedules import crontab
 from django.core.exceptions import ValidationError
 from django.db.utils import IntegrityError
-from django.db import transaction
-from django.db.models import Q
+from django.db import transaction, models
 from django.utils import timezone
 from django.utils.text import slugify
 from django.contrib.auth import get_user_model
 from django.db.models import functions as dbfunc, Count
 from django.utils.timezone import now
 
+from vstutils.models import BaseModel, BModel, BQuerySet
 from vstutils.custom_model import ListModel, CustomQuerySet
 from vstutils.utils import translate as _
 from . import Inventory
 from ..exceptions import DataNotReady, NotApplicable
-from .base import ForeignKeyACL, BModel, ACLModel, BQuerySet, models, BaseModel
+from .base import ForeignKeyACL, ACLModel
 from .vars import AbstractModel, AbstractVarsQuerySet
 from .projects import Project, HISTORY_ID
 from ..constants import CYPHER, HiddenArgumentsEnum
@@ -34,7 +34,6 @@
 User = get_user_model()
 
 
-# Block of real models
 class Template(ACLModel):
     name          = models.CharField(max_length=512)
     kind          = models.CharField(max_length=32)
@@ -499,7 +498,7 @@ def facts(self) -> Dict:
         data = self.get_raw(
             original=False,
             excludes=(
-                Q(line__contains="No config file") | Q(line__contains="as config file"),
+                models.Q(line__contains="No config file") | models.Q(line__contains="as config file"),
             )
         )
         regex = (
diff --git a/polemarch/main/models/users.py b/polemarch/main/models/users.py
index 7df83dac..099f3147 100644
--- a/polemarch/main/models/users.py
+++ b/polemarch/main/models/users.py
@@ -5,18 +5,44 @@
 
 from django.contrib.auth.models import Group as BaseGroup
 from django.contrib.auth import get_user_model
-from .base import models, BModel, ACLModel, BQuerySet
+from django.db import models
+from vstutils.models import BModel, BQuerySet
+from .base import ACLModel
+from ..constants import MemberType
 
 
 logger = logging.getLogger("polemarch")
 
+User = get_user_model()
+
+
+class UserGroup(BaseGroup, ACLModel):
+    objects = BQuerySet.as_manager()
+    parent = models.OneToOneField(BaseGroup, on_delete=models.CASCADE, parent_link=True)
+    users = BaseGroup.user_set
+
+
+class ACLPermissionQuerySet(BQuerySet):
+    def filter_by_user(self, user):  # noce
+        return self.filter(models.Q(user=user) | models.Q(uagroup__user=user))
+
 
 class ACLPermission(BModel):
-    role    = models.CharField(max_length=10)
-    uagroup = models.ForeignKey('main.UserGroup',
-                                on_delete=models.CASCADE, blank=True, null=True)
-    user    = models.ForeignKey(get_user_model(),
-                                on_delete=models.CASCADE, blank=True, null=True)
+    objects = ACLPermissionQuerySet.as_manager()
+
+    role = models.CharField(max_length=10)
+    uagroup = models.ForeignKey(
+        UserGroup,
+        on_delete=models.CASCADE,
+        blank=True,
+        null=True,
+    )
+    user = models.ForeignKey(
+        User,
+        on_delete=models.CASCADE,
+        blank=True,
+        null=True,
+    )
 
     @property
     def member(self) -> int:  # noce
@@ -25,22 +51,8 @@ def member(self) -> int:  # noce
             return self.user.id
         return self.uagroup.id
 
-    @member.setter
-    def member(self, value) -> None:  # nocv
-        pass
-
     @property
     def member_type(self) -> Text:  # noce
         if self.user is not None:
-            return "user"
-        return "team"
-
-    @member_type.setter
-    def member_type(self, value) -> None:  # nocv
-        pass
-
-
-class UserGroup(BaseGroup, ACLModel):
-    objects = BQuerySet.as_manager()
-    parent = models.OneToOneField(BaseGroup, on_delete=models.CASCADE, parent_link=True)
-    users = BaseGroup.user_set
+            return MemberType.USER
+        return MemberType.TEAM
diff --git a/polemarch/main/models/utils.py b/polemarch/main/models/utils.py
index 5eb8ff04..bd267329 100644
--- a/polemarch/main/models/utils.py
+++ b/polemarch/main/models/utils.py
@@ -14,6 +14,7 @@
 from subprocess import Popen
 from django.apps import apps
 from django.utils import timezone
+from rest_framework.exceptions import ValidationError
 from vstutils.utils import KVExchanger
 
 from .hosts import Inventory
@@ -25,6 +26,18 @@
 logger = logging.getLogger("polemarch")
 
 
+def ensure_inventory_is_from_project(inventory, project):  # pylint: disable=invalid-name
+    if isinstance(inventory, Inventory):
+        inventory_id = inventory.id
+    elif isinstance(inventory, int):
+        inventory_id = inventory
+    else:
+        return
+
+    if not project.inventories.filter(id=inventory_id).exists():
+        raise ValidationError('No Inventory matches the given query.')
+
+
 # Classes and methods for support
 class DummyHistory:
     # pylint: disable=unused-argument
diff --git a/polemarch/main/models/vars.py b/polemarch/main/models/vars.py
index d28a9c49..9b3f28e4 100644
--- a/polemarch/main/models/vars.py
+++ b/polemarch/main/models/vars.py
@@ -6,13 +6,14 @@
 
 from functools import reduce
 from collections import OrderedDict
-from django.db import transaction
+from django.db import transaction, models
 from django.db.models import Case, When, Value
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
 from vstutils.utils import tmp_file
+from vstutils.models import BQuerySet, BModel
 from vstutils.api.decorators import cache_method_result
-from .base import ACLModel, BQuerySet, BModel, models
+from .base import ACLModel
 from ..constants import CYPHER, InventoryVariablesEnum
 
 logger = logging.getLogger("polemarch")
diff --git a/polemarch/main/settings.py b/polemarch/main/settings.py
index 79445db7..f7512171 100644
--- a/polemarch/main/settings.py
+++ b/polemarch/main/settings.py
@@ -34,10 +34,6 @@
 # API settings
 VST_API_VERSION = 'v3'
 
-REST_FRAMEWORK["DEFAULT_PERMISSION_CLASSES"] = [
-    "{}.api.v2.permissions.ModelPermission".format(VST_PROJECT_LIB_NAME),
-]
-
 API_URL = VST_API_URL
 DEFAULT_API_URL = "/{}/{}".format(API_URL, VST_API_VERSION)
 API = {
@@ -52,7 +48,7 @@
         team={'view': '{}.api.v2.views.TeamViewSet'.format(VST_PROJECT_LIB_NAME)},
         token={'view': '{}.api.v2.views.TokenView'.format(VST_PROJECT_LIB_NAME), 'type': 'view'},
         hook={'view': '{}.api.v2.views.HookViewSet'.format(VST_PROJECT_LIB_NAME)},
-        stats={'view': '{}.api.v2.views.StatisticViewSet'.format(VST_PROJECT_LIB_NAME), 'op_types': ['get']}
+        stats={'view': '{}.api.v2.views.StatisticsViewSet'.format(VST_PROJECT_LIB_NAME), 'op_types': ['get']}
     )
 }
 API[VST_API_VERSION] = {
@@ -274,12 +270,6 @@ class PluginOptionsSection(PluginSection):
 
 CLONE_RETRY = rpc.getint('clone_retry_count', fallback=5)
 
-# ACL settings
-ACL = {
-    "MODEL_HANDLERS": {
-        "Default": "{}.main.acl.handlers.Default".format(VST_PROJECT_LIB_NAME)
-    }
-}
 
 # Outgoing hooks settings
 HOOKS = {
diff --git a/polemarch/translations/en.py b/polemarch/translations/en.py
index fb769716..1b89050e 100644
--- a/polemarch/translations/en.py
+++ b/polemarch/translations/en.py
@@ -14,4 +14,7 @@
     'hosts counter': 'hosts | host | hosts',
     'users counter': 'users | user | users',
     'all_tasks': 'all tasks',
+
+    'Vars': 'Variables',
+    'Acl': 'ACL'
 }
diff --git a/polemarch/translations/ru.py b/polemarch/translations/ru.py
index 4b9c5f22..f8052750 100644
--- a/polemarch/translations/ru.py
+++ b/polemarch/translations/ru.py
@@ -51,6 +51,8 @@
     'Directory with playbooks': 'Каталог с плейбуками',
     'Information': 'Информация',
     'Arguments': 'Аргументы',
+    'Vars': 'Переменные',
+    'Data': 'Данные',
     'Task type': 'Тип задачи',
     'Interval type': 'Типа интервала',
     'Contains groups': 'Содержит группы',
diff --git a/requirements.txt b/requirements.txt
index 8cf258ed..fd9ce705 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
 # Main
-vstutils[rpc,doc,prod]~=5.2.2
+vstutils[rpc,doc,prod]~=5.2.5
 docutils~=0.16.0
 markdown2~=2.4.0
 
diff --git a/setup.py b/setup.py
index d56faca3..2694e5a4 100644
--- a/setup.py
+++ b/setup.py
@@ -372,7 +372,11 @@ def make_setup(**opts):
     webpack_path = os.path.join(os.getcwd(), 'webpack.config.js')
     if os.path.exists(webpack_path) and is_build and os.environ.get('DONT_YARN', "") != 'true':
         try:
-            subprocess.check_call(['yarn', 'install', '--pure-lockfile'], stdout=sys.stdout, stderr=sys.stderr)
+            subprocess.check_call(
+                ['yarn', 'install', '--pure-lockfile', '--mutex network'],
+                stdout=sys.stdout,
+                stderr=sys.stderr
+            )
             subprocess.check_call(['yarn', 'devBuild' if is_develop else 'build'], stdout=sys.stdout, stderr=sys.stderr)
         except Exception as err:
             raise errors.CompileError(str(err))
diff --git a/tests.py b/tests.py
index d7befd91..1e9c68c4 100644
--- a/tests.py
+++ b/tests.py
@@ -316,6 +316,7 @@ def create_execution_template_bulk_data(self, project_id=None, inventory=None, *
 class ProjectTestCase(BaseProjectTestCase):
     def test_set_owner(self):
         user = self._create_user(is_super_user=False, is_staff=True)
+        user2 = self._create_user(is_super_user=False, is_staff=True)
         results = self.bulk([
             {
                 'method': 'post',
@@ -327,16 +328,59 @@ def test_set_owner(self):
                 'path': ['project', self.project.id, 'set_owner'],
                 'data': {'user_id': 146}
             },
-            {'method': 'get', 'path': ['project', self.project.id]}
+            {'method': 'get', 'path': ['project', self.project.id]},
         ])
         self.assertEqual(results[0]['status'], 201)
         self.assertEqual(results[1]['status'], 400)
         self.assertEqual(results[2]['status'], 200)
         self.assertEqual(results[2]['data']['owner']['id'], user.id)
 
+        with self.user_as(self, user2):
+            results = self.bulk([
+                {'method': 'post', 'path': ['project', self.project.id, 'set_owner'], 'data': {'user_id': user.id}},
+            ])
+        self.assertEqual(results[0]['status'], 403)
+        self.assertEqual(results[0]['data']['detail'], 'Only owner can change owner.')
+
 
 @own_projects_dir
 class InventoryTestCase(BaseProjectTestCase):
+    def test_fk_inventory_usage(self):
+        results = self.bulk_transactional([
+            {'method': 'post', 'path': 'inventory', 'name': 'unreachable'},
+            self.create_execution_template_bulk_data(),
+            self.create_periodic_task_bulk_data(),
+        ])
+        inventory_id = results[0]['data']['id']
+        template_id = results[1]['data']['id']
+        periodic_task_id = results[2]['data']['id']
+
+        results = self.bulk([
+            # [0]
+            self.execute_module_bulk_data(inventory=inventory_id),
+            # [1]
+            self.create_execution_template_bulk_data(inventory=inventory_id),
+            # [2]
+            self.create_periodic_task_bulk_data(inventory=inventory_id),
+            # [3]
+            {
+                'method': 'patch',
+                'path': ['project', self.project.id, 'execution_templates', template_id],
+                'data': {'inventory': inventory_id},
+            },
+            # [4]
+            {
+                'method': 'patch',
+                'path': ['project', self.project.id, 'periodic_task', periodic_task_id],
+                'data': {'inventory': inventory_id},
+            },
+        ])
+        self.assertEqual(results[0]['status'], 400)
+        self.assertEqual(results[0]['data'], ['No Inventory matches the given query.'])
+        for idx in range(1, 5):
+            self.assertEqual(results[idx]['status'], 400)
+            self.assertEqual(results[idx]['data'], ['No Inventory matches the given query.'])
+
     def test_import_inventory(self):
         def check_import(file_import=False):
             inventory = (TEST_DATA_DIR / 'inventory.yml').read_text()
@@ -2778,6 +2822,7 @@ def test_history_actions(self):
         self.assertEqual(results[4]['status'], 200)
         self.assertEqual(results[4]['data'], {'detail': f'Task canceled: {self.project.id}'})
 
+    @skipIf(settings.VST_PROJECT_LIB_NAME != 'polemarch', 'Stats may vary')
     def test_stats(self):
         def generate_history(status="OK"):
             project = self.get_model_class('main.Project').objects.create(name="Stats", repository='')
diff --git a/yarn.lock b/yarn.lock
index 0957f7e7..45434b03 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -17,26 +17,31 @@
   dependencies:
     "@babel/highlight" "^7.18.6"
 
-"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.0", "@babel/compat-data@^7.20.1":
+"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1":
   version "7.20.1"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30"
   integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==
 
+"@babel/compat-data@^7.20.0":
+  version "7.20.5"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.5.tgz#86f172690b093373a933223b4745deeb6049e733"
+  integrity sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==
+
 "@babel/core@^7.16.7":
-  version "7.20.2"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.2.tgz#8dc9b1620a673f92d3624bd926dc49a52cf25b92"
-  integrity sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==
+  version "7.20.5"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.5.tgz#45e2114dc6cd4ab167f81daf7820e8fa1250d113"
+  integrity sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==
   dependencies:
     "@ampproject/remapping" "^2.1.0"
     "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.20.2"
+    "@babel/generator" "^7.20.5"
     "@babel/helper-compilation-targets" "^7.20.0"
     "@babel/helper-module-transforms" "^7.20.2"
-    "@babel/helpers" "^7.20.1"
-    "@babel/parser" "^7.20.2"
+    "@babel/helpers" "^7.20.5"
+    "@babel/parser" "^7.20.5"
     "@babel/template" "^7.18.10"
-    "@babel/traverse" "^7.20.1"
-    "@babel/types" "^7.20.2"
+    "@babel/traverse" "^7.20.5"
+    "@babel/types" "^7.20.5"
     convert-source-map "^1.7.0"
     debug "^4.1.0"
     gensync "^1.0.0-beta.2"
@@ -52,12 +57,12 @@
     eslint-visitor-keys "^2.1.0"
     semver "^6.3.0"
 
-"@babel/generator@^7.20.1", "@babel/generator@^7.20.2":
-  version "7.20.4"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.4.tgz#4d9f8f0c30be75fd90a0562099a26e5839602ab8"
-  integrity sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==
+"@babel/generator@^7.20.1", "@babel/generator@^7.20.5":
+  version "7.20.5"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.5.tgz#cb25abee3178adf58d6814b68517c62bdbfdda95"
+  integrity sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==
   dependencies:
-    "@babel/types" "^7.20.2"
+    "@babel/types" "^7.20.5"
     "@jridgewell/gen-mapping" "^0.3.2"
     jsesc "^2.5.1"
 
@@ -253,14 +258,14 @@
     "@babel/traverse" "^7.19.0"
     "@babel/types" "^7.19.0"
 
-"@babel/helpers@^7.20.1":
-  version "7.20.1"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.1.tgz#2ab7a0fcb0a03b5bf76629196ed63c2d7311f4c9"
-  integrity sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==
+"@babel/helpers@^7.20.5":
+  version "7.20.6"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.6.tgz#e64778046b70e04779dfbdf924e7ebb45992c763"
+  integrity sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==
   dependencies:
     "@babel/template" "^7.18.10"
-    "@babel/traverse" "^7.20.1"
-    "@babel/types" "^7.20.0"
+    "@babel/traverse" "^7.20.5"
+    "@babel/types" "^7.20.5"
 
 "@babel/highlight@^7.18.6":
   version "7.18.6"
@@ -271,10 +276,10 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2":
-  version "7.20.3"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2"
-  integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==
+"@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.5":
+  version "7.20.5"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8"
+  integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
 
 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
   version "7.18.6"
@@ -896,7 +901,7 @@
     "@babel/parser" "^7.18.10"
     "@babel/types" "^7.18.10"
 
-"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1":
+"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1":
   version "7.20.1"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
   integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
@@ -912,7 +917,32 @@
     debug "^4.1.0"
     globals "^11.1.0"
 
-"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.4.4":
+"@babel/traverse@^7.20.1", "@babel/traverse@^7.20.5":
+  version "7.20.5"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.5.tgz#78eb244bea8270fdda1ef9af22a5d5e5b7e57133"
+  integrity sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==
+  dependencies:
+    "@babel/code-frame" "^7.18.6"
+    "@babel/generator" "^7.20.5"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-function-name" "^7.19.0"
+    "@babel/helper-hoist-variables" "^7.18.6"
+    "@babel/helper-split-export-declaration" "^7.18.6"
+    "@babel/parser" "^7.20.5"
+    "@babel/types" "^7.20.5"
+    debug "^4.1.0"
+    globals "^11.1.0"
+
+"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5":
+  version "7.20.5"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
+  integrity sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==
+  dependencies:
+    "@babel/helper-string-parser" "^7.19.4"
+    "@babel/helper-validator-identifier" "^7.19.1"
+    to-fast-properties "^2.0.0"
+
+"@babel/types@^7.18.9", "@babel/types@^7.4.4":
   version "7.20.2"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842"
   integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==
@@ -926,29 +956,34 @@
   resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
   integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
 
-"@eslint/eslintrc@^1.2.1":
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6"
-  integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==
+"@eslint/eslintrc@^1.3.3":
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95"
+  integrity sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==
   dependencies:
     ajv "^6.12.4"
     debug "^4.3.2"
-    espree "^9.3.1"
-    globals "^13.9.0"
+    espree "^9.4.0"
+    globals "^13.15.0"
     ignore "^5.2.0"
     import-fresh "^3.2.1"
     js-yaml "^4.1.0"
-    minimatch "^3.0.4"
+    minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@humanwhocodes/config-array@^0.9.2":
-  version "0.9.5"
-  resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7"
-  integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==
+"@humanwhocodes/config-array@^0.11.6":
+  version "0.11.7"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.7.tgz#38aec044c6c828f6ed51d5d7ae3d9b9faf6dbb0f"
+  integrity sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==
   dependencies:
     "@humanwhocodes/object-schema" "^1.2.1"
     debug "^4.1.1"
-    minimatch "^3.0.4"
+    minimatch "^3.0.5"
+
+"@humanwhocodes/module-importer@^1.0.1":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+  integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
 
 "@humanwhocodes/object-schema@^1.2.1":
   version "1.2.1"
@@ -972,7 +1007,7 @@
     "@jridgewell/sourcemap-codec" "^1.4.10"
     "@jridgewell/trace-mapping" "^0.3.9"
 
-"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3":
+"@jridgewell/resolve-uri@3.1.0":
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
   integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
@@ -995,15 +1030,7 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
   integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
 
-"@jridgewell/trace-mapping@^0.3.14":
-  version "0.3.15"
-  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
-  integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==
-  dependencies:
-    "@jridgewell/resolve-uri" "^3.0.3"
-    "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@jridgewell/trace-mapping@^0.3.9":
+"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9":
   version "0.3.17"
   resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
   integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==
@@ -1018,6 +1045,27 @@
   dependencies:
     eslint-scope "5.1.1"
 
+"@nodelib/fs.scandir@2.1.5":
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+  integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+  dependencies:
+    "@nodelib/fs.stat" "2.0.5"
+    run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5":
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.8":
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+  integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+  dependencies:
+    "@nodelib/fs.scandir" "2.1.5"
+    fastq "^1.6.0"
+
 "@polka/url@^1.0.0-next.20":
   version "1.0.0-next.21"
   resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
@@ -1032,9 +1080,9 @@
     "@types/estree" "*"
 
 "@types/eslint@*":
-  version "8.4.6"
-  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.6.tgz#7976f054c1bccfcf514bff0564c0c41df5c08207"
-  integrity sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==
+  version "8.4.10"
+  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.10.tgz#19731b9685c19ed1552da7052b6f668ed7eb64bb"
+  integrity sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==
   dependencies:
     "@types/estree" "*"
     "@types/json-schema" "*"
@@ -1055,9 +1103,9 @@
   integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
 
 "@types/node@*":
-  version "18.7.17"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.17.tgz#52438111ea98f77475470fc62d79b9eb96bb2c92"
-  integrity sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ==
+  version "18.11.14"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.14.tgz#a8571b25f3a31e9ded14e3ab9488509adef831d8"
+  integrity sha512-0KXV57tENYmmJMl+FekeW9V3O/rlcqGQQJ/hNh9r8pKIj304pskWuEd8fCyNT86g/TpO0gcOTiLzsHLEURFMIQ==
 
 "@vue/component-compiler-utils@^3.1.0":
   version "3.3.0"
@@ -1228,7 +1276,7 @@ acorn-import-assertions@^1.7.6:
   resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9"
   integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==
 
-acorn-jsx@^5.3.1:
+acorn-jsx@^5.3.2:
   version "5.3.2"
   resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
   integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
@@ -1238,21 +1286,11 @@ acorn-walk@^8.0.0:
   resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
   integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
 
-acorn@^8.0.4:
+acorn@^8.0.4, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0:
   version "8.8.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
   integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
 
-acorn@^8.5.0, acorn@^8.7.1:
-  version "8.8.0"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
-  integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
-
-acorn@^8.7.0:
-  version "8.7.0"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
-  integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
-
 ajv-keywords@^3.5.2:
   version "3.5.2"
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
@@ -1288,9 +1326,9 @@ ansi-styles@^4.1.0:
     color-convert "^2.0.1"
 
 anymatch@~3.1.2:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
-  integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+  integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
   dependencies:
     normalize-path "^3.0.0"
     picomatch "^2.0.4"
@@ -1354,6 +1392,11 @@ bluebird@^3.1.1:
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
   integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
 
+boolbase@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+  integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
 brace-expansion@^1.1.7:
   version "1.1.11"
   resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -1369,17 +1412,7 @@ braces@~3.0.2:
   dependencies:
     fill-range "^7.0.1"
 
-browserslist@^4.14.5:
-  version "4.21.3"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
-  integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
-  dependencies:
-    caniuse-lite "^1.0.30001370"
-    electron-to-chromium "^1.4.202"
-    node-releases "^2.0.6"
-    update-browserslist-db "^1.0.5"
-
-browserslist@^4.21.3, browserslist@^4.21.4:
+browserslist@^4.14.5, browserslist@^4.21.3, browserslist@^4.21.4:
   version "4.21.4"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
   integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
@@ -1399,10 +1432,10 @@ callsites@^3.0.0:
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
   integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
 
-caniuse-lite@^1.0.30001370, caniuse-lite@^1.0.30001400:
-  version "1.0.30001431"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz#e7c59bd1bc518fae03a4656be442ce6c4887a795"
-  integrity sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==
+caniuse-lite@^1.0.30001400:
+  version "1.0.30001439"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz#ab7371faeb4adff4b74dad1718a6fd122e45d9cb"
+  integrity sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==
 
 chalk@^2.0.0:
   version "2.4.2"
@@ -1456,9 +1489,9 @@ clone-deep@^4.0.1:
     shallow-clone "^3.0.0"
 
 codemirror@^5.65.6:
-  version "5.65.9"
-  resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.9.tgz#ec70c92aa206ee4c9853d5f1e7c4ed356cdab68c"
-  integrity sha512-19Jox5sAKpusTDgqgKB5dawPpQcY+ipQK7xoEI+MVucEF9qqFaXpeqY1KaoyGBso/wHQoDa4HMMxMjdsS3Zzzw==
+  version "5.65.10"
+  resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.10.tgz#4276a93b8534ce91f14b733ba9a1ac949666eac9"
+  integrity sha512-IXAG5wlhbgcTJ6rZZcmi4+sjWIbJqIGfeg3tNa3yX84Jb3T4huS5qzQAo/cUisc1l3bI47WZodpyf7cYcocDKg==
 
 color-convert@^1.9.0:
   version "1.9.3"
@@ -1507,7 +1540,7 @@ commondir@^1.0.1:
 concat-map@0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-  integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+  integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
 
 consolidate@^0.15.1:
   version "0.15.1"
@@ -1538,18 +1571,18 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
     which "^2.0.1"
 
 css-loader@^6.5.1:
-  version "6.7.1"
-  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e"
-  integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==
+  version "6.7.2"
+  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.2.tgz#26bc22401b5921686a10fbeba75d124228302304"
+  integrity sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q==
   dependencies:
     icss-utils "^5.1.0"
-    postcss "^8.4.7"
+    postcss "^8.4.18"
     postcss-modules-extract-imports "^3.0.0"
     postcss-modules-local-by-default "^4.0.0"
     postcss-modules-scope "^3.0.0"
     postcss-modules-values "^4.0.0"
     postcss-value-parser "^4.2.0"
-    semver "^7.3.5"
+    semver "^7.3.8"
 
 cssesc@^3.0.0:
   version "3.0.0"
@@ -1590,7 +1623,7 @@ duplexer@^0.1.2:
   resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
   integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
 
-electron-to-chromium@^1.4.202, electron-to-chromium@^1.4.251:
+electron-to-chromium@^1.4.251:
   version "1.4.284"
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592"
   integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==
@@ -1601,9 +1634,9 @@ emojis-list@^3.0.0:
   integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
 
 enhanced-resolve@^5.10.0:
-  version "5.10.0"
-  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6"
-  integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==
+  version "5.12.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634"
+  integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==
   dependencies:
     graceful-fs "^4.2.4"
     tapable "^2.2.0"
@@ -1634,24 +1667,26 @@ escape-string-regexp@^4.0.0:
   integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
 
 eslint-config-prettier@^8.3.0:
-  version "8.3.0"
-  resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a"
-  integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==
+  version "8.5.0"
+  resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1"
+  integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==
 
 eslint-plugin-prettier@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0"
-  integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b"
+  integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
   dependencies:
     prettier-linter-helpers "^1.0.0"
 
 eslint-plugin-vue@^8.2.0:
-  version "8.5.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-8.5.0.tgz#65832bba43ca713fa5da16bdfcf55d0095677f6f"
-  integrity sha512-i1uHCTAKOoEj12RDvdtONWrGzjFm/djkzqfhmQ0d6M/W8KM81mhswd/z+iTZ0jCpdUedW3YRgcVfQ37/J4zoYQ==
+  version "8.7.1"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz#f13c53547a0c9d64588a675cc5ecc6ccaf63703f"
+  integrity sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==
   dependencies:
     eslint-utils "^3.0.0"
     natural-compare "^1.4.0"
+    nth-check "^2.0.1"
+    postcss-selector-parser "^6.0.9"
     semver "^7.3.5"
     vue-eslint-parser "^8.0.1"
 
@@ -1689,12 +1724,14 @@ eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.3.0:
   integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
 
 eslint@^8.6.0:
-  version "8.11.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37"
-  integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==
-  dependencies:
-    "@eslint/eslintrc" "^1.2.1"
-    "@humanwhocodes/config-array" "^0.9.2"
+  version "8.29.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.29.0.tgz#d74a88a20fb44d59c51851625bc4ee8d0ec43f87"
+  integrity sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==
+  dependencies:
+    "@eslint/eslintrc" "^1.3.3"
+    "@humanwhocodes/config-array" "^0.11.6"
+    "@humanwhocodes/module-importer" "^1.0.1"
+    "@nodelib/fs.walk" "^1.2.8"
     ajv "^6.10.0"
     chalk "^4.0.0"
     cross-spawn "^7.0.2"
@@ -1704,38 +1741,40 @@ eslint@^8.6.0:
     eslint-scope "^7.1.1"
     eslint-utils "^3.0.0"
     eslint-visitor-keys "^3.3.0"
-    espree "^9.3.1"
+    espree "^9.4.0"
     esquery "^1.4.0"
     esutils "^2.0.2"
     fast-deep-equal "^3.1.3"
     file-entry-cache "^6.0.1"
-    functional-red-black-tree "^1.0.1"
-    glob-parent "^6.0.1"
-    globals "^13.6.0"
+    find-up "^5.0.0"
+    glob-parent "^6.0.2"
+    globals "^13.15.0"
+    grapheme-splitter "^1.0.4"
     ignore "^5.2.0"
     import-fresh "^3.0.0"
     imurmurhash "^0.1.4"
     is-glob "^4.0.0"
+    is-path-inside "^3.0.3"
+    js-sdsl "^4.1.4"
     js-yaml "^4.1.0"
     json-stable-stringify-without-jsonify "^1.0.1"
     levn "^0.4.1"
     lodash.merge "^4.6.2"
-    minimatch "^3.0.4"
+    minimatch "^3.1.2"
     natural-compare "^1.4.0"
     optionator "^0.9.1"
     regexpp "^3.2.0"
     strip-ansi "^6.0.1"
     strip-json-comments "^3.1.0"
     text-table "^0.2.0"
-    v8-compile-cache "^2.0.3"
 
-espree@^9.0.0, espree@^9.3.1:
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd"
-  integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==
+espree@^9.0.0, espree@^9.4.0:
+  version "9.4.1"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd"
+  integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==
   dependencies:
-    acorn "^8.7.0"
-    acorn-jsx "^5.3.1"
+    acorn "^8.8.0"
+    acorn-jsx "^5.3.2"
     eslint-visitor-keys "^3.3.0"
 
 esquery@^1.4.0:
@@ -1790,13 +1829,20 @@ fast-json-stable-stringify@^2.0.0:
 fast-levenshtein@^2.0.6:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
-  integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+  integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
 
 fastest-levenshtein@^1.0.12:
   version "1.0.16"
   resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
   integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
 
+fastq@^1.6.0:
+  version "1.14.0"
+  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.14.0.tgz#107f69d7295b11e0fccc264e1fc6389f623731ce"
+  integrity sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==
+  dependencies:
+    reusify "^1.0.4"
+
 file-entry-cache@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@@ -1828,6 +1874,14 @@ find-up@^4.0.0:
     locate-path "^5.0.0"
     path-exists "^4.0.0"
 
+find-up@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+  integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+  dependencies:
+    locate-path "^6.0.0"
+    path-exists "^4.0.0"
+
 flat-cache@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@@ -1837,14 +1891,14 @@ flat-cache@^3.0.4:
     rimraf "^3.0.2"
 
 flatted@^3.1.0:
-  version "3.2.4"
-  resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2"
-  integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
+  version "3.2.7"
+  resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
+  integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
 
 fs.realpath@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
-  integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
 
 fsevents@~2.3.2:
   version "2.3.2"
@@ -1856,17 +1910,12 @@ function-bind@^1.1.1:
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
   integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
 
-functional-red-black-tree@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
-  integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
-
 gensync@^1.0.0-beta.2:
   version "1.0.0-beta.2"
   resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
   integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
 
-glob-parent@^6.0.1:
+glob-parent@^6.0.2:
   version "6.0.2"
   resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
   integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
@@ -1886,14 +1935,14 @@ glob-to-regexp@^0.4.1:
   integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
 
 glob@^7.1.3:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
-  integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
+  version "7.2.3"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+  integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
   dependencies:
     fs.realpath "^1.0.0"
     inflight "^1.0.4"
     inherits "2"
-    minimatch "^3.0.4"
+    minimatch "^3.1.1"
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
@@ -1902,10 +1951,10 @@ globals@^11.1.0:
   resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
   integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
 
-globals@^13.6.0, globals@^13.9.0:
-  version "13.12.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e"
-  integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==
+globals@^13.15.0:
+  version "13.19.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8"
+  integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==
   dependencies:
     type-fest "^0.20.2"
 
@@ -1914,6 +1963,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
   integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
 
+grapheme-splitter@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
+  integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
+
 gzip-size@^6.0.0:
   version "6.0.0"
   resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
@@ -1959,9 +2013,9 @@ icss-utils@^5.0.0, icss-utils@^5.1.0:
   integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
 
 ignore@^5.2.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
-  integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.1.tgz#c2b1f76cb999ede1502f3a226a9310fdfe88d46c"
+  integrity sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==
 
 immutable@^4.0.0:
   version "4.1.0"
@@ -1987,12 +2041,12 @@ import-local@^3.0.2:
 imurmurhash@^0.1.4:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
-  integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+  integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
 
 inflight@^1.0.4:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
-  integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+  integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
   dependencies:
     once "^1.3.0"
     wrappy "1"
@@ -2038,6 +2092,11 @@ is-number@^7.0.0:
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
   integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
 
+is-path-inside@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+  integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
 is-plain-object@^2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
@@ -2064,6 +2123,11 @@ jest-worker@^27.4.5:
     merge-stream "^2.0.0"
     supports-color "^8.0.0"
 
+js-sdsl@^4.1.4:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.2.0.tgz#278e98b7bea589b8baaf048c20aeb19eb7ad09d0"
+  integrity sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==
+
 js-tokens@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -2099,7 +2163,7 @@ json-schema-traverse@^0.4.1:
 json-stable-stringify-without-jsonify@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
-  integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+  integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
 
 json5@^1.0.1:
   version "1.0.1"
@@ -2161,6 +2225,13 @@ locate-path@^5.0.0:
   dependencies:
     p-locate "^4.1.0"
 
+locate-path@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+  integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+  dependencies:
+    p-locate "^5.0.0"
+
 lodash.debounce@^4.0.8:
   version "4.0.8"
   resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -2222,10 +2293,10 @@ mime-types@^2.1.27:
   dependencies:
     mime-db "1.52.0"
 
-minimatch@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
-  integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
   dependencies:
     brace-expansion "^1.1.7"
 
@@ -2244,15 +2315,15 @@ ms@2.1.2:
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
-nanoid@^3.3.1:
-  version "3.3.1"
-  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
-  integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
+nanoid@^3.3.4:
+  version "3.3.4"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
+  integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
 
 natural-compare@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
-  integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+  integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
 
 neo-async@^2.6.2:
   version "2.6.2"
@@ -2260,19 +2331,26 @@ neo-async@^2.6.2:
   integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
 
 node-releases@^2.0.6:
-  version "2.0.6"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
-  integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
+  version "2.0.7"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.7.tgz#593edbc7c22860ee4d32d3933cfebdfab0c0e0e5"
+  integrity sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ==
 
 normalize-path@^3.0.0, normalize-path@~3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
   integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
 
+nth-check@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+  integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+  dependencies:
+    boolbase "^1.0.0"
+
 once@^1.3.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
-  integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+  integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
   dependencies:
     wrappy "1"
 
@@ -2300,6 +2378,13 @@ p-limit@^2.2.0:
   dependencies:
     p-try "^2.0.0"
 
+p-limit@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+  dependencies:
+    yocto-queue "^0.1.0"
+
 p-locate@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
@@ -2307,6 +2392,13 @@ p-locate@^4.1.0:
   dependencies:
     p-limit "^2.2.0"
 
+p-locate@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+  integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+  dependencies:
+    p-limit "^3.0.2"
+
 p-try@^2.0.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
@@ -2327,7 +2419,7 @@ path-exists@^4.0.0:
 path-is-absolute@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
-  integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+  integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
 
 path-key@^3.1.0:
   version "3.1.1"
@@ -2389,7 +2481,7 @@ postcss-modules-values@^4.0.0:
   dependencies:
     icss-utils "^5.0.0"
 
-postcss-selector-parser@^6.0.2:
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.9:
   version "6.0.11"
   resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc"
   integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==
@@ -2397,20 +2489,7 @@ postcss-selector-parser@^6.0.2:
     cssesc "^3.0.0"
     util-deprecate "^1.0.2"
 
-postcss-selector-parser@^6.0.4:
-  version "6.0.9"
-  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f"
-  integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==
-  dependencies:
-    cssesc "^3.0.0"
-    util-deprecate "^1.0.2"
-
-postcss-value-parser@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
-  integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
-
-postcss-value-parser@^4.2.0:
+postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
   integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@@ -2423,12 +2502,12 @@ postcss@^7.0.36:
     picocolors "^0.2.1"
     source-map "^0.6.1"
 
-postcss@^8.4.7:
-  version "8.4.12"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905"
-  integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==
+postcss@^8.4.18:
+  version "8.4.20"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.20.tgz#64c52f509644cecad8567e949f4081d98349dc56"
+  integrity sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==
   dependencies:
-    nanoid "^3.3.1"
+    nanoid "^3.3.4"
     picocolors "^1.0.0"
     source-map-js "^1.0.2"
 
@@ -2464,6 +2543,11 @@ punycode@^2.1.0:
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
   integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
 
+queue-microtask@^1.2.2:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+  integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
 randombytes@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@@ -2564,6 +2648,11 @@ resolve@^1.14.2, resolve@^1.9.0:
     path-parse "^1.0.7"
     supports-preserve-symlinks-flag "^1.0.0"
 
+reusify@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
 rimraf@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@@ -2571,6 +2660,13 @@ rimraf@^3.0.2:
   dependencies:
     glob "^7.1.3"
 
+run-parallel@^1.1.9:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+  integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+  dependencies:
+    queue-microtask "^1.2.2"
+
 safe-buffer@^5.1.0:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
@@ -2585,9 +2681,9 @@ sass-loader@^12.4.0:
     neo-async "^2.6.2"
 
 sass@^1.48.0:
-  version "1.56.1"
-  resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.1.tgz#94d3910cd468fd075fa87f5bb17437a0b617d8a7"
-  integrity sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==
+  version "1.56.2"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.2.tgz#9433b345ab3872996c82a53a58c014fd244fd095"
+  integrity sha512-ciEJhnyCRwzlBCB+h5cCPM6ie/6f8HrhZMQOf5vlU60Y1bI1rx5Zb0vlDZvaycHsg/MqFfF1Eq2eokAa32iw8w==
   dependencies:
     chokidar ">=3.0.0 <4.0.0"
     immutable "^4.0.0"
@@ -2616,10 +2712,10 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
   integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
 
-semver@^7.3.5:
-  version "7.3.5"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
-  integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+semver@^7.3.5, semver@^7.3.8:
+  version "7.3.8"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
+  integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
   dependencies:
     lru-cache "^6.0.0"
 
@@ -2736,9 +2832,9 @@ terser-webpack-plugin@^5.1.3:
     terser "^5.14.1"
 
 terser@^5.14.1:
-  version "5.15.0"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.0.tgz#e16967894eeba6e1091509ec83f0c60e179f2425"
-  integrity sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==
+  version "5.16.1"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.1.tgz#5af3bc3d0f24241c7fb2024199d5c461a1075880"
+  integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==
   dependencies:
     "@jridgewell/source-map" "^0.3.2"
     acorn "^8.5.0"
@@ -2748,7 +2844,7 @@ terser@^5.14.1:
 text-table@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
-  integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+  integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
 
 to-fast-properties@^2.0.0:
   version "2.0.0"
@@ -2802,7 +2898,7 @@ unicode-property-aliases-ecmascript@^2.0.0:
   resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd"
   integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==
 
-update-browserslist-db@^1.0.5, update-browserslist-db@^1.0.9:
+update-browserslist-db@^1.0.9:
   version "1.0.10"
   resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
   integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==
@@ -2822,11 +2918,6 @@ util-deprecate@^1.0.2:
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
   integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
 
-v8-compile-cache@^2.0.3:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
-  integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
-
 vue-eslint-parser@^8.0.1:
   version "8.3.0"
   resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
@@ -2932,9 +3023,9 @@ webpack-sources@^3.2.3:
   integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
 
 webpack@^5.74.0:
-  version "5.74.0"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980"
-  integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==
+  version "5.75.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152"
+  integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==
   dependencies:
     "@types/eslint-scope" "^3.7.3"
     "@types/estree" "^0.0.51"
@@ -2981,7 +3072,7 @@ word-wrap@^1.2.3:
 wrappy@1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
-  integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+  integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
 
 ws@^7.3.1:
   version "7.5.9"
@@ -2997,3 +3088,8 @@ yallist@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
   integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yocto-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==

From e4a0308eeb2207b1740df6e00a0041cc3c2b11c4 Mon Sep 17 00:00:00 2001
From: Vladislav Korenkov <vladnfs3@gmail.com>
Date: Mon, 26 Dec 2022 18:08:50 +1000
Subject: [PATCH 8/8] Optimization: `filter_by_user` query

---
 doc/gui.rst                    | 5 +++++
 polemarch/main/models/users.py | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/doc/gui.rst b/doc/gui.rst
index 10d8e2f4..94ca88da 100644
--- a/doc/gui.rst
+++ b/doc/gui.rst
@@ -557,6 +557,11 @@ As you can see, the form of new group creation consists of following fields:
 * **Notes** - not required field for some user’s notes, for example,
   for what purpose this group was created or something like this.
 
+.. warning::
+  By default SQLite's maximum expression tree depth is 1000. This could create
+  problems with very nested groups. If you encounter so, please refer to
+  `documentation https://www.sqlite.org/limits.html#max_expr_depth`_.
+
 After group creation you will see the next page:
 
 .. image:: new_screenshots/test_group.png
diff --git a/polemarch/main/models/users.py b/polemarch/main/models/users.py
index 099f3147..dd5a9fbb 100644
--- a/polemarch/main/models/users.py
+++ b/polemarch/main/models/users.py
@@ -24,7 +24,7 @@ class UserGroup(BaseGroup, ACLModel):
 
 class ACLPermissionQuerySet(BQuerySet):
     def filter_by_user(self, user):  # noce
-        return self.filter(models.Q(user=user) | models.Q(uagroup__user=user))
+        return self.filter(models.Q(user=user) | models.Q(uagroup__id__in=user.groups.values('id')))
 
 
 class ACLPermission(BModel):