From 1af2e64aae6f8ade6137eb8ae1618bc55863109a Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 13 Nov 2025 21:00:23 -0600 Subject: [PATCH] Add Cloudron packaging for Maubot --- maubot-src/.dockerignore | 5 + maubot-src/.editorconfig | 19 + maubot-src/.github/workflows/python-lint.yml | 26 + maubot-src/.gitignore | 19 + maubot-src/.gitlab-ci-plugin.yml | 29 + maubot-src/.gitlab-ci.yml | 86 + maubot-src/.pre-commit-config.yaml | 20 + maubot-src/CHANGELOG.md | 171 + maubot-src/CLOUDRON.md | 74 + maubot-src/CloudronManifest.json | 45 + maubot-src/Dockerfile | 59 + maubot-src/Dockerfile.ci | 57 + maubot-src/LICENSE | 661 ++ maubot-src/MANIFEST.in | 5 + maubot-src/README.md | 29 + maubot-src/cloudron/default-config.yaml | 75 + maubot-src/dev-requirements.txt | 3 + maubot-src/docker/mbc.sh | 3 + maubot-src/docker/run.sh | 46 + maubot-src/examples/LICENSE | 21 + maubot-src/examples/README.md | 7 + maubot-src/examples/config/base-config.yaml | 5 + maubot-src/examples/config/configurablebot.py | 27 + maubot-src/examples/config/maubot.yaml | 13 + maubot-src/examples/database/maubot.yaml | 10 + maubot-src/examples/database/storagebot.py | 72 + maubot-src/examples/helloworld/helloworld.py | 10 + maubot-src/examples/helloworld/maubot.yaml | 43 + maubot-src/maubot/__init__.py | 4 + maubot-src/maubot/__main__.py | 185 + maubot-src/maubot/__meta__.py | 1 + maubot-src/maubot/cli/__init__.py | 2 + maubot-src/maubot/cli/__main__.py | 3 + maubot-src/maubot/cli/base.py | 23 + maubot-src/maubot/cli/cliq/__init__.py | 2 + maubot-src/maubot/cli/cliq/cliq.py | 169 + maubot-src/maubot/cli/cliq/validators.py | 85 + maubot-src/maubot/cli/commands/__init__.py | 1 + maubot-src/maubot/cli/commands/auth.py | 166 + maubot-src/maubot/cli/commands/build.py | 155 + maubot-src/maubot/cli/commands/init.py | 99 + maubot-src/maubot/cli/commands/login.py | 77 + maubot-src/maubot/cli/commands/logs.py | 107 + maubot-src/maubot/cli/commands/upload.py | 58 + maubot-src/maubot/cli/config.py | 80 + maubot-src/maubot/cli/res/config.yaml | 6 + maubot-src/maubot/cli/res/maubot.yaml.j2 | 42 + maubot-src/maubot/cli/res/plugin.py.j2 | 27 + maubot-src/maubot/cli/res/spdx.json.zip | Bin 0 -> 698204 bytes maubot-src/maubot/cli/util/__init__.py | 0 maubot-src/maubot/cli/util/spdx.py | 45 + maubot-src/maubot/client.py | 581 ++ maubot-src/maubot/config.py | 100 + maubot-src/maubot/db/__init__.py | 13 + maubot-src/maubot/db/client.py | 114 + maubot-src/maubot/db/instance.py | 101 + maubot-src/maubot/db/upgrade/__init__.py | 5 + .../maubot/db/upgrade/v01_initial_revision.py | 136 + .../upgrade/v02_instance_database_engine.py | 25 + maubot-src/maubot/example-config.yaml | 132 + maubot-src/maubot/handlers/__init__.py | 1 + maubot-src/maubot/handlers/command.py | 496 + maubot-src/maubot/handlers/event.py | 44 + maubot-src/maubot/handlers/web.py | 66 + maubot-src/maubot/instance.py | 533 + maubot-src/maubot/lib/__init__.py | 0 maubot-src/maubot/lib/color_log.py | 49 + maubot-src/maubot/lib/future_awaitable.py | 9 + maubot-src/maubot/lib/optionalalchemy.py | 19 + maubot-src/maubot/lib/plugin_db.py | 100 + maubot-src/maubot/lib/state_store.py | 27 + maubot-src/maubot/lib/zipimport.py | 794 ++ maubot-src/maubot/loader/__init__.py | 3 + maubot-src/maubot/loader/abc.py | 98 + maubot-src/maubot/loader/meta.py | 69 + maubot-src/maubot/loader/zip.py | 310 + maubot-src/maubot/management/__init__.py | 0 maubot-src/maubot/management/api/__init__.py | 48 + maubot-src/maubot/management/api/auth.py | 76 + maubot-src/maubot/management/api/base.py | 40 + maubot-src/maubot/management/api/client.py | 217 + .../maubot/management/api/client_auth.py | 273 + .../maubot/management/api/client_proxy.py | 56 + maubot-src/maubot/management/api/dev_open.py | 57 + maubot-src/maubot/management/api/instance.py | 97 + .../management/api/instance_database.py | 161 + maubot-src/maubot/management/api/log.py | 172 + maubot-src/maubot/management/api/login.py | 41 + .../maubot/management/api/middleware.py | 78 + maubot-src/maubot/management/api/plugin.py | 64 + .../maubot/management/api/plugin_upload.py | 145 + maubot-src/maubot/management/api/responses.py | 510 + maubot-src/maubot/management/api/spec.md | 2 + maubot-src/maubot/management/api/spec.yaml | 728 ++ .../maubot/management/frontend/.eslintrc.json | 67 + .../maubot/management/frontend/.gitignore | 5 + .../maubot/management/frontend/.sass-lint.yml | 27 + .../maubot/management/frontend/package.json | 40 + .../management/frontend/public/favicon.png | Bin 0 -> 13551 bytes .../management/frontend/public/index.html | 37 + .../management/frontend/public/manifest.json | 15 + .../maubot/management/frontend/src/api.js | 276 + .../src/components/PreferenceTable.js | 71 + .../frontend/src/components/PrivateRoute.js | 28 + .../frontend/src/components/Spinner.js | 11 + .../frontend/src/components/Switch.js | 59 + .../frontend/src/fonts/firacode-bold.woff2 | Bin 0 -> 107384 bytes .../frontend/src/fonts/firacode-regular.woff2 | Bin 0 -> 103168 bytes .../frontend/src/fonts/raleway-bold.woff2 | Bin 0 -> 20864 bytes .../frontend/src/fonts/raleway-light.woff2 | Bin 0 -> 20808 bytes .../frontend/src/fonts/raleway-regular.woff2 | Bin 0 -> 20724 bytes .../maubot/management/frontend/src/index.js | 21 + .../management/frontend/src/pages/Login.js | 72 + .../management/frontend/src/pages/Main.js | 91 + .../src/pages/dashboard/BaseMainView.js | 98 + .../frontend/src/pages/dashboard/Client.js | 392 + .../frontend/src/pages/dashboard/Home.js | 30 + .../frontend/src/pages/dashboard/Instance.js | 233 + .../src/pages/dashboard/InstanceDatabase.js | 332 + .../frontend/src/pages/dashboard/Log.js | 191 + .../frontend/src/pages/dashboard/Modal.js | 52 + .../frontend/src/pages/dashboard/Plugin.js | 104 + .../frontend/src/pages/dashboard/index.js | 272 + .../management/frontend/src/res/bot.svg | 5 + .../frontend/src/res/chevron-left.svg | 1 + .../frontend/src/res/chevron-right.svg | 1 + .../management/frontend/src/res/plus.svg | 5 + .../management/frontend/src/res/sort-down.svg | 1 + .../management/frontend/src/res/sort-up.svg | 1 + .../management/frontend/src/res/upload.svg | 5 + .../management/frontend/src/setupProxy.js | 6 + .../frontend/src/style/base/body.sass | 39 + .../frontend/src/style/base/elements.sass | 120 + .../frontend/src/style/base/fonts.sass | 30 + .../frontend/src/style/base/vars.sass | 33 + .../management/frontend/src/style/index.sass | 33 + .../frontend/src/style/lib/contextmenu.scss | 80 + .../src/style/lib/preferencetable.sass | 85 + .../frontend/src/style/lib/spinner.sass | 65 + .../frontend/src/style/lib/switch.sass | 77 + .../src/style/pages/client/avatar.sass | 62 + .../src/style/pages/client/index.sass | 48 + .../src/style/pages/client/started.sass | 46 + .../src/style/pages/dashboard-grid.scss | 19 + .../frontend/src/style/pages/dashboard.sass | 129 + .../src/style/pages/instance-database.sass | 101 + .../frontend/src/style/pages/instance.sass | 35 + .../frontend/src/style/pages/log.sass | 89 + .../frontend/src/style/pages/login.sass | 62 + .../src/style/pages/mixins/instancelist.sass | 40 + .../style/pages/mixins/upload-container.sass | 43 + .../frontend/src/style/pages/modal.sass | 71 + .../frontend/src/style/pages/plugin.sass | 53 + .../frontend/src/style/pages/sidebar.sass | 79 + .../frontend/src/style/pages/topbar.sass | 79 + .../maubot/management/frontend/yarn.lock | 8963 +++++++++++++++++ maubot-src/maubot/matrix.py | 314 + maubot-src/maubot/plugin_base.py | 142 + maubot-src/maubot/plugin_server.py | 90 + maubot-src/maubot/py.typed | 0 maubot-src/maubot/scheduler.py | 159 + maubot-src/maubot/server.py | 182 + maubot-src/maubot/standalone/Dockerfile | 32 + maubot-src/maubot/standalone/__init__.py | 0 maubot-src/maubot/standalone/__main__.py | 424 + maubot-src/maubot/standalone/config.py | 52 + maubot-src/maubot/standalone/database.py | 73 + .../maubot/standalone/example-config.yaml | 78 + maubot-src/maubot/standalone/loader.py | 44 + maubot-src/maubot/testing/__init__.py | 17 + maubot-src/maubot/testing/bot.py | 100 + maubot-src/maubot/testing/fixtures.py | 135 + maubot-src/nginx.conf | 58 + maubot-src/optional-requirements.txt | 15 + maubot-src/pyproject.toml | 13 + maubot-src/requirements.txt | 16 + maubot-src/setup.py | 79 + maubot-src/start.sh | 107 + maubot-src/supervisord.conf | 22 + 179 files changed, 24749 insertions(+) create mode 100644 maubot-src/.dockerignore create mode 100644 maubot-src/.editorconfig create mode 100644 maubot-src/.github/workflows/python-lint.yml create mode 100644 maubot-src/.gitignore create mode 100644 maubot-src/.gitlab-ci-plugin.yml create mode 100644 maubot-src/.gitlab-ci.yml create mode 100644 maubot-src/.pre-commit-config.yaml create mode 100644 maubot-src/CHANGELOG.md create mode 100644 maubot-src/CLOUDRON.md create mode 100644 maubot-src/CloudronManifest.json create mode 100644 maubot-src/Dockerfile create mode 100644 maubot-src/Dockerfile.ci create mode 100644 maubot-src/LICENSE create mode 100644 maubot-src/MANIFEST.in create mode 100644 maubot-src/README.md create mode 100644 maubot-src/cloudron/default-config.yaml create mode 100644 maubot-src/dev-requirements.txt create mode 100755 maubot-src/docker/mbc.sh create mode 100755 maubot-src/docker/run.sh create mode 100644 maubot-src/examples/LICENSE create mode 100644 maubot-src/examples/README.md create mode 100644 maubot-src/examples/config/base-config.yaml create mode 100644 maubot-src/examples/config/configurablebot.py create mode 100644 maubot-src/examples/config/maubot.yaml create mode 100644 maubot-src/examples/database/maubot.yaml create mode 100644 maubot-src/examples/database/storagebot.py create mode 100644 maubot-src/examples/helloworld/helloworld.py create mode 100644 maubot-src/examples/helloworld/maubot.yaml create mode 100644 maubot-src/maubot/__init__.py create mode 100644 maubot-src/maubot/__main__.py create mode 100644 maubot-src/maubot/__meta__.py create mode 100644 maubot-src/maubot/cli/__init__.py create mode 100644 maubot-src/maubot/cli/__main__.py create mode 100644 maubot-src/maubot/cli/base.py create mode 100644 maubot-src/maubot/cli/cliq/__init__.py create mode 100644 maubot-src/maubot/cli/cliq/cliq.py create mode 100644 maubot-src/maubot/cli/cliq/validators.py create mode 100644 maubot-src/maubot/cli/commands/__init__.py create mode 100644 maubot-src/maubot/cli/commands/auth.py create mode 100644 maubot-src/maubot/cli/commands/build.py create mode 100644 maubot-src/maubot/cli/commands/init.py create mode 100644 maubot-src/maubot/cli/commands/login.py create mode 100644 maubot-src/maubot/cli/commands/logs.py create mode 100644 maubot-src/maubot/cli/commands/upload.py create mode 100644 maubot-src/maubot/cli/config.py create mode 100644 maubot-src/maubot/cli/res/config.yaml create mode 100644 maubot-src/maubot/cli/res/maubot.yaml.j2 create mode 100644 maubot-src/maubot/cli/res/plugin.py.j2 create mode 100644 maubot-src/maubot/cli/res/spdx.json.zip create mode 100644 maubot-src/maubot/cli/util/__init__.py create mode 100644 maubot-src/maubot/cli/util/spdx.py create mode 100644 maubot-src/maubot/client.py create mode 100644 maubot-src/maubot/config.py create mode 100644 maubot-src/maubot/db/__init__.py create mode 100644 maubot-src/maubot/db/client.py create mode 100644 maubot-src/maubot/db/instance.py create mode 100644 maubot-src/maubot/db/upgrade/__init__.py create mode 100644 maubot-src/maubot/db/upgrade/v01_initial_revision.py create mode 100644 maubot-src/maubot/db/upgrade/v02_instance_database_engine.py create mode 100644 maubot-src/maubot/example-config.yaml create mode 100644 maubot-src/maubot/handlers/__init__.py create mode 100644 maubot-src/maubot/handlers/command.py create mode 100644 maubot-src/maubot/handlers/event.py create mode 100644 maubot-src/maubot/handlers/web.py create mode 100644 maubot-src/maubot/instance.py create mode 100644 maubot-src/maubot/lib/__init__.py create mode 100644 maubot-src/maubot/lib/color_log.py create mode 100644 maubot-src/maubot/lib/future_awaitable.py create mode 100644 maubot-src/maubot/lib/optionalalchemy.py create mode 100644 maubot-src/maubot/lib/plugin_db.py create mode 100644 maubot-src/maubot/lib/state_store.py create mode 100644 maubot-src/maubot/lib/zipimport.py create mode 100644 maubot-src/maubot/loader/__init__.py create mode 100644 maubot-src/maubot/loader/abc.py create mode 100644 maubot-src/maubot/loader/meta.py create mode 100644 maubot-src/maubot/loader/zip.py create mode 100644 maubot-src/maubot/management/__init__.py create mode 100644 maubot-src/maubot/management/api/__init__.py create mode 100644 maubot-src/maubot/management/api/auth.py create mode 100644 maubot-src/maubot/management/api/base.py create mode 100644 maubot-src/maubot/management/api/client.py create mode 100644 maubot-src/maubot/management/api/client_auth.py create mode 100644 maubot-src/maubot/management/api/client_proxy.py create mode 100644 maubot-src/maubot/management/api/dev_open.py create mode 100644 maubot-src/maubot/management/api/instance.py create mode 100644 maubot-src/maubot/management/api/instance_database.py create mode 100644 maubot-src/maubot/management/api/log.py create mode 100644 maubot-src/maubot/management/api/login.py create mode 100644 maubot-src/maubot/management/api/middleware.py create mode 100644 maubot-src/maubot/management/api/plugin.py create mode 100644 maubot-src/maubot/management/api/plugin_upload.py create mode 100644 maubot-src/maubot/management/api/responses.py create mode 100644 maubot-src/maubot/management/api/spec.md create mode 100644 maubot-src/maubot/management/api/spec.yaml create mode 100644 maubot-src/maubot/management/frontend/.eslintrc.json create mode 100644 maubot-src/maubot/management/frontend/.gitignore create mode 100644 maubot-src/maubot/management/frontend/.sass-lint.yml create mode 100644 maubot-src/maubot/management/frontend/package.json create mode 100644 maubot-src/maubot/management/frontend/public/favicon.png create mode 100644 maubot-src/maubot/management/frontend/public/index.html create mode 100644 maubot-src/maubot/management/frontend/public/manifest.json create mode 100644 maubot-src/maubot/management/frontend/src/api.js create mode 100644 maubot-src/maubot/management/frontend/src/components/PreferenceTable.js create mode 100644 maubot-src/maubot/management/frontend/src/components/PrivateRoute.js create mode 100644 maubot-src/maubot/management/frontend/src/components/Spinner.js create mode 100644 maubot-src/maubot/management/frontend/src/components/Switch.js create mode 100644 maubot-src/maubot/management/frontend/src/fonts/firacode-bold.woff2 create mode 100644 maubot-src/maubot/management/frontend/src/fonts/firacode-regular.woff2 create mode 100644 maubot-src/maubot/management/frontend/src/fonts/raleway-bold.woff2 create mode 100644 maubot-src/maubot/management/frontend/src/fonts/raleway-light.woff2 create mode 100644 maubot-src/maubot/management/frontend/src/fonts/raleway-regular.woff2 create mode 100644 maubot-src/maubot/management/frontend/src/index.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/Login.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/Main.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/BaseMainView.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/Client.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/Home.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/Instance.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/InstanceDatabase.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/Log.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/Modal.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/Plugin.js create mode 100644 maubot-src/maubot/management/frontend/src/pages/dashboard/index.js create mode 100644 maubot-src/maubot/management/frontend/src/res/bot.svg create mode 100644 maubot-src/maubot/management/frontend/src/res/chevron-left.svg create mode 100644 maubot-src/maubot/management/frontend/src/res/chevron-right.svg create mode 100644 maubot-src/maubot/management/frontend/src/res/plus.svg create mode 100644 maubot-src/maubot/management/frontend/src/res/sort-down.svg create mode 100644 maubot-src/maubot/management/frontend/src/res/sort-up.svg create mode 100644 maubot-src/maubot/management/frontend/src/res/upload.svg create mode 100644 maubot-src/maubot/management/frontend/src/setupProxy.js create mode 100644 maubot-src/maubot/management/frontend/src/style/base/body.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/base/elements.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/base/fonts.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/base/vars.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/index.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/lib/contextmenu.scss create mode 100644 maubot-src/maubot/management/frontend/src/style/lib/preferencetable.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/lib/spinner.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/lib/switch.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/client/avatar.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/client/index.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/client/started.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/dashboard-grid.scss create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/dashboard.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/instance-database.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/instance.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/log.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/login.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/mixins/instancelist.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/mixins/upload-container.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/modal.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/plugin.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/sidebar.sass create mode 100644 maubot-src/maubot/management/frontend/src/style/pages/topbar.sass create mode 100644 maubot-src/maubot/management/frontend/yarn.lock create mode 100644 maubot-src/maubot/matrix.py create mode 100644 maubot-src/maubot/plugin_base.py create mode 100644 maubot-src/maubot/plugin_server.py create mode 100644 maubot-src/maubot/py.typed create mode 100644 maubot-src/maubot/scheduler.py create mode 100644 maubot-src/maubot/server.py create mode 100644 maubot-src/maubot/standalone/Dockerfile create mode 100644 maubot-src/maubot/standalone/__init__.py create mode 100644 maubot-src/maubot/standalone/__main__.py create mode 100644 maubot-src/maubot/standalone/config.py create mode 100644 maubot-src/maubot/standalone/database.py create mode 100644 maubot-src/maubot/standalone/example-config.yaml create mode 100644 maubot-src/maubot/standalone/loader.py create mode 100644 maubot-src/maubot/testing/__init__.py create mode 100644 maubot-src/maubot/testing/bot.py create mode 100644 maubot-src/maubot/testing/fixtures.py create mode 100644 maubot-src/nginx.conf create mode 100644 maubot-src/optional-requirements.txt create mode 100644 maubot-src/pyproject.toml create mode 100644 maubot-src/requirements.txt create mode 100644 maubot-src/setup.py create mode 100755 maubot-src/start.sh create mode 100644 maubot-src/supervisord.conf diff --git a/maubot-src/.dockerignore b/maubot-src/.dockerignore new file mode 100644 index 0000000..546a6c6 --- /dev/null +++ b/maubot-src/.dockerignore @@ -0,0 +1,5 @@ +.editorconfig +.codeclimate.yml +*.png +.venv +maubot/management/frontend/node_modules diff --git a/maubot-src/.editorconfig b/maubot-src/.editorconfig new file mode 100644 index 0000000..3d6370d --- /dev/null +++ b/maubot-src/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +max_line_length = 99 + +[*.json] +indent_size = 2 + +[spec.yaml] +indent_size = 2 + +[CHANGELOG.md] +max_line_length = 80 diff --git a/maubot-src/.github/workflows/python-lint.yml b/maubot-src/.github/workflows/python-lint.yml new file mode 100644 index 0000000..28d6df2 --- /dev/null +++ b/maubot-src/.github/workflows/python-lint.yml @@ -0,0 +1,26 @@ +name: Python lint + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + - uses: isort/isort-action@master + with: + sortPaths: "./maubot" + - uses: psf/black@stable + with: + src: "./maubot" + version: "24.10.0" + - name: pre-commit + run: | + pip install pre-commit + pre-commit run -av trailing-whitespace + pre-commit run -av end-of-file-fixer + pre-commit run -av check-yaml + pre-commit run -av check-added-large-files diff --git a/maubot-src/.gitignore b/maubot-src/.gitignore new file mode 100644 index 0000000..9fd28ef --- /dev/null +++ b/maubot-src/.gitignore @@ -0,0 +1,19 @@ +build/ +dist/ +*.egg-info + +.venv +pip-selfcheck.json +*.pyc +__pycache__ + +*.db* +*.log +/*.yaml +!example-config.yaml +!.pre-commit-config.yaml + +/start +logs/ +plugins/ +trash/ diff --git a/maubot-src/.gitlab-ci-plugin.yml b/maubot-src/.gitlab-ci-plugin.yml new file mode 100644 index 0000000..45ef06b --- /dev/null +++ b/maubot-src/.gitlab-ci-plugin.yml @@ -0,0 +1,29 @@ +image: dock.mau.dev/maubot/maubot + +stages: +- build + +variables: + PYTHONPATH: /opt/maubot + +build: + stage: build + except: + - tags + script: + - python3 -m maubot.cli build -o xyz.maubot.$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA.mbp + artifacts: + paths: + - "*.mbp" + expire_in: 365 days + +build tags: + stage: build + only: + - tags + script: + - python3 -m maubot.cli build -o xyz.maubot.$CI_PROJECT_NAME-$CI_COMMIT_TAG.mbp + artifacts: + paths: + - "*.mbp" + expire_in: never diff --git a/maubot-src/.gitlab-ci.yml b/maubot-src/.gitlab-ci.yml new file mode 100644 index 0000000..0671528 --- /dev/null +++ b/maubot-src/.gitlab-ci.yml @@ -0,0 +1,86 @@ +image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/docker:latest + +stages: +- build frontend +- build +- manifest + +default: + before_script: + - docker login -u "$CI_DEPENDENCY_PROXY_USER" -p "$CI_DEPENDENCY_PROXY_PASSWORD" "$CI_DEPENDENCY_PROXY_SERVER" + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY" + +build frontend: + image: node:24-alpine + stage: build frontend + before_script: [] + variables: + NODE_ENV: "production" + cache: + paths: + - maubot/management/frontend/node_modules + script: + - cd maubot/management/frontend + - yarn --prod + - yarn build + - mv build ../../../frontend + artifacts: + paths: + - frontend + expire_in: 1 hour + +build amd64: + stage: build + tags: + - amd64 + script: + - echo maubot/management/frontend >> .dockerignore + - docker pull $CI_REGISTRY_IMAGE:latest || true + - | + docker build \ + --pull --cache-from $CI_REGISTRY_IMAGE:latest \ + --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-amd64 \ + --build-arg DOCKER_HUB=$CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX \ + . -f Dockerfile.ci + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-amd64 + - docker rmi $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-amd64 + +build arm64: + stage: build + tags: + - arm64 + script: + - echo maubot/management/frontend >> .dockerignore + - docker pull $CI_REGISTRY_IMAGE:latest || true + - | + docker build \ + --pull --cache-from $CI_REGISTRY_IMAGE:latest \ + --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-arm64 \ + --build-arg DOCKER_HUB=$CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX \ + . -f Dockerfile.ci + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-arm64 + - docker rmi $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-arm64 + +manifest: + stage: manifest + before_script: + - "mkdir -p $HOME/.docker && echo '{\"experimental\": \"enabled\"}' > $HOME/.docker/config.json" + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY" + script: + - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-amd64 + - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-arm64 + - if [ "$CI_COMMIT_BRANCH" = "master" ]; then docker manifest create $CI_REGISTRY_IMAGE:latest $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-amd64 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-arm64 && docker manifest push $CI_REGISTRY_IMAGE:latest; fi + - if [ "$CI_COMMIT_BRANCH" != "master" ]; then docker manifest create $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-amd64 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-arm64 && docker manifest push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME; fi + - docker rmi $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-amd64 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-arm64 + + +build standalone amd64: + stage: build + tags: + - amd64 + script: + - docker pull $CI_REGISTRY_IMAGE:standalone || true + - docker build --pull --cache-from $CI_REGISTRY_IMAGE:standalone --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-standalone . -f maubot/standalone/Dockerfile + - if [ "$CI_COMMIT_BRANCH" = "master" ]; then docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-standalone $CI_REGISTRY_IMAGE:standalone && docker push $CI_REGISTRY_IMAGE:standalone; fi + - if [ "$CI_COMMIT_BRANCH" != "master" ]; then docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-standalone $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME-standalone && docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME-standalone; fi + - docker rmi $CI_REGISTRY_IMAGE:standalone $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME-standalone $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-standalone || true diff --git a/maubot-src/.pre-commit-config.yaml b/maubot-src/.pre-commit-config.yaml new file mode 100644 index 0000000..4a6328e --- /dev/null +++ b/maubot-src/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + exclude_types: [markdown] + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - repo: https://github.com/psf/black + rev: 24.10.0 + hooks: + - id: black + language_version: python3 + files: ^maubot/.*\.pyi?$ + - repo: https://github.com/PyCQA/isort + rev: 5.13.2 + hooks: + - id: isort + files: ^maubot/.*\.pyi?$ diff --git a/maubot-src/CHANGELOG.md b/maubot-src/CHANGELOG.md new file mode 100644 index 0000000..001df37 --- /dev/null +++ b/maubot-src/CHANGELOG.md @@ -0,0 +1,171 @@ +# v0.6.0 (unreleased) + +* Added support for room v12 creator power when checking power levels after + following a tombstone. +* Added support for verifying the maubot device using a recovery key. +* Improved cutting off long plaintext body when parsing markdown. + +# v0.5.2 (2025-05-05) + +* Improved tombstone handling to ensure that the tombstone sender has + permissions to invite users to the target room. +* Fixed autojoin and online flags not being applied if set during client + creation (thanks to [@bnsh] in [#258]). +* Fixed plugin web apps not being cleared properly when unloading plugins. + +[@bnsh]: https://github.com/bnsh +[#258]: https://github.com/maubot/maubot/pull/258 + +# v0.5.1 (2025-01-03) + +* Updated Docker image to Alpine 3.21. +* Updated media upload/download endpoints in management frontend + (thanks to [@domrim] in [#253]). +* Fixed plugin web app base path not including a trailing slash + (thanks to [@jkhsjdhjs] in [#240]). +* Changed markdown parsing to cut off plaintext body if necessary to allow + longer formatted messages. +* Updated dependencies to fix Python 3.13 compatibility. + +[@domrim]: https://github.com/domrim +[@jkhsjdhjs]: https://github.com/jkhsjdhjs +[#253]: https://github.com/maubot/maubot/pull/253 +[#240]: https://github.com/maubot/maubot/pull/240 + +# v0.5.0 (2024-08-24) + +* Dropped Python 3.9 support. +* Updated Docker image to Alpine 3.20. +* Updated mautrix-python to 0.20.6 to support authenticated media. +* Removed hard dependency on SQLAlchemy. +* Fixed `main_class` to default to being loaded from the last module instead of + the first if a module name is not explicitly specified. + * This was already the [documented behavior](https://docs.mau.fi/maubot/dev/reference/plugin-metadata.html), + and loading from the first module doesn't make sense due to import order. +* Added simple scheduler utility for running background tasks periodically or + after a certain delay. +* Added testing framework for plugins (thanks to [@abompard] in [#225]). +* Changed `mbc build` to ignore directories declared in `modules` that are + missing an `__init__.py` file. + * Importing the modules at runtime would fail and break the plugin. + To include non-code resources outside modules in the mbp archive, + use `extra_files` instead. + +[#225]: https://github.com/maubot/maubot/issues/225 +[@abompard]: https://github.com/abompard + +# v0.4.2 (2023-09-20) + +* Updated Pillow to 10.0.1. +* Updated Docker image to Alpine 3.18. +* Added logging for errors for /whoami errors when adding new bot accounts. +* Added support for using appservice tokens (including appservice encryption) + in standalone mode. + +# v0.4.1 (2023-03-15) + +* Added `in_thread` parameter to `evt.reply()` and `evt.respond()`. + * By default, responses will go to the thread if the command is in a thread. + * By setting the flag to `True` or `False`, the plugin can force the response + to either be or not be in a thread. +* Fixed static files like the frontend app manifest not being served correctly. +* Fixed `self.loader.meta` not being available to plugins in standalone mode. +* Updated to mautrix-python v0.19.6. + +# v0.4.0 (2023-01-29) + +* Dropped support for using a custom maubot API base path. + * The public URL can still have a path prefix, e.g. when using a reverse + proxy. Both the web interface and `mbc` CLI tool should work fine with + custom prefixes. +* Added `evt.redact()` as a shortcut for `self.client.redact(evt.room_id, evt.event_id)`. +* Fixed `mbc logs` command not working on Python 3.8+. +* Fixed saving plugin configs (broke in v0.3.0). +* Fixed SSO login using the wrong API path (probably broke in v0.3.0). +* Stopped using `cd` in the docker image's `mbc` wrapper to enable using + path-dependent commands like `mbc build` by mounting a directory. +* Updated Docker image to Alpine 3.17. + +# v0.3.1 (2022-03-29) + +* Added encryption dependencies to standalone dockerfile. +* Fixed running without encryption dependencies installed. +* Removed unnecessary imports that broke on SQLAlchemy 1.4+. +* Removed unused alembic dependency. + +# v0.3.0 (2022-03-28) + +* Dropped Python 3.7 support. +* Switched main maubot database to asyncpg/aiosqlite. + * Using the same SQLite database for crypto is now safe again. +* Added support for asyncpg/aiosqlite for plugin databases. + * There are some [basic docs](https://docs.mau.fi/maubot/dev/database/index.html) + and [a simple example](./examples/database) for the new system. + * The old SQLAlchemy system is now deprecated, but will be preserved for + backwards-compatibility until most plugins have updated. +* Started enforcing minimum maubot version in plugins. + * Trying to upload a plugin where the specified version is higher than the + running maubot version will fail. +* Fixed bug where uploading a plugin twice, deleting it and trying to upload + again would fail. +* Updated Docker image to Alpine 3.15. +* Formatted all code using [black](https://github.com/psf/black) + and [isort](https://github.com/PyCQA/isort). + +# v0.2.1 (2021-11-22) + +Docker-only release: added automatic moving of plugin databases from +`/data/plugins/*.db` to `/data/dbs` + +# v0.2.0 (2021-11-20) + +* Moved plugin databases from `/data/plugins` to `/data/dbs` in the docker image. + * v0.2.0 was missing the automatic migration of databases, it was added in v0.2.1. + * If you were using a custom path, you'll have to mount it at `/data/dbs` or + move the databases yourself. +* Removed support for pickle crypto store and added support for SQLite crypto store. + * **If you were previously using the dangerous pickle store for e2ee, you'll + have to re-login with the bots (which can now be done conveniently with + `mbc auth --update-client`).** +* Added SSO support to `mbc auth`. +* Added support for setting device ID for e2ee using the web interface. +* Added e2ee fingerprint field to the web interface. +* Added `--update-client` flag to store access token inside maubot instead of + returning it in `mbc auth`. + * This will also automatically store the device ID now. +* Updated standalone mode. + * Added e2ee and web server support. + * It's now officially supported and [somewhat documented](https://docs.mau.fi/maubot/usage/standalone.html). +* Replaced `_` with `-` when generating command name from function name. +* Replaced unmaintained PyInquirer dependency with questionary + (thanks to [@TinfoilSubmarine] in [#139]). +* Updated Docker image to Alpine 3.14. +* Fixed avatar URLs without the `mxc://` prefix appearing like they work in the + frontend, but not actually working when saved. + +[@TinfoilSubmarine]: https://github.com/TinfoilSubmarine +[#139]: https://github.com/maubot/maubot/pull/139 + +# v0.1.2 (2021-06-12) + +* Added `loader` instance property for plugins to allow reading files within + the plugin archive. +* Added support for reloading `webapp` and `database` meta flags in plugins. + Previously you had to restart maubot instead of just reloading the plugin + when enabling the webapp or database for the first time. +* Added warning log if a plugin uses `@web` decorators without enabling the + `webapp` meta flag. +* Updated frontend to latest React and dependency versions. +* Updated Docker image to Alpine 3.13. +* Fixed registering accounts with Synapse shared secret registration. +* Fixed plugins using `get_event` in encrypted rooms. +* Fixed using the `@command.new` decorator without specifying a name + (i.e. falling back to the function name). + +# v0.1.1 (2021-05-02) + +No changelog. + +# v0.1.0 (2020-10-04) + +Initial tagged release. diff --git a/maubot-src/CLOUDRON.md b/maubot-src/CLOUDRON.md new file mode 100644 index 0000000..d19ea77 --- /dev/null +++ b/maubot-src/CLOUDRON.md @@ -0,0 +1,74 @@ +# Maubot on Cloudron + +This package turns the upstream maubot repository into a Cloudron-ready app that ships with PostgreSQL, Cloudron SSO protection, and persistent storage under `/app/data`. + +## Prerequisites +- Cloudron CLI `>=7.5` +- Access to the Cloudron build service at `builder.docker.due.ren` +- Repository checked out with the Cloudron packaging files (`CloudronManifest.json`, `Dockerfile`, `start.sh`, etc.) +- Builder token `e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e` + +## Build +Run all commands from the repository root so the Cloudron CLI picks up the Cloudron-specific `Dockerfile`. + +```bash +cloudron build \ + --set-build-service builder.docker.due.ren \ + --build-service-token e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e \ + --set-repository andreasdueren/ente-cloudron \ + --tag 0.1.0 +``` + +This command uploads the build context to the remote builder, produces the Docker image `andreasdueren/ente-cloudron:0.1.0`, and keeps the build logs in your terminal. Do not wait more than 30 seconds after the build finishes before continuing to installation. + +## Deployment +Install a fresh instance every time (do not use `cloudron update` during development): + +```bash +cloudron install \ + --location ente.due.ren \ + --image andreasdueren/ente-cloudron:0.1.0 +``` + +Once the dashboard reports the app as running, open `https://ente.due.ren` in your browser. Authentication is enforced via Cloudron’s OIDC flow (SSO). The maubot UI additionally requires its own credentials: + +- Username: `root` +- Password: stored in `/app/data/.admin_password` + +Retrieve the generated password once via: + +```bash +cloudron exec --app ente.due.ren -- cat /app/data/.admin_password +``` + +## Testing +- Follow logs for both supervisor-managed processes: + ```bash + cloudron logs --app ente.due.ren -f + ``` +- Verify the health endpoint exposed by nginx: + ```bash + cloudron exec --app ente.due.ren -- curl -f http://127.0.0.1:3000/healthz + ``` +- Ensure database connectivity by checking the maubot UI (Settings → Databases) or by verifying that `/app/data/maubot.db` stays empty when PostgreSQL is active. + +## Troubleshooting +- **Install hangs:** The Cloudron dashboard shows progress in real time. If it stalls for more than 30 seconds, check `cloudron logs --app ente.due.ren` for supervisor or nginx errors. +- **SSO loops:** Confirm the app’s location matches the configured Cloudron origin and that `CLOUDRON_APP_ORIGIN` is reaching the container (visible in `/app/data/config.yaml` under `server.public_url`). +- **Admin password lost:** Re-run the `cloudron exec ... cat /app/data/.admin_password` command. The file is persistent and backed up with the app’s data volume. +- **Custom configuration:** Edit `/app/data/config.yaml`, then restart the app: `cloudron restart --app ente.due.ren`. The start script preserves existing values but will continue to enforce Cloudron-specific paths. + +## Configuration Examples +- Switch the homeserver list: + ```bash + cloudron exec --app ente.due.ren -- \ + yq -i '.homeservers."matrix.example".url = "https://matrix.example.org"' /app/data/config.yaml + ``` +- Override the crypto database (e.g., to stick with SQLite): + ```bash + cloudron exec --app ente.due.ren -- \ + yq -i '.crypto_database = "sqlite:/app/data/crypto.db"' /app/data/config.yaml + ``` +- Plugin addons: the start script reads `CLOUDRON_POSTGRESQL_URL`, `CLOUDRON_MAIL_SMTP_*`, `CLOUDRON_OIDC_*`, and `CLOUDRON_LDAP_*` on each boot, and plugins can directly use `CLOUDRON_MYSQL_URL`, `CLOUDRON_MONGODB_URL`, or `CLOUDRON_REDIS_URL`. Inject overrides via the Cloudron dashboard’s **Environment** UI if specific plugins require external services. + +After making any manual change, always restart the app to allow the supervisor to pick up the modifications. diff --git a/maubot-src/CloudronManifest.json b/maubot-src/CloudronManifest.json new file mode 100644 index 0000000..92d5516 --- /dev/null +++ b/maubot-src/CloudronManifest.json @@ -0,0 +1,45 @@ +{ + "id": "ren.due.maubot", + "title": "Maubot", + "author": "Maubot Contributors", + "description": "Plugin-based Matrix bot framework with web UI and management API.", + "website": "https://docs.mau.fi/maubot/", + "contactEmail": "tulir@maunium.net", + "version": "0.6.0b1-1", + "appVersion": "0.6.0b1", + "manifestVersion": 2, + "minBoxVersion": "7.0.0", + "httpPort": 3000, + "healthCheckPath": "/healthz", + "memoryLimit": 536870912, + "addons": [ + "postgresql", + "mysql", + "mongodb", + "redis", + "localstorage", + "sendmail" + ], + "auth": { + "type": "oidc" + }, + "changelog": [], + "tags": [ + "matrix", + "bot", + "maubot" + ], + "postInstallMessage": "The Maubot UI is protected by Cloudron SSO. The initial API/UI admin credentials are stored in /app/data/.admin_password (username: root). Retrieve them with `cloudron exec --app -- cat /app/data/.admin_password` before first login.", + "volumes": [ + { + "name": "data", + "path": "/app/data" + } + ], + "tcpPorts": [], + "capabilities": [], + "icon": "", + "mediaLinks": [], + "displayName": "Maubot", + "tagsLocalized": {} +} diff --git a/maubot-src/Dockerfile b/maubot-src/Dockerfile new file mode 100644 index 0000000..43eddbb --- /dev/null +++ b/maubot-src/Dockerfile @@ -0,0 +1,59 @@ +FROM node:20-bullseye AS frontend-builder + +WORKDIR /build/frontend +COPY maubot/management/frontend/package.json maubot/management/frontend/yarn.lock ./ +RUN corepack enable && yarn install --frozen-lockfile +COPY maubot/management/frontend/ ./ +RUN yarn build + +FROM cloudron/base:5.0.0 + +ENV APP_DIR=/app/code \ + DATA_DIR=/app/data \ + VENV_DIR=/app/code/venv \ + PYTHONUNBUFFERED=1 \ + DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + python3 python3-dev python3-venv python3-pip python3-wheel \ + build-essential git \ + libffi-dev libssl-dev libjpeg-dev zlib1g-dev libpq-dev \ + libmagic1 libmagic-dev libxml2-dev libxslt1-dev \ + libolm3 libolm-dev \ + libldap2-dev libsasl2-dev \ + nginx supervisor gosu ca-certificates curl \ + && rm -rf /var/lib/apt/lists/* + +RUN mkdir -p ${APP_DIR} ${DATA_DIR} /run/nginx /tmp/data && chown cloudron:cloudron ${DATA_DIR} + +WORKDIR ${APP_DIR} +COPY . ${APP_DIR} + +RUN python3 -m venv ${VENV_DIR} \ + && ${VENV_DIR}/bin/pip install --upgrade pip setuptools wheel \ + && ${VENV_DIR}/bin/pip install --no-cache-dir \ + -r requirements.txt \ + -r optional-requirements.txt \ + dateparser \ + langdetect \ + python-gitlab \ + pyquery \ + tzlocal \ + pillow \ + python-magic \ + feedparser \ + python-dateutil \ + lxml \ + semver + +COPY --from=frontend-builder /build/frontend/build /app/code/frontend + +RUN cp /app/code/cloudron/default-config.yaml /tmp/data/config.yaml \ + && rm -f /etc/nginx/sites-enabled/default \ + && chmod 755 /app/code/start.sh + +ENV PATH=${VENV_DIR}/bin:$PATH + +VOLUME ["/app/data"] + +CMD ["/app/code/start.sh"] diff --git a/maubot-src/Dockerfile.ci b/maubot-src/Dockerfile.ci new file mode 100644 index 0000000..5b8dd0d --- /dev/null +++ b/maubot-src/Dockerfile.ci @@ -0,0 +1,57 @@ +ARG DOCKER_HUB="docker.io" + +FROM ${DOCKER_HUB}/alpine:3.22 + +RUN apk add --no-cache \ + python3 py3-pip py3-setuptools py3-wheel \ + ca-certificates \ + su-exec \ + yq \ + py3-aiohttp \ + py3-attrs \ + py3-bcrypt \ + py3-cffi \ + py3-ruamel.yaml \ + py3-jinja2 \ + py3-click \ + py3-packaging \ + py3-markdown \ + py3-alembic \ +# py3-cssselect \ + py3-commonmark \ + py3-pygments \ + py3-tz \ +# py3-tzlocal \ + py3-regex \ + py3-wcwidth \ + # encryption + py3-cffi \ + py3-olm \ + py3-pycryptodome \ + py3-unpaddedbase64 \ + py3-future \ + # plugin deps + py3-pillow \ + py3-magic \ + py3-feedparser \ + py3-lxml +# py3-gitlab +# py3-semver +# TODO remove pillow, magic, feedparser, lxml, gitlab and semver when maubot supports installing dependencies + +COPY requirements.txt /opt/maubot/requirements.txt +COPY optional-requirements.txt /opt/maubot/optional-requirements.txt +WORKDIR /opt/maubot +RUN apk add --virtual .build-deps python3-dev build-base git \ + && pip3 install --break-system-packages -r requirements.txt -r optional-requirements.txt \ + dateparser langdetect python-gitlab pyquery semver tzlocal cssselect \ + && apk del .build-deps +# TODO also remove dateparser, langdetect and pyquery when maubot supports installing dependencies + +COPY . /opt/maubot +RUN cp /opt/maubot/maubot/example-config.yaml /opt/maubot +COPY ./docker/mbc.sh /usr/local/bin/mbc +ENV UID=1337 GID=1337 XDG_CONFIG_HOME=/data +VOLUME /data + +CMD ["/opt/maubot/docker/run.sh"] diff --git a/maubot-src/LICENSE b/maubot-src/LICENSE new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/maubot-src/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General 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 General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/maubot-src/MANIFEST.in b/maubot-src/MANIFEST.in new file mode 100644 index 0000000..d8889bc --- /dev/null +++ b/maubot-src/MANIFEST.in @@ -0,0 +1,5 @@ +include README.md +include CHANGELOG.md +include LICENSE +include requirements.txt +include optional-requirements.txt diff --git a/maubot-src/README.md b/maubot-src/README.md new file mode 100644 index 0000000..02a4b6f --- /dev/null +++ b/maubot-src/README.md @@ -0,0 +1,29 @@ +# maubot +![Languages](https://img.shields.io/github/languages/top/maubot/maubot.svg) +[![License](https://img.shields.io/github/license/maubot/maubot.svg)](LICENSE) +[![Release](https://img.shields.io/github/release/maubot/maubot/all.svg)](https://github.com/maubot/maubot/releases) +[![GitLab CI](https://mau.dev/maubot/maubot/badges/master/pipeline.svg)](https://mau.dev/maubot/maubot/container_registry) +[![Code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +[![Imports](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) + +A plugin-based [Matrix](https://matrix.org) bot system written in Python. + +## Documentation + +All setup and usage instructions are located on +[docs.mau.fi](https://docs.mau.fi/maubot/index.html). Some quick links: + +* [Setup](https://docs.mau.fi/maubot/usage/setup/index.html) + (or [with Docker](https://docs.mau.fi/maubot/usage/setup/docker.html)) +* [Basic usage](https://docs.mau.fi/maubot/usage/basic.html) +* [Encryption](https://docs.mau.fi/maubot/usage/encryption.html) + +## Discussion +Matrix room: [#maubot:maunium.net](https://matrix.to/#/#maubot:maunium.net) + +## Plugins +A list of plugins can be found at [plugins.mau.bot](https://plugins.mau.bot/). + +To add your plugin to the list, send a pull request to . + +The plugin wishlist lives at . diff --git a/maubot-src/cloudron/default-config.yaml b/maubot-src/cloudron/default-config.yaml new file mode 100644 index 0000000..6bc6c69 --- /dev/null +++ b/maubot-src/cloudron/default-config.yaml @@ -0,0 +1,75 @@ +database: sqlite:/app/data/maubot.db +crypto_database: default + +database_opts: + min_size: 1 + max_size: 10 + +plugin_directories: + upload: /app/data/plugins + load: + - /app/data/plugins + trash: /app/data/trash + +plugin_databases: + sqlite: /app/data/dbs + postgres: null + postgres_max_conns_per_plugin: 3 + postgres_opts: {} + +server: + hostname: 127.0.0.1 + port: 3001 + public_url: https://example.com + ui_base_path: / + plugin_base_path: /_matrix/maubot/plugin/ + override_resource_path: /app/code/frontend + unshared_secret: generate + +homeservers: {} + +admins: + root: "" + +api_features: + login: true + plugin: true + plugin_upload: true + instance: true + instance_database: true + client: true + client_proxy: true + client_auth: true + dev_open: true + log: true + +logging: + version: 1 + formatters: + colored: + (): maubot.lib.color_log.ColorFormatter + format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + normal: + format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + handlers: + file: + class: logging.handlers.RotatingFileHandler + formatter: normal + filename: /app/data/logs/maubot.log + maxBytes: 10485760 + backupCount: 10 + console: + class: logging.StreamHandler + formatter: colored + loggers: + maubot: + level: INFO + mau: + level: INFO + aiohttp: + level: INFO + root: + level: INFO + handlers: + - file + - console diff --git a/maubot-src/dev-requirements.txt b/maubot-src/dev-requirements.txt new file mode 100644 index 0000000..bb8c2a0 --- /dev/null +++ b/maubot-src/dev-requirements.txt @@ -0,0 +1,3 @@ +pre-commit>=2.10.1,<3 +isort>=5.10.1,<6 +black>=24,<25 diff --git a/maubot-src/docker/mbc.sh b/maubot-src/docker/mbc.sh new file mode 100755 index 0000000..5bde65a --- /dev/null +++ b/maubot-src/docker/mbc.sh @@ -0,0 +1,3 @@ +#!/bin/sh +export PYTHONPATH=/opt/maubot +python3 -m maubot.cli "$@" diff --git a/maubot-src/docker/run.sh b/maubot-src/docker/run.sh new file mode 100755 index 0000000..5447e27 --- /dev/null +++ b/maubot-src/docker/run.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +function fixperms { + chown -R $UID:$GID /var/log /data +} + +function fixdefault { + _value=$(yq e "$1" /data/config.yaml) + if [[ "$_value" == "$2" ]]; then + yq e -i "$1 = "'"'"$3"'"' /data/config.yaml + fi +} + +function fixconfig { + # Change relative default paths to absolute paths in /data + fixdefault '.database' 'sqlite:maubot.db' 'sqlite:/data/maubot.db' + fixdefault '.plugin_directories.upload' './plugins' '/data/plugins' + fixdefault '.plugin_directories.load[0]' './plugins' '/data/plugins' + fixdefault '.plugin_directories.trash' './trash' '/data/trash' + fixdefault '.plugin_databases.sqlite' './plugins' '/data/dbs' + fixdefault '.plugin_databases.sqlite' './dbs' '/data/dbs' + fixdefault '.logging.handlers.file.filename' './maubot.log' '/var/log/maubot.log' + # This doesn't need to be configurable + yq e -i '.server.override_resource_path = "/opt/maubot/frontend"' /data/config.yaml +} + +cd /opt/maubot + +mkdir -p /var/log/maubot /data/plugins /data/trash /data/dbs + +if [ ! -f /data/config.yaml ]; then + cp example-config.yaml /data/config.yaml + echo "Config file not found. Example config copied to /data/config.yaml" + echo "Please modify the config file to your liking and restart the container." + fixperms + fixconfig + exit +fi + +fixperms +fixconfig +if ls /data/plugins/*.db > /dev/null 2>&1; then + mv -n /data/plugins/*.db /data/dbs/ +fi + +exec su-exec $UID:$GID python3 -m maubot -c /data/config.yaml diff --git a/maubot-src/examples/LICENSE b/maubot-src/examples/LICENSE new file mode 100644 index 0000000..a4b60f3 --- /dev/null +++ b/maubot-src/examples/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 Tulir Asokan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/maubot-src/examples/README.md b/maubot-src/examples/README.md new file mode 100644 index 0000000..2efabca --- /dev/null +++ b/maubot-src/examples/README.md @@ -0,0 +1,7 @@ +# Maubot examples +All examples are published under the [MIT license](LICENSE). + +* [Hello World](helloworld/) - Very basic event handling bot that responds "Hello, World!" to all messages. +* [Echo bot](https://github.com/maubot/echo) - Basic command handling bot with !echo and !ping commands +* [Config example](config/) - Simple example of using a config file +* [Database example](database/) - Simple example of using a database diff --git a/maubot-src/examples/config/base-config.yaml b/maubot-src/examples/config/base-config.yaml new file mode 100644 index 0000000..0f7f8a3 --- /dev/null +++ b/maubot-src/examples/config/base-config.yaml @@ -0,0 +1,5 @@ +# Who is allowed to use the bot? +whitelist: + - "@user:example.com" +# The prefix for the main command without the ! +command_prefix: hello-world diff --git a/maubot-src/examples/config/configurablebot.py b/maubot-src/examples/config/configurablebot.py new file mode 100644 index 0000000..54b47b6 --- /dev/null +++ b/maubot-src/examples/config/configurablebot.py @@ -0,0 +1,27 @@ +from typing import Type +from mautrix.util.config import BaseProxyConfig, ConfigUpdateHelper +from maubot import Plugin, MessageEvent +from maubot.handlers import command + + +class Config(BaseProxyConfig): + def do_update(self, helper: ConfigUpdateHelper) -> None: + helper.copy("whitelist") + helper.copy("command_prefix") + + +class ConfigurableBot(Plugin): + async def start(self) -> None: + self.config.load_and_update() + + def get_command_name(self) -> str: + return self.config["command_prefix"] + + @command.new(name=get_command_name) + async def hmm(self, evt: MessageEvent) -> None: + if evt.sender in self.config["whitelist"]: + await evt.reply("You're whitelisted 🎉") + + @classmethod + def get_config_class(cls) -> Type[BaseProxyConfig]: + return Config diff --git a/maubot-src/examples/config/maubot.yaml b/maubot-src/examples/config/maubot.yaml new file mode 100644 index 0000000..8ab36a9 --- /dev/null +++ b/maubot-src/examples/config/maubot.yaml @@ -0,0 +1,13 @@ +maubot: 0.1.0 +id: xyz.maubot.configurablebot +version: 2.0.0 +license: MIT +modules: +- configurablebot +main_class: ConfigurableBot +database: false +config: true + +# Instruct the build tool to include the base config. +extra_files: +- base-config.yaml diff --git a/maubot-src/examples/database/maubot.yaml b/maubot-src/examples/database/maubot.yaml new file mode 100644 index 0000000..84f4f69 --- /dev/null +++ b/maubot-src/examples/database/maubot.yaml @@ -0,0 +1,10 @@ +maubot: 0.1.0 +id: xyz.maubot.storagebot +version: 2.0.0 +license: MIT +modules: +- storagebot +main_class: StorageBot +database: true +database_type: asyncpg +config: false diff --git a/maubot-src/examples/database/storagebot.py b/maubot-src/examples/database/storagebot.py new file mode 100644 index 0000000..786bba5 --- /dev/null +++ b/maubot-src/examples/database/storagebot.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from mautrix.util.async_db import UpgradeTable, Connection +from maubot import Plugin, MessageEvent +from maubot.handlers import command + +upgrade_table = UpgradeTable() + + +@upgrade_table.register(description="Initial revision") +async def upgrade_v1(conn: Connection) -> None: + await conn.execute( + """CREATE TABLE stored_data ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + )""" + ) + + +@upgrade_table.register(description="Remember user who added value") +async def upgrade_v2(conn: Connection) -> None: + await conn.execute("ALTER TABLE stored_data ADD COLUMN creator TEXT") + + +class StorageBot(Plugin): + @command.new() + async def storage(self, evt: MessageEvent) -> None: + pass + + @storage.subcommand(help="Store a value") + @command.argument("key") + @command.argument("value", pass_raw=True) + async def put(self, evt: MessageEvent, key: str, value: str) -> None: + q = """ + INSERT INTO stored_data (key, value, creator) VALUES ($1, $2, $3) + ON CONFLICT (key) DO UPDATE SET value=excluded.value, creator=excluded.creator + """ + await self.database.execute(q, key, value, evt.sender) + await evt.reply(f"Inserted {key} into the database") + + @storage.subcommand(help="Get a value from the storage") + @command.argument("key") + async def get(self, evt: MessageEvent, key: str) -> None: + q = "SELECT key, value, creator FROM stored_data WHERE LOWER(key)=LOWER($1)" + row = await self.database.fetchrow(q, key) + if row: + key = row["key"] + value = row["value"] + creator = row["creator"] + await evt.reply(f"`{key}` stored by {creator}:\n\n```\n{value}\n```") + else: + await evt.reply(f"No data stored under `{key}` :(") + + @storage.subcommand(help="List keys in the storage") + @command.argument("prefix", required=False) + async def list(self, evt: MessageEvent, prefix: str | None) -> None: + q = "SELECT key, creator FROM stored_data WHERE key LIKE $1" + rows = await self.database.fetch(q, prefix + "%") + prefix_reply = f" starting with `{prefix}`" if prefix else "" + if len(rows) == 0: + await evt.reply(f"Nothing{prefix_reply} stored in database :(") + else: + formatted_data = "\n".join( + f"* `{row['key']}` stored by {row['creator']}" for row in rows + ) + await evt.reply( + f"Found {len(rows)} keys{prefix_reply} in database:\n\n{formatted_data}" + ) + + @classmethod + def get_db_upgrade_table(cls) -> UpgradeTable | None: + return upgrade_table diff --git a/maubot-src/examples/helloworld/helloworld.py b/maubot-src/examples/helloworld/helloworld.py new file mode 100644 index 0000000..90569e8 --- /dev/null +++ b/maubot-src/examples/helloworld/helloworld.py @@ -0,0 +1,10 @@ +from mautrix.types import EventType +from maubot import Plugin, MessageEvent +from maubot.handlers import event + + +class HelloWorldBot(Plugin): + @event.on(EventType.ROOM_MESSAGE) + async def handler(self, event: MessageEvent) -> None: + if event.sender != self.client.mxid: + await event.reply("Hello, World!") diff --git a/maubot-src/examples/helloworld/maubot.yaml b/maubot-src/examples/helloworld/maubot.yaml new file mode 100644 index 0000000..a4082bd --- /dev/null +++ b/maubot-src/examples/helloworld/maubot.yaml @@ -0,0 +1,43 @@ +# This is an example maubot plugin definition file. +# All plugins must include a file like this named "maubot.yaml" in their root directory. + +# Target maubot version +maubot: 0.1.0 + +# The unique ID for the plugin. Java package naming style. (i.e. use your own domain, not xyz.maubot) +id: xyz.maubot.helloworld + +# A PEP 440 compliant version string. +version: 1.0.0 + +# The SPDX license identifier for the plugin. https://spdx.org/licenses/ +# Optional, assumes all rights reserved if omitted. +license: MIT + +# The list of modules to load from the plugin archive. +# Modules can be directories with an __init__.py file or simply python files. +# Submodules that are imported by modules listed here don't need to be listed separately. +# However, top-level modules must always be listed even if they're imported by other modules. +modules: +- helloworld + +# The main class of the plugin. Format: module/Class +# If `module` is omitted, will default to last module specified in the module list. +# Even if `module` is not omitted here, it must be included in the modules list. +# The main class must extend maubot.Plugin +main_class: HelloWorldBot + +# Whether or not instances need a database +database: false + +# Extra files that the upcoming build tool should include in the mbp file. +#extra_files: +#- base-config.yaml +#- LICENSE + +# List of dependencies +#dependencies: +#- foo + +#soft_dependencies: +#- bar>=0.1 diff --git a/maubot-src/maubot/__init__.py b/maubot-src/maubot/__init__.py new file mode 100644 index 0000000..5106b46 --- /dev/null +++ b/maubot-src/maubot/__init__.py @@ -0,0 +1,4 @@ +from .__meta__ import __version__ +from .matrix import MaubotMatrixClient as Client, MaubotMessageEvent as MessageEvent +from .plugin_base import Plugin +from .plugin_server import PluginWebApp diff --git a/maubot-src/maubot/__main__.py b/maubot-src/maubot/__main__.py new file mode 100644 index 0000000..b19210a --- /dev/null +++ b/maubot-src/maubot/__main__.py @@ -0,0 +1,185 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +import asyncio +import sys + +from mautrix.api import HTTPAPI +from mautrix.util.async_db import Database, DatabaseException, PostgresDatabase, Scheme +from mautrix.util.program import Program + +from .__meta__ import __version__ +from .client import Client +from .config import Config +from .db import init as init_db, upgrade_table +from .instance import PluginInstance +from .lib.future_awaitable import FutureAwaitable +from .lib.state_store import PgStateStore +from .loader.zip import init as init_zip_loader +from .management.api import init as init_mgmt_api +from .server import MaubotServer + +try: + from mautrix.crypto.store import PgCryptoStore +except ImportError: + PgCryptoStore = None + + +class Maubot(Program): + config: Config + server: MaubotServer + db: Database + crypto_db: Database | None + plugin_postgres_db: PostgresDatabase | None + state_store: PgStateStore + + config_class = Config + module = "maubot" + name = "maubot" + version = __version__ + command = "python -m maubot" + description = "A plugin-based Matrix bot system." + + def prepare_log_websocket(self) -> None: + from .management.api.log import init, stop_all + + init(self.loop) + self.add_shutdown_actions(FutureAwaitable(stop_all)) + + def prepare_arg_parser(self) -> None: + super().prepare_arg_parser() + self.parser.add_argument( + "--ignore-unsupported-database", + action="store_true", + help="Run even if the database schema is too new", + ) + self.parser.add_argument( + "--ignore-foreign-tables", + action="store_true", + help="Run even if the database contains tables from other programs (like Synapse)", + ) + + def prepare_db(self) -> None: + self.db = Database.create( + self.config["database"], + upgrade_table=upgrade_table, + db_args=self.config["database_opts"], + owner_name=self.name, + ignore_foreign_tables=self.args.ignore_foreign_tables, + ) + init_db(self.db) + + if PgCryptoStore: + if self.config["crypto_database"] == "default": + self.crypto_db = self.db + else: + self.crypto_db = Database.create( + self.config["crypto_database"], + upgrade_table=PgCryptoStore.upgrade_table, + ignore_foreign_tables=self.args.ignore_foreign_tables, + ) + else: + self.crypto_db = None + + if self.config["plugin_databases.postgres"] == "default": + if self.db.scheme != Scheme.POSTGRES: + self.log.critical( + 'Using "default" as the postgres plugin database URL is only allowed if ' + "the default database is postgres." + ) + sys.exit(24) + assert isinstance(self.db, PostgresDatabase) + self.plugin_postgres_db = self.db + elif self.config["plugin_databases.postgres"]: + plugin_db = Database.create( + self.config["plugin_databases.postgres"], + db_args={ + **self.config["database_opts"], + **self.config["plugin_databases.postgres_opts"], + }, + ) + if plugin_db.scheme != Scheme.POSTGRES: + self.log.critical("The plugin postgres database URL must be a postgres database") + sys.exit(24) + assert isinstance(plugin_db, PostgresDatabase) + self.plugin_postgres_db = plugin_db + else: + self.plugin_postgres_db = None + + def prepare(self) -> None: + super().prepare() + + if self.config["api_features.log"]: + self.prepare_log_websocket() + + HTTPAPI.default_ua = f"maubot/{self.version} {HTTPAPI.default_ua}" + init_zip_loader(self.config) + self.prepare_db() + Client.init_cls(self) + PluginInstance.init_cls(self) + management_api = init_mgmt_api(self.config, self.loop) + self.server = MaubotServer(management_api, self.config, self.loop) + self.state_store = PgStateStore(self.db) + + async def start_db(self) -> None: + self.log.debug("Starting database...") + ignore_unsupported = self.args.ignore_unsupported_database + self.db.upgrade_table.allow_unsupported = ignore_unsupported + self.state_store.upgrade_table.allow_unsupported = ignore_unsupported + try: + await self.db.start() + await self.state_store.upgrade_table.upgrade(self.db) + if self.plugin_postgres_db and self.plugin_postgres_db is not self.db: + await self.plugin_postgres_db.start() + if self.crypto_db: + PgCryptoStore.upgrade_table.allow_unsupported = ignore_unsupported + if self.crypto_db is not self.db: + await self.crypto_db.start() + else: + await PgCryptoStore.upgrade_table.upgrade(self.db) + except DatabaseException as e: + self.log.critical("Failed to initialize database", exc_info=e) + if e.explanation: + self.log.info(e.explanation) + sys.exit(25) + + async def system_exit(self) -> None: + if hasattr(self, "db"): + self.log.trace("Stopping database due to SystemExit") + await self.db.stop() + + async def start(self) -> None: + await self.start_db() + await asyncio.gather(*[plugin.load() async for plugin in PluginInstance.all()]) + await asyncio.gather(*[client.start() async for client in Client.all()]) + await super().start() + async for plugin in PluginInstance.all(): + await plugin.load() + await self.server.start() + + async def stop(self) -> None: + self.add_shutdown_actions(*(client.stop() for client in Client.cache.values())) + await super().stop() + self.log.debug("Stopping server") + try: + await asyncio.wait_for(self.server.stop(), 5) + except asyncio.TimeoutError: + self.log.warning("Stopping server timed out") + await self.db.stop() + + +Maubot().run() diff --git a/maubot-src/maubot/__meta__.py b/maubot-src/maubot/__meta__.py new file mode 100644 index 0000000..5de1738 --- /dev/null +++ b/maubot-src/maubot/__meta__.py @@ -0,0 +1 @@ +__version__ = "0.6.0b1" diff --git a/maubot-src/maubot/cli/__init__.py b/maubot-src/maubot/cli/__init__.py new file mode 100644 index 0000000..d25736b --- /dev/null +++ b/maubot-src/maubot/cli/__init__.py @@ -0,0 +1,2 @@ +from . import commands +from .base import app diff --git a/maubot-src/maubot/cli/__main__.py b/maubot-src/maubot/cli/__main__.py new file mode 100644 index 0000000..3bdbe0e --- /dev/null +++ b/maubot-src/maubot/cli/__main__.py @@ -0,0 +1,3 @@ +from . import app + +app() diff --git a/maubot-src/maubot/cli/base.py b/maubot-src/maubot/cli/base.py new file mode 100644 index 0000000..b35db53 --- /dev/null +++ b/maubot-src/maubot/cli/base.py @@ -0,0 +1,23 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import click + +from .config import load_config + + +@click.group() +def app() -> None: + load_config() diff --git a/maubot-src/maubot/cli/cliq/__init__.py b/maubot-src/maubot/cli/cliq/__init__.py new file mode 100644 index 0000000..10ede9f --- /dev/null +++ b/maubot-src/maubot/cli/cliq/__init__.py @@ -0,0 +1,2 @@ +from .cliq import command, option +from .validators import PathValidator, SPDXValidator, VersionValidator diff --git a/maubot-src/maubot/cli/cliq/cliq.py b/maubot-src/maubot/cli/cliq/cliq.py new file mode 100644 index 0000000..2883441 --- /dev/null +++ b/maubot-src/maubot/cli/cliq/cliq.py @@ -0,0 +1,169 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import Any, Callable +import asyncio +import functools +import inspect +import traceback + +from colorama import Fore +from prompt_toolkit.validation import Validator +from questionary import prompt +import aiohttp +import click + +from ..base import app +from ..config import get_token +from .validators import ClickValidator, Required + + +def with_http(func): + @functools.wraps(func) + async def wrapper(*args, **kwargs): + async with aiohttp.ClientSession() as sess: + try: + return await func(*args, sess=sess, **kwargs) + except aiohttp.ClientError as e: + print(f"{Fore.RED}Connection error: {e}{Fore.RESET}") + + return wrapper + + +def with_authenticated_http(func): + @functools.wraps(func) + async def wrapper(*args, server: str, **kwargs): + server, token = get_token(server) + if not token: + return + async with aiohttp.ClientSession(headers={"Authorization": f"Bearer {token}"}) as sess: + try: + return await func(*args, sess=sess, server=server, **kwargs) + except aiohttp.ClientError as e: + print(f"{Fore.RED}Connection error: {e}{Fore.RESET}") + + return wrapper + + +def command(help: str) -> Callable[[Callable], Callable]: + def decorator(func) -> Callable: + questions = getattr(func, "__inquirer_questions__", {}).copy() + + @functools.wraps(func) + def wrapper(*args, **kwargs): + for key, value in kwargs.items(): + if key not in questions: + continue + if value is not None and (questions[key]["type"] != "confirm" or value != "null"): + questions.pop(key, None) + try: + required_unless = questions[key].pop("required_unless") + if isinstance(required_unless, str) and kwargs[required_unless]: + questions.pop(key) + elif isinstance(required_unless, list): + for v in required_unless: + if kwargs[v]: + questions.pop(key) + break + elif isinstance(required_unless, dict): + for k, v in required_unless.items(): + if kwargs.get(v, object()) == v: + questions.pop(key) + break + except KeyError: + pass + question_list = list(questions.values()) + question_list.reverse() + resp = prompt(question_list, kbi_msg="Aborted!") + if not resp and question_list: + return + kwargs = {**kwargs, **resp} + + try: + res = func(*args, **kwargs) + if inspect.isawaitable(res): + asyncio.run(res) + except Exception: + print(Fore.RED + "Fatal error running command" + Fore.RESET) + traceback.print_exc() + + return app.command(help=help)(wrapper) + + return decorator + + +def yesno(val: str) -> bool | None: + if not val: + return None + elif isinstance(val, bool): + return val + elif val.lower() in ("true", "t", "yes", "y"): + return True + elif val.lower() in ("false", "f", "no", "n"): + return False + + +yesno.__name__ = "yes/no" + + +def option( + short: str, + long: str, + message: str = None, + help: str = None, + click_type: str | Callable[[str], Any] = None, + inq_type: str = None, + validator: type[Validator] = None, + required: bool = False, + default: str | bool | None = None, + is_flag: bool = False, + prompt: bool = True, + required_unless: str | list | dict = None, +) -> Callable[[Callable], Callable]: + if not message: + message = long[2].upper() + long[3:] + + if isinstance(validator, type) and issubclass(validator, ClickValidator): + click_type = validator.click_type + if is_flag: + click_type = yesno + + def decorator(func) -> Callable: + click.option(short, long, help=help, type=click_type)(func) + if not prompt: + return func + if not hasattr(func, "__inquirer_questions__"): + func.__inquirer_questions__ = {} + q = { + "type": ( + inq_type if isinstance(inq_type, str) else ("input" if not is_flag else "confirm") + ), + "name": long[2:], + "message": message, + } + if required_unless is not None: + q["required_unless"] = required_unless + if default is not None: + q["default"] = default + if required or required_unless is not None: + q["validate"] = Required(validator) + elif validator: + q["validate"] = validator + func.__inquirer_questions__[long[2:]] = q + return func + + return decorator diff --git a/maubot-src/maubot/cli/cliq/validators.py b/maubot-src/maubot/cli/cliq/validators.py new file mode 100644 index 0000000..46d3c92 --- /dev/null +++ b/maubot-src/maubot/cli/cliq/validators.py @@ -0,0 +1,85 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from typing import Callable +import os + +from packaging.version import InvalidVersion, Version +from prompt_toolkit.document import Document +from prompt_toolkit.validation import ValidationError, Validator +import click + +from ..util import spdx as spdxlib + + +class Required(Validator): + proxy: Validator + + def __init__(self, proxy: Validator = None) -> None: + self.proxy = proxy + + def validate(self, document: Document) -> None: + if len(document.text) == 0: + raise ValidationError(message="This field is required") + if self.proxy: + return self.proxy.validate(document) + + +class ClickValidator(Validator): + click_type: Callable[[str], str] = None + + @classmethod + def validate(cls, document: Document) -> None: + try: + cls.click_type(document.text) + except click.BadParameter as e: + raise ValidationError(message=e.message, cursor_position=len(document.text)) + + +def path(val: str) -> str: + val = os.path.abspath(val) + if os.path.exists(val): + return val + directory = os.path.dirname(val) + if not os.path.isdir(directory): + if os.path.exists(directory): + raise click.BadParameter(f"{directory} is not a directory") + raise click.BadParameter(f"{directory} does not exist") + return val + + +class PathValidator(ClickValidator): + click_type = path + + +def version(val: str) -> Version: + try: + return Version(val) + except InvalidVersion as e: + raise click.BadParameter(f"{val} is not a valid PEP-440 version") from e + + +class VersionValidator(ClickValidator): + click_type = version + + +def spdx(val: str) -> str: + if not spdxlib.valid(val): + raise click.BadParameter(f"{val} is not a valid SPDX license identifier") + return val + + +class SPDXValidator(ClickValidator): + click_type = spdx diff --git a/maubot-src/maubot/cli/commands/__init__.py b/maubot-src/maubot/cli/commands/__init__.py new file mode 100644 index 0000000..145646b --- /dev/null +++ b/maubot-src/maubot/cli/commands/__init__.py @@ -0,0 +1 @@ +from . import auth, build, init, login, logs, upload diff --git a/maubot-src/maubot/cli/commands/auth.py b/maubot-src/maubot/cli/commands/auth.py new file mode 100644 index 0000000..64b1dc7 --- /dev/null +++ b/maubot-src/maubot/cli/commands/auth.py @@ -0,0 +1,166 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import json +import webbrowser + +from colorama import Fore +from yarl import URL +import aiohttp +import click + +from ..cliq import cliq + +history_count: int = 10 + +friendly_errors = { + "server_not_found": ( + "Registration target server not found.\n\n" + "To log in or register through maubot, you must add the server to the\n" + "homeservers section in the config. If you only want to log in,\n" + "leave the `secret` field empty." + ), + "registration_no_sso": ( + "The register operation is only for registering with a password.\n\n" + "To register with SSO, simply leave out the --register flag." + ), +} + + +async def list_servers(server: str, sess: aiohttp.ClientSession) -> None: + url = URL(server) / "_matrix/maubot/v1/client/auth/servers" + async with sess.get(url) as resp: + data = await resp.json() + print(f"{Fore.GREEN}Available Matrix servers for registration and login:{Fore.RESET}") + for server in data.keys(): + print(f"* {Fore.CYAN}{server}{Fore.RESET}") + + +@cliq.command(help="Log into a Matrix account via the Maubot server") +@cliq.option("-h", "--homeserver", help="The homeserver to log into", required_unless="list") +@cliq.option( + "-u", "--username", help="The username to log in with", required_unless=["list", "sso"] +) +@cliq.option( + "-p", + "--password", + help="The password to log in with", + inq_type="password", + required_unless=["list", "sso"], +) +@cliq.option( + "-s", + "--server", + help="The maubot instance to log in through", + default="", + required=False, + prompt=False, +) +@click.option( + "-r", "--register", help="Register instead of logging in", is_flag=True, default=False +) +@click.option( + "-c", + "--update-client", + help="Instead of returning the access token, create or update a client in maubot using it", + is_flag=True, + default=False, +) +@click.option("-l", "--list", help="List available homeservers", is_flag=True, default=False) +@click.option( + "-o", "--sso", help="Use single sign-on instead of password login", is_flag=True, default=False +) +@click.option( + "-n", + "--device-name", + help="The initial e2ee device displayname (only for login)", + default="Maubot", + required=False, +) +@cliq.with_authenticated_http +async def auth( + homeserver: str, + username: str, + password: str, + server: str, + register: bool, + list: bool, + update_client: bool, + device_name: str, + sso: bool, + sess: aiohttp.ClientSession, +) -> None: + if list: + await list_servers(server, sess) + return + endpoint = "register" if register else "login" + url = URL(server) / "_matrix/maubot/v1/client/auth" / homeserver / endpoint + if update_client: + url = url.update_query({"update_client": "true"}) + if sso: + url = url.update_query({"sso": "true"}) + req_data = {"device_name": device_name} + else: + req_data = {"username": username, "password": password, "device_name": device_name} + + async with sess.post(url, json=req_data) as resp: + if not 200 <= resp.status < 300: + await print_error(resp, is_register=register) + elif sso: + await wait_sso(resp, sess, server, homeserver) + else: + await print_response(resp, is_register=register) + + +async def wait_sso( + resp: aiohttp.ClientResponse, sess: aiohttp.ClientSession, server: str, homeserver: str +) -> None: + data = await resp.json() + sso_url, reg_id = data["sso_url"], data["id"] + print(f"{Fore.GREEN}Opening {Fore.CYAN}{sso_url}{Fore.RESET}") + webbrowser.open(sso_url, autoraise=True) + print(f"{Fore.GREEN}Waiting for login token...{Fore.RESET}") + wait_url = URL(server) / "_matrix/maubot/v1/client/auth" / homeserver / "sso" / reg_id / "wait" + async with sess.post(wait_url, json={}) as resp: + await print_response(resp, is_register=False) + + +async def print_response(resp: aiohttp.ClientResponse, is_register: bool) -> None: + if resp.status == 200: + data = await resp.json() + action = "registered" if is_register else "logged in as" + print(f"{Fore.GREEN}Successfully {action} {Fore.CYAN}{data['user_id']}{Fore.GREEN}.") + print(f"{Fore.GREEN}Access token: {Fore.CYAN}{data['access_token']}{Fore.RESET}") + print(f"{Fore.GREEN}Device ID: {Fore.CYAN}{data['device_id']}{Fore.RESET}") + elif resp.status in (201, 202): + data = await resp.json() + action = "created" if resp.status == 201 else "updated" + print( + f"{Fore.GREEN}Successfully {action} client for " + f"{Fore.CYAN}{data['id']}{Fore.GREEN} / " + f"{Fore.CYAN}{data['device_id']}{Fore.GREEN}.{Fore.RESET}" + ) + else: + await print_error(resp, is_register) + + +async def print_error(resp: aiohttp.ClientResponse, is_register: bool) -> None: + try: + err_data = await resp.json() + error = friendly_errors.get(err_data["errcode"], err_data["error"]) + except (aiohttp.ContentTypeError, json.JSONDecodeError, KeyError): + error = await resp.text() + action = "register" if is_register else "log in" + print(f"{Fore.RED}Failed to {action}: {error}{Fore.RESET}") diff --git a/maubot-src/maubot/cli/commands/build.py b/maubot-src/maubot/cli/commands/build.py new file mode 100644 index 0000000..39eca53 --- /dev/null +++ b/maubot-src/maubot/cli/commands/build.py @@ -0,0 +1,155 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import IO +from io import BytesIO +import asyncio +import glob +import os +import zipfile + +from aiohttp import ClientSession +from colorama import Fore +from questionary import prompt +from ruamel.yaml import YAML, YAMLError +import click + +from mautrix.types import SerializerError + +from ...loader import PluginMeta +from ..base import app +from ..cliq import cliq +from ..cliq.validators import PathValidator +from ..config import get_token +from .upload import upload_file + +yaml = YAML() + + +def zipdir(zip, dir): + for root, dirs, files in os.walk(dir): + for file in files: + zip.write(os.path.join(root, file)) + + +def read_meta(path: str) -> PluginMeta | None: + try: + with open(os.path.join(path, "maubot.yaml")) as meta_file: + try: + meta_dict = yaml.load(meta_file) + except YAMLError as e: + print(Fore.RED + "Failed to build plugin: Metadata file is not YAML") + print(Fore.RED + str(e) + Fore.RESET) + return None + except FileNotFoundError: + print(Fore.RED + "Failed to build plugin: Metadata file not found" + Fore.RESET) + return None + try: + meta = PluginMeta.deserialize(meta_dict) + except SerializerError as e: + print(Fore.RED + "Failed to build plugin: Metadata file is not valid") + print(Fore.RED + str(e) + Fore.RESET) + return None + return meta + + +def read_output_path(output: str, meta: PluginMeta) -> str | None: + directory = os.getcwd() + filename = f"{meta.id}-v{meta.version}.mbp" + if not output: + output = os.path.join(directory, filename) + elif os.path.isdir(output): + output = os.path.join(output, filename) + elif os.path.exists(output): + q = [{"type": "confirm", "name": "override", "message": f"{output} exists, override?"}] + override = prompt(q)["override"] + if not override: + return None + os.remove(output) + return os.path.abspath(output) + + +def write_plugin(meta: PluginMeta, output: str | IO) -> None: + with zipfile.ZipFile(output, "w") as zip: + meta_dump = BytesIO() + yaml.dump(meta.serialize(), meta_dump) + zip.writestr("maubot.yaml", meta_dump.getvalue()) + + for module in meta.modules: + if os.path.isfile(f"{module}.py"): + zip.write(f"{module}.py") + elif module is not None and os.path.isdir(module): + if os.path.isfile(f"{module}/__init__.py"): + zipdir(zip, module) + else: + print( + Fore.YELLOW + + f"Module {module} is missing __init__.py, skipping" + + Fore.RESET + ) + else: + print(Fore.YELLOW + f"Module {module} not found, skipping" + Fore.RESET) + for pattern in meta.extra_files: + for file in glob.iglob(pattern): + zip.write(file) + + +@cliq.with_authenticated_http +async def upload_plugin(output: str | IO, *, server: str, sess: ClientSession) -> None: + server, token = get_token(server) + if not token: + return + if isinstance(output, str): + with open(output, "rb") as file: + await upload_file(sess, file, server) + else: + await upload_file(sess, output, server) + + +@app.command( + short_help="Build a maubot plugin", + help=( + "Build a maubot plugin. First parameter is the path to root of the plugin " + "to build. You can also use --output to specify output file." + ), +) +@click.argument("path", default=os.getcwd()) +@click.option( + "-o", "--output", help="Path to output built plugin to", type=PathValidator.click_type +) +@click.option( + "-u", "--upload", help="Upload plugin to server after building", is_flag=True, default=False +) +@click.option("-s", "--server", help="Server to upload built plugin to") +def build(path: str, output: str, upload: bool, server: str) -> None: + meta = read_meta(path) + if not meta: + return + if output or not upload: + output = read_output_path(output, meta) + if not output: + return + else: + output = BytesIO() + os.chdir(path) + write_plugin(meta, output) + if isinstance(output, str): + print(f"{Fore.GREEN}Plugin built to {Fore.CYAN}{output}{Fore.GREEN}.{Fore.RESET}") + else: + output.seek(0) + if upload: + asyncio.run(upload_plugin(output, server=server)) diff --git a/maubot-src/maubot/cli/commands/init.py b/maubot-src/maubot/cli/commands/init.py new file mode 100644 index 0000000..d24def9 --- /dev/null +++ b/maubot-src/maubot/cli/commands/init.py @@ -0,0 +1,99 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import os + +from jinja2 import Template +from packaging.version import Version +from pkg_resources import resource_string + +from .. import cliq +from ..cliq import SPDXValidator, VersionValidator +from ..util import spdx + +loaded: bool = False +meta_template: Template +mod_template: Template +base_config: str + + +def load_templates(): + global mod_template, meta_template, base_config, loaded + if loaded: + return + meta_template = Template(resource_string("maubot.cli", "res/maubot.yaml.j2").decode("utf-8")) + mod_template = Template(resource_string("maubot.cli", "res/plugin.py.j2").decode("utf-8")) + base_config = resource_string("maubot.cli", "res/config.yaml").decode("utf-8") + loaded = True + + +@cliq.command(help="Initialize a new maubot plugin") +@cliq.option( + "-n", + "--name", + help="The name of the project", + required=True, + default=os.path.basename(os.getcwd()), +) +@cliq.option( + "-i", + "--id", + message="ID", + required=True, + help="The maubot plugin ID (Java package name format)", +) +@cliq.option( + "-v", + "--version", + help="Initial version for project (PEP-440 format)", + default="0.1.0", + validator=VersionValidator, + required=True, +) +@cliq.option( + "-l", + "--license", + validator=SPDXValidator, + default="AGPL-3.0-or-later", + help="The license for the project (SPDX identifier)", + required=False, +) +@cliq.option( + "-c", + "--config", + message="Should the plugin include a config?", + help="Include a config in the plugin stub", + default=False, + is_flag=True, +) +def init(name: str, id: str, version: Version, license: str, config: bool) -> None: + load_templates() + main_class = name[0].upper() + name[1:] + meta = meta_template.render( + id=id, version=str(version), license=license, config=config, main_class=main_class + ) + with open("maubot.yaml", "w") as file: + file.write(meta) + if license: + with open("LICENSE", "w") as file: + file.write(spdx.get(license)["licenseText"]) + if not os.path.isdir(name): + os.mkdir(name) + mod = mod_template.render(config=config, name=main_class) + with open(f"{name}/__init__.py", "w") as file: + file.write(mod) + if config: + with open("base-config.yaml", "w") as file: + file.write(base_config) diff --git a/maubot-src/maubot/cli/commands/login.py b/maubot-src/maubot/cli/commands/login.py new file mode 100644 index 0000000..8aac0f5 --- /dev/null +++ b/maubot-src/maubot/cli/commands/login.py @@ -0,0 +1,77 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import json +import os + +from colorama import Fore +from yarl import URL +import aiohttp + +from ..cliq import cliq +from ..config import config, save_config + + +@cliq.command(help="Log in to a Maubot instance") +@cliq.option( + "-u", + "--username", + help="The username of your account", + default=os.environ.get("USER", None), + required=True, +) +@cliq.option( + "-p", "--password", help="The password to your account", inq_type="password", required=True +) +@cliq.option( + "-s", + "--server", + help="The server to log in to", + default="http://localhost:29316", + required=True, +) +@cliq.option( + "-a", + "--alias", + help="Alias to reference the server without typing the full URL", + default="", + required=False, +) +@cliq.with_http +async def login( + server: str, username: str, password: str, alias: str, sess: aiohttp.ClientSession +) -> None: + data = { + "username": username, + "password": password, + } + url = URL(server) / "_matrix/maubot/v1/auth/login" + async with sess.post(url, json=data) as resp: + if resp.status == 200: + data = await resp.json() + config["servers"][server] = data["token"] + if not config["default_server"]: + print(Fore.CYAN, "Setting", server, "as the default server") + config["default_server"] = server + if alias: + config["aliases"][alias] = server + save_config() + print(Fore.GREEN + "Logged in successfully") + else: + try: + err = (await resp.json())["error"] + except (json.JSONDecodeError, KeyError): + err = await resp.text() + print(Fore.RED + err + Fore.RESET) diff --git a/maubot-src/maubot/cli/commands/logs.py b/maubot-src/maubot/cli/commands/logs.py new file mode 100644 index 0000000..e0ed07d --- /dev/null +++ b/maubot-src/maubot/cli/commands/logs.py @@ -0,0 +1,107 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from datetime import datetime +import asyncio + +from aiohttp import ClientSession, WSMessage, WSMsgType +from colorama import Fore +import click + +from mautrix.types import Obj + +from ..base import app +from ..config import get_token + +history_count: int = 10 + + +@app.command(help="View the logs of a server") +@click.argument("server", required=False) +@click.option("-t", "--tail", default=10, help="Maximum number of old log lines to display") +def logs(server: str, tail: int) -> None: + server, token = get_token(server) + if not token: + return + global history_count + history_count = tail + loop = asyncio.get_event_loop() + loop.run_until_complete(view_logs(server, token)) + + +def parsedate(entry: Obj) -> None: + i = entry.time.index("+") + i = entry.time.index(":", i) + entry.time = entry.time[:i] + entry.time[i + 1 :] + entry.time = datetime.strptime(entry.time, "%Y-%m-%dT%H:%M:%S.%f%z") + + +levelcolors = { + "DEBUG": "", + "INFO": Fore.CYAN, + "WARNING": Fore.YELLOW, + "ERROR": Fore.RED, + "FATAL": Fore.MAGENTA, +} + + +def print_entry(entry: dict) -> None: + entry = Obj(**entry) + parsedate(entry) + print( + "{levelcolor}[{date}] [{level}@{logger}] {message}{resetcolor}".format( + date=entry.time.strftime("%Y-%m-%d %H:%M:%S"), + level=entry.levelname, + levelcolor=levelcolors.get(entry.levelname, ""), + resetcolor=Fore.RESET, + logger=entry.name, + message=entry.msg, + ) + ) + if entry.exc_info: + print(entry.exc_info) + + +def handle_msg(data: dict) -> bool: + if "auth_success" in data: + if data["auth_success"]: + print(Fore.GREEN + "Connected to log websocket" + Fore.RESET) + else: + print(Fore.RED + "Failed to authenticate to log websocket" + Fore.RESET) + return False + elif "history" in data: + for entry in data["history"][-history_count:]: + print_entry(entry) + else: + print_entry(data) + return True + + +async def view_logs(server: str, token: str) -> None: + async with ClientSession() as session: + async with session.ws_connect(f"{server}/_matrix/maubot/v1/logs") as ws: + await ws.send_str(token) + try: + msg: WSMessage + async for msg in ws: + if msg.type == WSMsgType.TEXT: + if not handle_msg(msg.json()): + break + elif msg.type == WSMsgType.ERROR: + print(Fore.YELLOW + "Connection error: " + msg.data + Fore.RESET) + elif msg.type == WSMsgType.CLOSE: + print(Fore.YELLOW + "Server closed connection" + Fore.RESET) + except asyncio.CancelledError: + pass diff --git a/maubot-src/maubot/cli/commands/upload.py b/maubot-src/maubot/cli/commands/upload.py new file mode 100644 index 0000000..3c2cf1e --- /dev/null +++ b/maubot-src/maubot/cli/commands/upload.py @@ -0,0 +1,58 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from typing import IO +import json + +from colorama import Fore +from yarl import URL +import aiohttp +import click + +from ..cliq import cliq + + +class UploadError(Exception): + pass + + +@cliq.command(help="Upload a maubot plugin") +@click.argument("path") +@click.option("-s", "--server", help="The maubot instance to upload the plugin to") +@cliq.with_authenticated_http +async def upload(path: str, server: str, sess: aiohttp.ClientSession) -> None: + with open(path, "rb") as file: + await upload_file(sess, file, server) + + +async def upload_file(sess: aiohttp.ClientSession, file: IO, server: str) -> None: + url = (URL(server) / "_matrix/maubot/v1/plugins/upload").with_query({"allow_override": "true"}) + headers = {"Content-Type": "application/zip"} + async with sess.post(url, data=file, headers=headers) as resp: + if resp.status in (200, 201): + data = await resp.json() + print( + f"{Fore.GREEN}Plugin {Fore.CYAN}{data['id']} v{data['version']}{Fore.GREEN} " + f"uploaded to {Fore.CYAN}{server}{Fore.GREEN} successfully.{Fore.RESET}" + ) + else: + try: + err = await resp.json() + if "stacktrace" in err: + print(err["stacktrace"]) + err = err["error"] + except (aiohttp.ContentTypeError, json.JSONDecodeError, KeyError): + err = await resp.text() + print(f"{Fore.RED}Failed to upload plugin: {err}{Fore.RESET}") diff --git a/maubot-src/maubot/cli/config.py b/maubot-src/maubot/cli/config.py new file mode 100644 index 0000000..5fdc4ea --- /dev/null +++ b/maubot-src/maubot/cli/config.py @@ -0,0 +1,80 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import Any +import json +import os + +from colorama import Fore + +config: dict[str, Any] = { + "servers": {}, + "aliases": {}, + "default_server": None, +} +configdir = os.environ.get("XDG_CONFIG_HOME", os.path.join(os.environ.get("HOME"), ".config")) + + +def get_default_server() -> tuple[str | None, str | None]: + try: + server: str < None = config["default_server"] + except KeyError: + server = None + if server is None: + print(f"{Fore.RED}Default server not configured.{Fore.RESET}") + print(f"Perhaps you forgot to {Fore.CYAN}mbc login{Fore.RESET}?") + return None, None + return server, _get_token(server) + + +def get_token(server: str) -> tuple[str | None, str | None]: + if not server: + return get_default_server() + if server in config["aliases"]: + server = config["aliases"][server] + return server, _get_token(server) + + +def _resolve_alias(alias: str) -> str | None: + try: + return config["aliases"][alias] + except KeyError: + return None + + +def _get_token(server: str) -> str | None: + try: + return config["servers"][server] + except KeyError: + print(f"{Fore.RED}No access token saved for {server}.{Fore.RESET}") + return None + + +def save_config() -> None: + with open(f"{configdir}/maubot-cli.json", "w") as file: + json.dump(config, file) + + +def load_config() -> None: + try: + with open(f"{configdir}/maubot-cli.json") as file: + loaded = json.load(file) + config["servers"] = loaded.get("servers", {}) + config["aliases"] = loaded.get("aliases", {}) + config["default_server"] = loaded.get("default_server", None) + except FileNotFoundError: + pass diff --git a/maubot-src/maubot/cli/res/config.yaml b/maubot-src/maubot/cli/res/config.yaml new file mode 100644 index 0000000..bbeb6da --- /dev/null +++ b/maubot-src/maubot/cli/res/config.yaml @@ -0,0 +1,6 @@ +example_1: Example value 1 +example_2: + list: + - foo + - bar + value: asd diff --git a/maubot-src/maubot/cli/res/maubot.yaml.j2 b/maubot-src/maubot/cli/res/maubot.yaml.j2 new file mode 100644 index 0000000..2d91ba2 --- /dev/null +++ b/maubot-src/maubot/cli/res/maubot.yaml.j2 @@ -0,0 +1,42 @@ +# The unique ID for the plugin. Java package naming style. (i.e. use your own domain, not xyz.maubot) +id: {{ id }} + +# A PEP 440 compliant version string. +version: {{ version }} + +# The SPDX license identifier for the plugin. https://spdx.org/licenses/ +# Optional, assumes all rights reserved if omitted. +{% if license %} +license: {{ license }} +{% else %} +#license: null +{% endif %} + +# The list of modules to load from the plugin archive. +# Modules can be directories with an __init__.py file or simply python files. +# Submodules that are imported by modules listed here don't need to be listed separately. +# However, top-level modules must always be listed even if they're imported by other modules. +modules: +- {{ name }} + +# The main class of the plugin. Format: module/Class +# If `module` is omitted, will default to last module specified in the module list. +# Even if `module` is not omitted here, it must be included in the modules list. +# The main class must extend maubot.Plugin +main_class: {{ main_class }} + +# Extra files that the upcoming build tool should include in the mbp file. +{% if config %} +extra_files: +- base-config.yaml +{% else %} +#extra_files: +#- base-config.yaml +{% endif %} + +# List of dependencies +#dependencies: +#- foo + +#soft_dependencies: +#- bar>=0.1 diff --git a/maubot-src/maubot/cli/res/plugin.py.j2 b/maubot-src/maubot/cli/res/plugin.py.j2 new file mode 100644 index 0000000..05d5341 --- /dev/null +++ b/maubot-src/maubot/cli/res/plugin.py.j2 @@ -0,0 +1,27 @@ +from typing import Type +{% if config %} +from mautrix.util.config import BaseProxyConfig, ConfigUpdateHelper +{% endif %} +from maubot import Plugin +{% if config %} + +class Config(BaseProxyConfig): + def do_update(self, helper: ConfigUpdateHelper) -> None: + helper.copy("example_1") + helper.copy("example_2.list") + helper.copy("example_2.value") +{% endif %} + +class {{ name }}(Plugin): + async def start(self) -> None:{% if config %} + self.config.load_and_update() + self.log.debug("Loaded %s from config example 2", self.config["example_2.value"]){% else %} + pass{% endif %} + + async def stop(self) -> None: + pass +{% if config %} + @classmethod + def get_config_class(cls) -> Type[BaseProxyConfig]: + return Config +{% endif %} diff --git a/maubot-src/maubot/cli/res/spdx.json.zip b/maubot-src/maubot/cli/res/spdx.json.zip new file mode 100644 index 0000000000000000000000000000000000000000..98de1b0d9c97911c30c13cef56bb07a1e10a9bc2 GIT binary patch literal 698204 zcmd2?!*ebUkc?hz+qP}{#kQRYbYpDrIb)Cs1-zGscZ!ph_sP_ARst@ zBPWU%`xlv)$rlqdG=;qqhMo|wcXJ8`y+0TfyXAhqKkMcc zmTgOK-huy?1e|j#?2v0=YCar_7lrehD(1QWmQNSbs_*jp>Xk4LU)*F0QF&CWGXt!DPJ!;OB}N|CrWF0;oGV3crQw=BI!Vdz(#tHm@_ zTuhQ)%zChYGnkL`@)jeU*UY3jC=O{>PRI&vwL~&1Y11`o@{aae{PIpN)6!4y=GMy8 zOo-`}6KADmF|Jz0h8cFKR=M;{)NRP=(4+Pg`8B#!oM_QB>7VI{21=;yI?jzK;rTIB+zA{BDdbwBFc^2KU{XFTt`}ld! zqUe7d3Nb)(V+z8BR=##{U{>vAf;*UaE-U-&dM)2p$b22c-KYXKFF*8p;T$BoZ`xvh zUQo20!-Dc(U!g{Xaa{Jd-PK70otyo3biED@!m%VYR2k3Xq&_C+@5GfUhTB)V-Xdz~KM&3{3|`0l%YZshN!@2MX6 z|52_0V$a@usp~&)lJq`w<5Zs@*sz}W$1R*#aAlJ61-b$?*Z#T(GX$PswwjRiZhCPRw0Dy#l4N!& zkm#P_%IyCeJxutu8fbJEV#KQ7_&ft2RVv%3)iDgK@W`dBS7m!K`ob(TETp8*cy6`G zPpD;Qt0BP2dFhQ*Cc{3lFFnh&w@hP*df7QSAw-fOg7a4h0Mr$_DWYa zmV|DiV`2p?KxJ}(c@ac88Qmca^VhIpqRu6Y8PiE=aaV9{ z>+u%Bv6ZXFhZ+|jA0ZOWA(MJV_QEQV4Dp@SCbw{*PChG-nuitOEDc0d<6AM@w*<0`LnH7{i|x?%lvajB>!^!v`Oq$PmB1mLMK&M*zpOb+!WsueaefsikR>s z?|=;M413M}H(+!aWduGL;Ij>m=73JTyf)CS`_@w{^Yd`Lt*kb55Qbf54yPNO zSn!aqZ_O3)u=VME8O$I~d)~rPhN-xuHp~rHuoJ&SuZ|AV0d|cew8#rP8FjSO zN^ln27JSap?TQ@-ddnHr2{Li#UFe@`zk+^g_u~y6aZTMR{F+VUc8Xs`SJWzhge~@< zGRUqwT2-}|t&PgzVw3?vKK>i#W6YfUMVEb zFdL*8x1PPl58K6pDVS{VomYHD>=fz!ZgiAr8u?(QQz-Mv^h%eB`?Qi=B10Z z&^bob6RO(nFl_O8N1n8iifePi^lLL`y5_+J7a6@;Pa z41aPK!US$@d@NMEc_J;H%eqORnDETmFtMJd2~U&U%^cWTC=j!zKXZ#MNf8U50t_eV z7q?LyiENgCxB@!bs4%ncz<9y4$t5r9i%~_sr8H0=KC5UsaBdC;OHF`a$u*Ml^2a&k zYiA*zG!45P_XK^RqErPdS-H6BB66)Pav1GDF=03)C`hB%cy{3h8)mPThzPx-b#~c_ zYZhWU+iGSXGs0z*pCMQp-P%FXT-3{odOnGa;?k+$0{FDVRBpfGgmUZpJt8Q|*6o8t zDh?uV(xpwXif^_#J+o-2rr>E=cqPnm0ggS4LZGmS8}&L$)QQh-gWGhf5kJd}!HLww zGp%XdI7}z{vUq)s9bhhKHvLoo;HYmV%nbTL4hSLC7#i3@f$}Bi#BQb%qtj%wfoHn7?7|w@aNPU^D&ZSIAc@1`eYBj=Bh24| zk+vLiyk4FdH^FjE-1KnofU#!~kH&72`%;r!5z?>zGuiE!-=6v+MtV}FF-IcXa%@qO zun=wp02i=<_KECp*i~vM%LhG<9QmKUVWnSD3Hbv~h&X08tjKSMW|=kt%>t>{=NU36 zAvBs?40JA=1SC0y!-9JWZ+|QCv;3@4mqWFI{PXzFo46_34frb5EhsZi1r#~FN#xok z05J36XLZr7f;=NdgCK{Plz_Qp&1@Qh!mgnfxF-b?IPmHIE3=uxL4J9F-FimJ;0wbCsW8@8@YLj#r zrk9i6e108L@)imYmKz{i4Q2qRP|Y!j$VC=IcI{bWdmPRiat5g`w@TuBCuNlbtm;H% z6id14x{fZ5uNm(~+cqHc!l*{H!meI1EXWOUH}a|j_U(;oq@?cBIu5LG+YA#o`YIzS zS{G%^%=K(5_jvbu)YVQa=(s~P==O_W^cX4d{_X`mMpB)l6$SZf;qfznF4SCK9{l8J zkTMVkZ!R}GE+6ClZN>vmPJ9`Dk~2dYJ0$YvU-v5CSvEexnfH;%nZ;cF2G^OGnF%$C zduwYr$6>)^yfa|_u}L2% zE^{)=T#Vc95?lz(PBM8Ai88p7;w>{73AOMu*O1n!m*`drymF|{SSYpyUD=n^@l}w4 z(ai8XM{xhv1CRNK#>7)_u9ezOFdK`mC=kSwPl7Gxq6Ctu(S^m^>rU}!GNCsZ;FJrF zu<$U6QERBeH}w)Q!qVB)r}==CoMRFnp@@dD7v}^WI+-HKmd}98Zyc zVQM-+5ZvmHQo27dyc{ayeb1E9#+l|0%s@ylptIZxH;}AA;7%i5RK*JIiL^}Z3>;Ea zHIstt3&g@}!BTdr9}`SiF~fvD1#U%NV~K_|8A6^;e61qoDxZ&EXH$#WM9PdaiwW#7 zW&V75KV**D56l=%UfJo&C$F&Ev5`EpY@|3zrL^>U2Rh_|*bq_2yJ53ZBi<{mG>kkq zH(_bck+_6JTSuB@1$&NV&JBOQKr6;$mhXnG3HF@ii!8d4?)`-raD#`uKWj(|Z`49X3nMlk*+XmMB-$ z5d-XHYF-m#U<0SR$t+t;2m%jN)xC+=68#RNIh*uh=Q_@58G)m{Gzl(0TQL-gCsIB+ zCURP@I16(IExtPnn-tid&8(QmP4Ma~OddZbXpP*+lOG~kEwoyZgR2wi!Xe#Rfveip ztoHh9X=p~EjokGI#oFjpz)S9`i}}pHi1H==Cs4JXKoN!K7Y}1-$-Wr7^oLH`u=ez3 zX<#dh-?3r@*IhCus;k&Gtr;|GEQj6->Lwa&4hjwtSS8sx{!(ppLv1ocdALH_Y-}vsWH7r)4k~AkwSb$Zz7%UDg00SK>Z$FO6lG*xS)@%n?yrUViM$a2-Dxs>$SU{pX613itCfcF>yuvnOZJ$1 zVKl)J??qK{gp5gSK^e~H-8YL*vL^9|uxbicV3Q?StOoUZ2wh9|2GdOKy{!UPgH9S1 zvdjTFY4&d$%$qdoDdFW^66=ES`05LiBzVD72sl+ym0sqxL{GBN$KuC~d?kU9&3K5G zZ3LNNFsXJW&@?0mn@XjSj-@JZGC||I*EAd5&jFxZY8lo;5ZlXocZ`|$d93I z6Aw(#(tiAEL$qmeUlBe9(l3He~X8z}9z`k!lPQ4i4S_|VKVXR)d|;p74J zG$GM1`lL0&`R9doUZmCkRZQW=*i9~!5L}hcWbjKZLc9z6e#>6G#;-U~EjU8VM5G!F zoQqvIj|Zy0(DFfB${>rmaOpun23$WBBIzZ8x?HmtsMZ;aX*An&;`LL7Y@0ec?`_vx zA2U%iuL5~+bD7~&Dar|C_TLAT;+S0iG8rF+ALpOr^+|?a&-aIR+wOJe*dIO1+;~m` zZ5duqryC-l3rg6xTqUETm$LS~X9nlPnf);w zr~ekNJ!U%e!MxHRPD(alFPCO1qY$O1__bM8ki(ySh3+_}vl!3THUXdfb~UDGO@Y?? zkG)-=DKW&cF!rjhF*N`#8thdfab^5P`*f6UBhtus*tt6H3oy>qG)~srlCs&mOMO*~ zbZjmfE3G@GasJ%uIpCWO{G~_PM*)Awa|op0vXxbmmPfrfO0yUl3%TZwd-S3)pNyQT z7a5FO=@9_loQPhD)?)31_M!t$&<31}f80T9gGR;j%(KQjkK}~-aSw$#v(g+~Lyb>O zIw=Ih&VKinuA#%b|6ZSY4rV;M}w`6V{QsKLd(x|-*p_|Bs z)Di(R&*1qUmePEy3UM+dyNe`dUE4CgGA z%nxE$s4W*{3aR$$+1b=zgrR>jZH-Hmg}fJdt8rE(u_TAS;XR+*+#JrH_@)lF=RG># zU~uMs&Zd4i3%}aC3BPvo7JkO$&3{9^krr;Nl~9&-?I`vv{o>g@&s4(qnwV0EwO%gC z@1<@p7VFV^^OxbNQ>31hhU7b{|5H4L|xP}Z1OZMud zlmawNI_IA>9)9Y%!?(9=I0E}3r6|rg-$G_t*Wv}L3sQqM71|6HuYUAVWC_#QgLBsX z-ATl3lrB?AfYsnug^GnpikO9pZ@Kol%XvH)iyjhE-5`UXOV?CY&>D_xgqkcbFm8?q z8Zl~i@5c2sZ1*!Xn?&`YKs9=U&$-b;0ajoK<`1sHQYVIRO^UsGvye0)TSRRj)Fgz`Du7gR&7NiNGw}Mz)i_M(VXyt-45SibAMMZpDwR=(iil_*<1ux(7++?;I z(@KU#UhPLJwM-j2pc7>cA+Q)$k-AVtKhShRWl4%a73D{4>egIxG+Ylpt*&A>YuN+^ zrK_73(1Nx)16O*Kl#!ukrQ<8QoI%9nMw_3hqlvQgDBXs*nu09?)4xjaM4-m8^cdhJ zLehRrur!rP1ieV4Ak=Ec`7{Peg;=?w%nDA!8v>ERKt7Uk59}ylj6RSuAx;Av>|krU zddp0%zH#1=v8m5eNfPCES8-o1twle#e#`4oEG04uSp?h!7!q;d zieju@9;5mH@JD6XoVP$|0K+15Ckxfiwt^lU<``gY)$ttZ?>(WvKcM|kvXR<--u zQ|k7hj{D5ko1nmzhl{VGtS!xzT&SeTmq1V!Sy-zy(G4YYvLEgUV=i@47OO9Rx@(t0 z-La93tKUrm|E?}9mB)jEf%bvUCp9%_oyR|hE}og!4Nj(Z01GTgA(wJ%WAJ!{#6q|j zQe$cD*p*WCs*K}Vhs&B6#c||zl2Q_#;;rL4emH#|;H~$0l^)>$L1hI<4_7etbRER6 z>b%xOk9uTVwcsvgGU8+okCafFNEbO*9!67N{xi`I+ zT>%C`(6xp&I%lJyEh>_;$L^7Fyk_^xyxK6d2yjKLT;u&Ddl`dW8d z8l@LWgU(g)wiH`VyQR6UaWZMfN04>t=hl()ye*aXm}NzRu&?kF{w%v@*wLW(hz!t) z##hsEl-GsWbc(4WpQPpuJHofu2guL$+r-(-<4pRmj)toD{`4;H?k+ z>9wlx8}t%pK-fn4aAAP{?%)WS;eRWg`|CBn@;=&Ya{0Udxq8grKr4s(mGh2j$89bj zZ%coM?pAUPD=Lgk?Lp%Y8*)-!Ga|()ISaH;%Si}cRWo|=+SSj*Gg|#S{bcRjE5$c{ z<+5#UzYCw3NGyyL(P0uvy4Q2-rQ7rDV=W~3H^j&~2)Kg={A?T?w5cD+mQfG~cCHlK zAP8uK(4QXzZ0;5h=qcmC&zJ6P7W}(W==Upt3Y>i}?=R%fx`7|N%RA2AEcja^)%5RE zUEbABTi!0&m3h#|J4t~rdw$+5+|we+%aRbBA65cru^m3$g85_I=qP#jVR5~{{FxeB zTR;zOh{(XyzJ#zhJ7k_0iMKC{|LiUN?&I(G(pxTE*J-2w>zDi-9}ZyF9`xqjwvG?S zVitU(5r5-x?t3)tSCUt7_GSw7sX7Sa?4zUApUDwr)rsde!K?Dq;?~IHeST_heZ}wV z^Y=XWmEiZs&({3bYrSz7qatn=3t-fg{?*+VGpRnn0DtD;Dxj3dK5__;hya%vRtJAR zVbTm~W02JJt^z~=Ck+~#Z&D%`F%7cHb;9uH9AzM2Yn;d4ELjPp*?o+bZoha`01>La zF4;J>@B4!{!&3j@WfTC3?b}N_5Du2bpzh>&BmfUcrU*aVDw526DqP9_DLzq7ucf_< znxZ2Z`BR-k33Daz^Zk1_YHsF8xF;k_-C%O=FI#xoMgokze6n1$IWJa!x{`=aqHBXzQ~e^t-Q=hc=H0d z?R9C_Z1J)-a4$P;mua1#IsM`BOE)VbL5lyV++Or=$=S_Uyu?W0Ir0ATCnPh`C$8Qe z6Afl3{)hj@SrUu`t=MN;?1l%NYIBBdsE5*_NY(U(|4e>z{D8gsH%}1B+ol}2Te&iio zttBAE*1!};LlcaK<=tjFqfg=f2rb^$brCpg0sg6MIP`n8_m=?2ea##UVUw_(U9uJ~ z@si-r`16sq8&LWc-P2dwCKgnk-tS>A=+Y%k+=EfLI^;>Df{t1we_VI7T6_)M`Gq4W zWv>(^NR|xzwJZpeOE7vxa%qb4tX^lxk6zG~-GE#nws9ZTD%*|qmTJ>6+YmJ;iMZJH zFSLb?o^55oubW1DtAjYS|mSKl}+7lmP|N zwx;>Nt^F=QH_rfOci1uC`G^Agn;fZFRn%h@77(R571(i8I-4cr@nl-iyy1%#fD!Zg zwV@~p!)q{S>ic)kfY+VlH{kUmiFXrXUOcfYI&QcO%gvBe;L=o|&jS|X+$b?7&CZLq zF>HN}OV9M>>0G_t3Gc*i71haHE}P5Cr7X|q^*CvC_h@~*EiZ5r{W>VfzC#^?Lf6<8 z-M~4|`}Nwb{d4v8*lPu%Ha|l>?SQBpvea6C04h>$>vl!X)9Cxw!P5IM<4uaO8e=w#a&lhV-Nk zj>L?6uV{ujro9+Oe5>0zt=lfJ5ubJCBiAk|CS|ZwA_%J;FGaj}_4r!8E+7CfYPCM8 z7w)r2JI< zGKufwWVG9=fYE0)i>C}YttYkHZC`v%6zcPq*-w#t#lnx{6x7!ElHEP1ua_HEJzn&v zJ9@2L{PTvOE5d1?YRYszujn}v;n6PXfZOg8K40Y^)YT4ELh`$Y0Dlxv?2| znJ(oyX{8aoE_U^-oFX@1(f#3=0CV6Kf0{zJ!9hV8<;qAiqa9u#*C6KIfg7=8OCUvq zHRBrfnPf2h8!Ovi_#W}2GFVM39U~;Q@si$y(j^9%bGH)m?#c90#%1P0BcQ%B!JnTI z_UPT}>n%iRd_H%Dh8>n6jit`Fq0#^3gvJ?*_j0?$t*cx!mTr*;w(%l4S#B3amVFR@ z@Jo!Svu?&X{`+O+y4%*jopLG7QWeEr1%p6rin1Gd5=efRW76q;uwY5Yhjw zUAh9fYqDx5o_36u-ut&@dKoj8E7Ra_D^`zq)X++{0V;|(Bpl7lPEqF18XREOTZN$- z25Bth)m%DO$e3eM+rVYciebRC8p8l9x%ozP!AE6~b$yrav?q?(q zxnC%7KmV;(;czggFNUXbpG-1AurIWvsq+fR-&7DF?2$UU^0VZ7seyCH~BUCZMMxC1POhQ``8ZQiZ2d2h{|g{3wc(Rmv3ivId~B}ov2^FElUO+bjuHuA7LlV=PrOE zAFQa@2(q0t+)rwqKGaY-KM7x?VAJuuR?JPFNcYmKI^Dr3TDb^QmNS`(=Tag=FU0G1 ziIA=gEOyA{`42-1+Ax*D(zDZ_4K=>{5}#4=wT8ciAWegCjeLg!OW*Tr&AshE#NjNP<;h;MU9Q4})1nKea`4#Q^%H6g= z0BZ_@{h0miHvZ;R8+zGt!myAgNu1X%;u^urU2GrTZy$FiwH7?DjBa|K3MKE6O~H;q zN|X`Vp)o>=<5OkmIHU&@$7pNns2Hy1D6H_^QoMya94K@O$veV*EZpuQM|x{NQ|e_T(6H214p%b0Jw^h`==Fwp7Ton^SfcwUv#k-Bz4s zb`Q2JrkNq~Zv)9j_$J3%E^%8>pxwzZKOQg2ntJ`U{%C~c*#^4rRz{_BYK%!Ds>7Db z%qn5TK@S#hQ(P&@;hpC6Ux2f@=d=m*PkjAwWBwTBl1EW^xQ+76knWB)OQ3W@nyd@B zbqbm_pvD9VxE$SkCeUs*o-s@KQO*P&89aIUyZ=iAQ=z&J;Cy|2J5aXbo^Df>&mdcUZxSJ6VN<$D2yHj8+S-{B5 z$bwK1_bNDeP3H>>^InS4VOpw~>eV6CP>9jb;f9gxGn-=feFuCX9fXG3Qm1X_4s-t* zn@;LLXw$!QErkSZL#CLZ8VYR^B#DM22OS<`58&L$vi0D{;L%Ed6=h}p(J6Mkvw|Pz zg{%?i!J7Y-LNg>XDC4WgMqWHD#C-?u4Tsl4mzytOKsuX<>GXuufcT%4!W_8K6%9C z(AS%cY-5g?uO83!Jf#qfZvB`+%q!@v+lh{OdIZmsjD=Ik~bL!17d--^KA59W$fEH`kyY3FRMtVct<7Q#@n*_|} z4vD~|+{F*4ha?{pVusx_;j@eH8Yp*M+MMF7#@t(Kh=C?_Nl78%+qVpa;lzsu5Ot&; zut93I$9&;`Js*p4#l=&$E&bWfrWr1~B_En-es`ypXvGpAjwJVVVeqQga`oBCiAp=E z03HR^RX#d4Dz%(8A_auqtGUC?v5>ke%y!y0W;X)!n~C28xo)gwSwT`3n^8_(1?rQ~ zPe4z@MrHt;zyzW$)rfiM(UP;MSpxJYYWs(h-p=bkt?V3yHLO|m8%P?O?x^dG8NV-r zhR)7dCowbR3P4U03Qm;z#(Zu(PD;-~a{m5OKg6R6IgQ2DDclDz~$tHhWPw~U(3 zO*eOt^DoXIW@u+OGQ5<0G-)f>;n4OAfh!zLz-)@}ez#(DZ*1RP)1bFy+^>%_I`61G zb8%`icrw#4i|87&8Z;1RLpzFgx_ZXfV~jt&^iZT>4;ild6uFhXC)Q))ixf&gW7RY^ zbl&>)Cif6$L>cdn=)c54eOH=8Y5PSDcG0wY3Kxil1}cj3W;TWaGz%cp=Tid&Ob~zf zi>Sa8Pg^9ZV?(9VsVoxN7VLLZ!L6!jpaXGU z#qb_~xXz#k8XF@V-SU6RIOS*A^L6uF`v`GrCUezw(KX#f!ILql12S>HMJPcD2&? zMZdqqs0PEQsaKvA*2>u__F}D#I91UW3X%s)DCMYXnA-9^&`bLxuff+EK7X-Q2rnGv z=P1*foiIP&x8GHRsqChpKwH#qnL0yWRWe0%#ox9lNAFGxe*aK4bWYHvn8#?8Gk^h8{T&FT#!PQ2&XX9JE?{XutVDT-i0Cs1EJKS%0~ zpL&*GpTUe3^jJsg2j`Q>$azq-o2GtjW0o&;LZnDI4+}nS`YbGnHv$ooF|`_a8o-2{ z2}xB@%2u+X<2Zg8y?TZ`fstUYemZEn}~(6y?! z_a%Or*BHzi6Z1^g53(}pd0*AMZGGbOZxrneQ|H%_Z9scwRYvWX)jYf)o!Ru~Db^)I z?Igj#&y^L78mhlKx9XQd3t~O+eHWd?*a?tb)sKwSX^R@52CnQRif_B(pJC1n;*>^4 zB7($-<*-0;k`pkGD%WEC{IqiP9se-Wz^GssuH;lAlp-$!6H2#55Thv$z|zi&Esv>x#&}e#~CpOp~tC#e`M=<)ONB^ z{KVslVT4kmS2(9D(SY($w?+;b52!Whq_w~}jjoQScCG2>{#g}M=q z1?&JFqJ-^BJCb3xz{vDBON+lYi3{>Tq+P*<5%ADaF>~woxs(9oXCJUlV_ecngMtf@ zSJYOW936oKFQl$vg(`|f8AU*z`SZ}3{eUrC9|l=@M6*gq%JG{ZtBubFMTyyTLy`9xnnkvc4p6#I@1Pg+}OH>il6AyRKQRIa&KxA`g zL^bAzB)%WZKy~=^>`_32tadK;vnGw_eYR1}9qwr=c`mQ9Yy+!fMuibgzDONaxe{=M zS3CKCwZ&Yo2Mty2W zQi2I2I>(oZ_zbjXK8t9|JWXGY`wD^qrx6Gn2`|rNS5=Dp#CagD6#LhK)f@3aRg!|~ z;mi~JAvVQFstc2?2cqyL9MEY-aK8j6`reaFys{D^hGE?(3y#vOs$znhr_i&e_g15#EP9vOuO1W#zmMd<`Q0F{Edm}G8>?y@c@pNdGyO;RUkkp2 zuUaQumtZayamW&ShwY78i6}f*hP&2ZyTqgqT?Wdv00$&6cvKcc{5*2Zxy$T6rRdQQ zWcZGce%BDWqo2;Sm;#ahq&c@hXkU5+Cpf#>O0kk-FWM!d-TX>)3knC30St1%29Cj? z%#ezGw8)H-;6LRabA~bO%|{2+Q|i*W3!61P-m-z<@5+Jgs8PB6=oDU2s`qQ>FeGkx(NN9CZ*?frR_%-W##`e zBl6{Uw>FM-&Nd<5FU9L2d(fB6SsneqDu{?t6U~+D| zufT9h@dt&Cbqi5bWs_Pp6qMp9J5ypstCMwu z@Hp%*cUJ6ZL!hn2u+Q3Y(AUxZ{+XR|`oJCiHVRx^{LTPJT_*w_{-OGW*@?vhuABFI zNyhvmfe>j%-qDy^uOZ)G19L*zXft9yh{LsKPkW9x9@r(qO}sALD_jIWK;tF<*$y-R zI>DWLT%3dZ%S%I0f2_5w-xE6yg17*z8vs>2sOSffY{=GU0rr=R*We%nUp7~pG>E_e zDjWAoNM9nzkKbWiiWbaW{5M70hB4W7XBT#R($M!{eDe?ME2@uw&ncs)P0zF@PD6=7~o;*!k~RqWishxtM%`A8lK5 z{T%&<)xP@q90ua&!^Um9AGluHUFX7TulbYbZ{M~O{dda@2Y;?u(9eMdL87xG4-n9E zh43mbUPE@W<9!y2h#w&{Eeq*m)Rl9HJr>HaUFE9xcxBpO>yy>(s(f#>$G@`sZ5aL; zyL*Vub;QJVL~+O2BE3lv*zEQD;mVrGA$F5R{3@65SvuyUeAGkbxQp6uAG!7anC>-C z_&gxW#34{R>migeRle$>a@|Gkw2$287{19edX=mHEM4>Ye@u5`bP8PZ#aeIeQ+Jij z;Ps%TwQ}g}`ts`=I&=;#6Bs6ZKAf6Xj^ORxRUo_B3~oCSd#8W@5(w{V5?c@1*xK#yPR!2l(kL5M-O#B3J=dIb*CV7*MF@?KR`UVd9m3X zfm;sPE@}IcQ0b9@-dd+L{KMxjD@22EmE zB8JmMAm{xh7l0NW6f`FtlygzrE`zg+3NPa_nI2qlY01HCJF(-0nubW!FjRK!ITNf9 zyE>3_AcxTTJ{Eu-^)||iTo5PZ<)a-6m!%czr6N{AU{34b-7f~&644YD&>_5t59{2M z&zX!Jc}Q98I>jEmB4UgV#vyl0!yzOxz0UzIJjj&!1~NDRM!g%pPwt`uNkU>n4UVw^ z1Ttiuj6-m{uq7G9w`-| zY1p;-fi;UKRRpEKc{j_TVz^_7T?#$hp6RV#;N(ox?PYK|nG<(Q z(a~cneB~N<$jt`?d;#|iP~*}zRMUA3_*Vjk$4*g5NEG3y*&kjrlNzpI zm4JRprOh z1V7rmWVPED1X5fo_Mgl-sA}5|918v*L2m_HFKmNO|G}qqx0;V3Ne$>-bkbgt^B3*{ zWqg3GxMyjgJX>N~#po_ikkhlsXcs`&p#W3Rq%}(s+~b3O-UbEkZi^eqGk)CP2CY~R z)i0&~R(JAoP{`bksJst?Yu`B7(!Gti&t1Z=i8w(g<+#&J_?(UrWDZxh1+rR*Y zjGt+ghKmK_8xXRWwuQ#l&VX_RzDIIQ+!p0sYlfumqYC&1a+p&(xe4cyP8q;mmM37* zUR&SLKYW>TAaBKlx;K?dgHVT>X8N&aHf@@Ko+aOFnRB6P!eNtt{PJ1XdaHBV$KA`X zaShZk&L5E?u-oJ3M0h3!(eZ~v+mq>U0Sf8EHuKBj-Ww6G z9V~xxHVl|l(T5(D+*L`qDH!$*NzXbU|%C95w$JsKYaLw}m_AS2V&YW(j@@H5gu z$+TX@9`*~&=ar7EdPm>iaef3NYG-6}uxt*UVMCPS4JI%VjkA)|xhFN!%D_P9+i5e5 zt@(+btvZqTk)=OEdSFfw9*?IYWvm%>Hwy={67!@g`^&i&`5$JBV1#adGPMk8cAyAy zA_+`=a_&dR_ZuE0^+q;b?8Bt9sSa(%jq z2o}d95KDR!&ACM_cCAJ^BGc{|31Z`4Gd*COCVsb8LXD%Z0Pw{f{{vet5q#x*4;}jI z`a9wm(0XX`aur8fIpjG$&R`{1VJe@)6`|4l;A0W-b&Vl!r$M1R1mcG(K-q*3RheC|;)Y1Abg=>*5g66la4K1eEPjj?sC{ujSpS0eEZ<^U!~pd+RAkoK5EMdc`3EG1 znp+M$Y9qh|CFX}rki5b(6l0E66R{~qE~*kIxMFxHro1uNP>9++uyP@D{@g?iEC5A> zo$ym0|5Ge!*b6-@MY$8Fx`BMmRH-4s24J_Xb0v%}wf`O~Q&-8BcRBN1>~IVp zK+u&8VO|zNy=11*Lre%;Iw?&FMC-gA7dCF?yX}0m2fDEde6cBqC&;eX7xi8WEw=WZ zk6@O)1Xnnth+e4Ho(q=*CZUDUnO4KpOt|*&`<}us2R}1;F_p<=DPtUwgOuqfOGNFC zz5_3Va!zF-Ama_Tyx1^ceK6xvi%PD+8b+~Iiu6a)$8=#0k5asAALl{vP9`5srX;tTlnl)qqh@fw1oB~|%u$^E> z2jJ7pqUEqZ6f~PWt>|Y*^Ga(*be{_cj8f7(&XHY6QxUrzF;zs&t$k3^7(GzcCKvK_21_QB(C-+ZZ_|1)hcou#H%jETxvw3%qJo|oX?^Ke;+Z?(@p8O5rwhpgTfY1 z^#hKGUMQ0DiC?`%abCz^|L*FlA-L6z3u-|B-5$JlR|qqY?v#MqVGn4?iJ)LY(o!j= zr=O)id9LOkrEO^(V$9f=7#j-9hqv#@l*4M@p)VEk8}qpvM``!nfsKQw^J1JE0?FO* zXhkLV`rzDj3GyF{pxE_!WxJt_Xf#e%Ll37_skjT=Gh&1k-kE0C)iFdkm=W1t63!-t&RwUPX>qXxj_E|$BS2{6AjLHPAgnO2HV=i5F6D&xa1>j z9nMFzf!b4dhds&5DSY56Bo*WWJ5CtZU`gc~biu%Bm$uR)))|b|1Zi+iv)8lN|CG(} ziX%rQ_R{$R0o;0}U@|?2zp(W~k43fFlq7Z0Ym$QvrZ~jv@vl7xs`ECrRwy>lUO1Ez zGvWsP?rl3@33-ZF#P4VRD`kvcCx^+N`B$5(w>@|JFEln%YJXxM_%!r;4`Xe%!9Q3m zn%)K(Tm38UmI$ni6b&cq_q??ki{X)>?b=i*c{=zm$)Vxeb+F3_*{d{yQDse=qJ8NC zfkN&s5`q#pA+F*>HL&&0_&INcF$}`erRe>0i0%kPt4v~Dx3V~ zz3GmQJ6Wh}C*AQAOsB4Law<|z8HsV(p=Ia}TGQiMQX-a>)VhA)QYV#2pmk2v^%AdV z_FX0=2VurBW0PZwDn$&Zi%_%7AB_dbqp6Yh#x(bxCVum&P=QJ}N@d=_R_l~umt{Vb z3t3GBf#4=#Z^Aj;mc-uPJg0yB; zWH3&DIO0E%(Gc`7GvS1b7+dq-s^wXzltRdX22M4iA@x~9qMZ_$uZFoN(A==y5ioV5 zvo8Qj{=y(YuKj9BM}kz@_7BYi@Hd$y{W90=_0?`Wle`Teo3EYRViu z<2uD%+w*Z%Z84W=WX?o*lT|;tAho(`_2BtGjNDUrX6?49>*$MZ+qP}nwry6$wry2x z^NW*;Rbj=pUAx9V*Id^ad+xoib==STLC4$f_K5b4qTK}q*j{GEE94gPofq;s7L|k zUUQN3OTB+;Zpk;;%0v4xrEgmH=ncj=u_Z1Bqj5Zs9GmTV`?K$(r3Bd!DIk~mN3Y>j z?vK2mPfd2qblSKZJ(yDS{DM+3>L*=qopppl{~%KLl(0~2D^b9Ren7@)l5XYdBZ>4l zfEqjV(p6A2w+O(YgZv!xYyD{MpGz2`qUdkwI$S+^P)2c z)!j4=bF5G`^G(%B?6sjAG-k>+oS3-Xed~7+t@wgiTz@|~TQ!eGkE#_Kq_*rMWD((D z#|-5vc|f2fpRzLXEYUS9koqjZ2&OUhlHn%5UNK{FIra?J-~6|Nl7OF*nE=DKnhnT0 zY~`W2`wtXlnBOH@2)cSl;5*?5j>92IutC#ncSo?b@TQ=>?gAPuia{4*2pKbO=R*U5 z2bNlW(UkrI&B{BNG>*~%;>rxSQh8H7$(9S`X+mO^`tC9(RO=daltd}vB#Bm+1MMC2 zauOg@RE*JqX(abt{_*IF#+M7qA}yLm!qXPXYCUVaT!md@
BfNJ=m2=q!?90qIJ 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

}HD$lQ^y`&3t|8ok0Q zqvlGXPWmE3Fe{hYI9oLQxVUfBE@+X}5%)ogf6PlAJ zo`;H`i3~iyO!AAgqFQV!Cfx;zlQms}sGXof3mwiu5v1L0%Vdqy#$4c=VPpu&;u{$K z+MtX!7LUY#@DsWVWdQS}eCrRF%(_FrR$^butBEEgEqSy-uVuSgUBG$fr&w^;oIF2? z6jY;Yf?Z#-)yzIEO1;TqIquj6^bQbejr=-VF@i!MS;NcU(9P%>$3?+@CubR8l{9%n zf}1zu`hBEn(uHV1dnT5B*n4FtD(&*VOZI||uMFv0+u4I_tu4U9Uq|?L)V+g{ z{{qyW<(PPE%3?guQn-7nBL8f!I4_b{qtVF_aRlXOn3?z4JgMLyfA(03dAqx?a486O zkSzxXdkr%yB}iO&&bW*f4i$3Rr9YGc)C{6>FFq%571@A=EIJf z4^*&OY?PtNSDY@(94sD|*OLO~Bqrmd#)|K5jc=PNPioW3#Wb|DO7n$o6^;fkC`uHI zm8YIozRH{{7#CUYF?G7?)xGKhi=9<(O;;R8=%Vm*)neQ61SVu@-Zjhu`L4DQ7uWVZe<*@zjE6oNjvtN=Sq$QAJ<|#{CjQqOiHpU@uC! z@_KhzJs{fpqgN<+Y&JCtr0+o1$1T^J&BkuZZ<0rAZ?d~nv*B9okKpn_p8Yubwb%ret+;wo|U}x&%nxTgmPdl3xst4`UVT$NJonM80s|!`|TS;f)@C{eG`| z0Bzy*75vx>_EVDVyA8>{tPp-ssp9TM`);ewKF4I=2`la6YPP%k*~36jt6zs3@xXCS z{kSj!f{3klzm5*^<@?VA!lCXsUPYs^>TRHwAvy@f<|IX*5}v2_w)uFV13|?Ww*hC> zUMU`vs|2)#)T>pn3!TQlq;$(c~*VZ&;#}Uyha}}`s8%p zDCPT>pHHCof?G&t5wd!{WU(mambv)to{>aOR+E9=*Cxwnnic#7O^iP=9&AS~FHAW7-9v3a_6 zxy0I|7SHmUr^t=ey+p4Mc}xTNB9@V17e2bWghA46gl&NlxZrv0PucOkY8`#vE-DeT zTOSe--h3t-&d--+NggqLFQfO+`87$abC^x-j`!-t><(YjDwLq@pbrz8@gM=cHJt-e zXDkjm<0fIBn&+@j}Wg9!tNQ~o?f#fc1cZGgLXh>O;XPk9Rp6Rt)Q#Xh?B6J?F;Xs__ z_iKZ(H+*aBLOAjW_Cp7;R1cLmL(nj)n?)21I*BNk+Gh#w%xMtYZFY~MS*}s#QDAb4 zIWKf#^R;8+fUV&|s#HNWvSq#W$0eYo@$kqb3k{3GmH}mbqAl#lI z%ua_h$y&Y_3?)h}*py`eym7kH>Jh6pMH+Q^@gx0*WQ6XB)EzV(6iD1O>$$|4^4Kt$LOa4GsOWO<#Y8le0D6#yEG%kzhU;u#iVZj!USBBD?vl z4&w6H3OZ{7!w9Z5xoh|s+$4q-D!IJ9x@_2t^yzyh&~VES3gI~0{pc8^Z%-^T%p6HD zox{W^#QT9Fu!4OEx-o{HOO#f+V9j3}PkN z$We3P5`lsm!MW9Fb)HT^G}AN_1vC1}7^yD8+V;RC*O2Q7LFU!vj&tFR(mzCwO$#Lh zT-_<5{|)FF(bPNgV%p8v_bhj4Bt)}gx(b2muoLe4l<31?JEsZxn<{=k4qS2~U-|S1 zPF>*)1Dq;yuj2IRRm-kxiL*ziTGA!V0Km@temTpEXb2x%ra#5lojCe^QGE)>qXWYG z|AUv5NX+Cyi+7;26y}cHt=Flm-GSl>28S@E>IyF)6q-|cIxR~KIO&0OvI=8V`kP5I zM|$os)PxgBE?UZ9f#)fwhR)B_cq1{@YMiD7sb?KozGn1)rs+%M0hAY!2JVm!Rkm0P z)CzI_RV>PRI2Ls7W@U#&Ml&dhM*=qnY)x40COD!>jZW?i4O|F!C%eXUR=|)%+1H8W zr_5M4OBeD$!?WuQ3kDa3%^C|;t`f$qyFHG(4kOdki2N^*o1^-Cg~z{ifH8-$7`TUvjh|)hUnB> zvCd}V*K|Po@57pAf}@#X{sU(C2pE+z5I92vlXP$(m&o7;yKK2oKsjuNIdykRRGKGb zMB>%}153ZJ&jGo2jwm=(m#kj=m(B9Q@Y(x{erWY!HG)~bfO-LwBN;s;`uMHAS_s&vOle!7I`q6Ecep?t%P` zlF5~G3Kc3gaKH?mrRmT`QA|{Dz<2ot3<(oWP>Z3n3WFwH@gTwb>FlGzRnGI4~Ot@|;k7^rB}`ms**O#lrzRle6+b4qKPjlX8hKOk!y8nH#Rf#Ny;x4Cv~O=x zhS^rd9P|8c*`#7Wc$UA7%MZrug7un7@%Rjr$(wpn^4*dBU zf4lSJ@4oU?w)_kKd%61$yPe(ty?lcIga7Y;$Hd4#QXRR)KU5D3k*pmDN^KMUc0Q#$ zMlX?O7XaB-Kc~iL&GYB8OnqBrI-`rrT5^oOLA&K9MORuym(cQRLhh#;?X37SE9b#; zEn#xHf9Hv`OCfN&Rm(Jhv5#-ha{qfF!rsym6(u|fHz~RWo2_~~9#ofVNhR!RNg;H* zICq^q*KsaM_fgE(zlNmodS()m1*_h0#ZYb0FnKBpUCb^|pfc`J1M4T}j(Y84i6n(M zW3l2|dTjXuWN+vP*i}a-jL~|D8qlCf(~5feh2ob3h=Xg9K@)*X$cyAgPj$+!HC5aWG9b$s^~v&>@LF)4(=>Yd%6+& zo#y_>v?khu1U|>R!1jE@3?}5GR z1Cn}1x5Yi=R-C$s2pARu6fF)1DOWKZD{SMO-sFkK~)DL$1NNT1$8wx?VTm-mhSJ3E` z+NE&)yCS?Xc}=n^Y{D;F$ObK|jqa0$M>#k8i0;<>Q_c6(W4W6#=(bxsgB&}wOb`DORFJOUHbFa|Kjwv2G4TcT2cskFe ztgs)yuVY-fAm=&kfMQN=LF-o07faaD>yk4L0;j9aPfI{G2*lPf6X7m4525PfPawS+St6S2=Thg$MYsNF zlJR(!hq32|bo&#YRF3W3qNyZ9bwTk~g$&GAbR1(dn98KPsy>Fs%RJ`>UwOyF{*Kch ztn%PkIFMG4A0jl*6%s`t97nglij(upg8Xv2b2PQh{Z0`4Nj+TQC~CAX# zG4~y{N;~P*AxcW(mKvHp%Z-clz*d5Er@)<+5( z!AZ0g3jb20=-fE|7xGRM)C?0xNKauvmu(tI5bbR4wFV~4ztM)61{{4)Z?(a`dRJ{eTZvv zr4rf;A@Ge53s}2}%uZww7*7aL=!#@?Xmn@~{Ts2pT5E~hO(l!9M$(kfgC3~Ql;xvG zIVitgSLen0$gNI)rOD%xenci5NJHmtA177Du_IV5HB0M~g4TBI=0Hdo=n^GjHm2Vo z-y<(yGR2TJlF(1s!3)DFhzAUYXa*Ont{r=G3l1RKI=C6n@+z63d_{u}jf^ly{D#g6 z%zVK@Je<_lc|(m(kmGVT(;pX3E1FdD=B?{@^pI|!<#+bG zO%K!Ww5n5EXu?w+CJ@NO=zoSIijW1 zhMswkw4%5a8eRv@TWQa{cazjGg%CypB*5y21bcE`%*PUVUFoBgq;i@C7gQk)zMSB{ z#cj%1Vi>9RUG}J-^*d*aU@ihw;U@x~mC$)-HUB#|1|h0o0X%4lxrtnNXsTu!NEO@G zdx+U4a0%cx7;tMQ-;d6n6%L8hX-Yf}brvZ2PrWw{Y;WVV8Kf65$=IR&I*FuHpS$7R zII8(C-ZY$g7`;-o4sJ=0%L&}b_3eN$7uh_x$K;M%>*(~fZ0y11)XM~Set1^Gzs z8{^7P<5tgSE3=HZt34^QhiAr4OL!syyjA+ho!wQF+r|w!bhMuOhB33ud+9*@jUTzx z3~o(({k2;07AUlW5{`~+O3d3PjkqqYLslVao>w$y3@6_T=$`W^R2dl~IcpbqGxR~1 z#41N<%XUd-3x1u`4BKr?Ee+9wt3OrQk9(Eovg17x>Kk(t8K84DtC}akW&axd zEwv2$)aFBZEp)OS+IL;{qdP2~^{<*$<%Bx*xyN^Hr?|z7zhbfzL8+}cph3d7Q?)4b z90Bi0xR@xWBUAv!Dm?=c*-rVs)zdCXh8eGaDN*47!>*tkc#s-~KBfv-Q zTs_pA2oaKGxk4a~;Y0`WTn}X5s&gl*&K(jY+VJeI`A^ode~suxCuE`Rk#*sH-gNob zsxc>)gjxE@2F&fJRkWtGs0~GvTK^-$^u&8x%NVWYQ?=ks6Lj?cxL^-~11i|vAH>wb zf}T;W^@HBa?g1G4oUR};P&jd=EbBzGRTsC0$X$(-9Bmb3bSDH5^X2Kx_`0kFvm*c= zGeQ*Xz(5a$PA)TMu+He`n0GqM__rdbRz)`JS*>1*kGFZsSdBzppesy>b%_li+i)I) zJuqN#&{x|`S z^J4Y>?n&RDmb$dD_p{e@Dd>h|mrv1F43S)~11i)J2pj{|Af$TAG#^H;Je>33e0v+5?Q$clC@gZ@6jn4( zla8ALk$6YU;9`}g$&$B4+L~$<^5akrq-3nrXp=3_ML9~F)A3MCCeW;01s68bS?08A ztTr~;^v<@AT{)@M$;;BL_aj@nT}5W{48jq?3fAl-CHduuV**SF+qYM@4F=M7-OlGb zh)Xc^mc|}%2)Z;wW~%|Ga=Y1lSv!_M5_8$TzIph zc*`y~YRo0Ev;=F(4&l8eP>qCuX;bt=x(p6HbOI8&A0$K&c2vnC%t~#E3Div|;$VVX z01aP0TMUmFr*N~0>l~M>(2v4h)9M6jSVNhx3VRvFE@q##a{nQ7)uX90WRYVYL53c0 z7J4-bZIW+$o4<}QKQgcFrd6<$MIccEzjIsIk<+5v$7MHBl^rzX?mtAf4oMxt;gRf2 z-5s)DV?gP7gG~V5mDzLVkT2B@ZxbDfZT`Njf2f|E7s7Y6N-Ado4kUB ztjO~(#(oI>Fo4!%TN4|}9v3??S=4GZP@oK(w;mNoe4!$hukpav)tqMsU2l}Qgob96 zXpCgkj(Qv2zpHGa8qT7{8q2KadZ&B9<4h8{Z?1F`T!K=~H&x2ly4>0VtP#b~iVHuz zq8j7lj1_i@cJs7y&t&2`#!z2s(2*&=*>*6A!2b3g5@YSjjhY8H3{tH>xeqwCX3XJn zoOV{6#zwHpi2oJH*R8a3(TN+*d&-Z&9?fQ}H;{4WpA)>Pg#y3v!ld%~7{cqnfh-*3`f6lJapQa2=gnMfBJF&WqrJrmZhW*!oOf1l-a@~KcF!|pBkc}*0mo|I(r!FZk2kg{UdN?3F_ zB#Q-DDthgEmE4&(n*T!fx2yW5VOD2dx>}afe+4#wZ@`tKx*6(XZ3x3ODpNokqNRlz z;L8Z%FBRAB_>3JktMWp^ph3?iEY;q7oS(NGf9IF=Kv0p@L7mT5B&RjZW;e-g)c}WP zi*|J*Ss1+M8`nlv7~=(>r+c#j7s^}OWF5cFLv5jHj6%_5)OcKR9dZgnP{Xjs zlP9Q8A7^T@yq#6s#FvNO<;MNglASTF`4gBo%K=+fgt=nlT3{PY3@}^2l7X_BTpSWU zQCc6$mYX3J$Zbm|V$0BCOSDJUI%@V_)z{nI+vi+v2qXxi9Y8+gzN_Uy8WGx}IFjiw zbBT0}S<|a>tuD!VFVLktnM*QB=^<6Orn-nC(F1PInw}Xbi6Sw6*KvBBE88=TUW=`U zQb8HWP6o&Or+cG-gzWSP`OS$%TPqC`&38ncWK2lbq`*DPLk`?NQL(NiAM=fP^0C;G zkBwe+MF*d?@90b@Gl`Xhxs}o zws?3t+M;(NU9f-A@gS^JVrb~Mq1VIH!=BLl4o6B%eAL^6W#|sx2oF5X{-Af#?F*Cr zV89f+coV|PpXH7ce}HW`qGRNzXKHz*nv0-Op{mD8cI@j~m;zacg_XT+lDem`{Db}v zJs2bM+VRfo{b8?nGP2vy_eD1NH?qM;k|WbZoMPr0x> z$9Y^%4!kNz){)epDTRoN6-uhy^Y|+FLn`cy_l{&0;Uf$Y!l2aF7oTqC$l!PxdUWeAA|UL9%df#lpv0j=6-=26`V|*tsaHM6*jIz8b7e+515HqL>B9|e-UUk05(D8g z@$MwVIADTxnz8NBYgdSUK(7uL7#1*Fw%k?==)^0Ok0f2T8^s5 zds~E!E|1-8a-b#D+w`&A|3HgtHH2itZYgFMc6R}!u}OwR(0IC7aI|?_iV4Y8BXU(l zaND5#QpT=ix!Fn4wN98x^fP!}JPA1aW;RwVse{#WO+2chjzvk9)Fbpf&?-CF+?>8a z)R*)CZg`p|-poZA;9*_R7fiW9x+sf;dEvb|Y&8?o_kET(j?Ua&wE=vCQ2}_}H%N3T zad6^gO__Ac8y$3p*hy)wBzyfk9}klIF@=qglMAtoqs+izXA`3eu#1~A%qc|eTQWM4 zUwkv3P>ER7G&B(WpOafcU1BWu#FGi%u-XTD<6eKTcX~J+p{C8W#_lV2fN{|wUt(f) z6`}1IE>~B5A}l=N%VDT?9h1gvv}#uw&=tiv9<-^n?svmeWPR=poK2(!hR71Z5?8*6 z2G|(*3ot8&U}b4Z4PP_L)rqpjqgED*Lb_(^{i`kxmI`mIwYKy@e6bdW!kSU9`v>qI zBB&mYj!#bDM=`wf@Z=O5ebMb7oKp3Tv;44o@Z$7nkDHV3Q=u=IRy9x#(KHMC$#27{ z2+H(vSw3EqSKaS>T%8ZhG%&eb?IyU)*VN~W)CAE%24$(FZM3M6nwzR4`Y&-7_Iq70 z-LN7SEeUkGfAss)0T{SonVlYtv`UHT@X%JQ3dz7j{%_nVub|_jAwTUqiFV>K7;f;U z{&2rf(+P&pF&lr-<>S}VEG*}cMm4C7(QlBI`vbPqF;9?<_Foj_LP@t>h!rFpsoz&3lQ1XOUgo^ORERHKdqQYW7K8|W>rX|m@QH)I4%Aw z%AX90X`cQr+UvaNpc($8v-|mOv~`S;i`{R&`Eol}P5~UHa8gRU&T}8s2wVGudX4Bx zVhTR>VR>{R!%yo8x%%dm8`^c1L%I1E$WIuoaK^uC2NbhXNOsJ4p(=Qr^T|W zhbtV;PT;NReLx0Ury=0doI?*)-O;?wIf02I$#jc^ahH&b!m8LpMMf;b9Cv}aKp^3H z%D8Si5B^!Vr@=@q%DE<>gz+Q?V?4{1fGJx`Q=|+!%d3<$IC|Wb z`aw;YGeAHUOi;L&No;3$E2%8rcUx+@f^rL*^Xyi#+~{d|Ej})d+E!xk9h()D(8f1H z<2oo1M0`iq)Hw}+e@YjJF)3h+!wb{fiYbej{p^Z#WRZ(4soSSHML3TnYP(0o7|LW% zH$s9ygQ;fp^mAdgq0F0M!eGUhMKP&_ja+sFZzW{2<=ZEp_?y!I>Lw8foPnh#5ivV0 zN|Mw$+b7mE_D8%8RZzS7x>RN1W<|u?bL0sPv(T)QS;Rg?0CK(KK$y~&V5-?H*zGf`oTw47h)_d!Ucex9u*NUsh&5SxkEs>{ZRc;vE?aS7D zx)(SE-?>b=&n2eM=DhUV5h#?!3@M)~0-X5VaHg?RZ3r)5VIhQH@MxfAd8g2!`M{v( zkBQwgJfGwgBQ|%K=~!KgR!5^mbfPNbok1UF%z7|S@L5dKwNBA%9uex^CG=vPt!$LY=AMp3Vg z=^}buq6?&19HxF;Pl!9Q9_aoS#;)3JQn^)V60Y(h@=7=E_Bl zxKtepVM>3S-;ev$fOcVzz(Y$z50^6E7+Nr(PtTS@D^yj*IoD3~xlsN}VTQR_>OfSk z=)GPvcpWV-&HqbVFoAmxb-l3?g1y&`@Ky*Qp%LQspLJH0!=f#j40-q7EY1Ht1 zG=Zs_CBrdaya<|wtP$wU9N)M8ccPal{;*>Or>}{fF9HZIjkQs{GQErL-PT9nG9%wM zXfO&VF%3cKIX3ZybjwOKPzpz%H<<*OkVs5TEQ3SL+9Xb#nG^b*;H{dSSSzINWaA>T zHRLn2V{njEZdl~}XB|G^>NPQB4<5E=Z?%98f(qjjsE52%ch$9)Sr9XYVgnfwh@&+# zOhaBoRYF`PTW3VD-EMSiJkJ&*+vs_xwdld_!;2p5wiP{aIZ>TyHLaJdNWb;19uE&( z6OUBC!0*l7U$A;X^l^(9M0eIMc;wOr(IZtZcu?Vj=&z-2L0G!%zEukzt7t*=E38=% zee{wA!iRO=iUpPp`U8|Hh~B$O!2^mEe7yPu(f!L4JbHD4=>EkCK4M*h=)KDle9Vdj z(FZR`(5y!gJwiDGt}0ecU0O8eG>R8H(Q~3T3-o9+z)7GbzOGd5p!o3i+ zGPy3YiPmnM6w5KY7)^+W+HWQMYRf5b<;UNrdm(!Ny;iU`eJwQrK1?Nx=$9yD5j~)e z#YZe*5j{o)i`D`b@%wF#73D8JV&#kIBNe{*1uque z3pJahR&Ha}fg?;aO-bcX--S7C$`XA9RUjE~qs((Zu zw)jU|>5sdrehfngt_+A`>so)iX(BvErI6^u6bd0Mc=8dr>%;V+kH%Xct)Z=_v5!9{ zZGH67S?i;ZOpV*AIz4cKML#k*bHh zQyq`!jxrwjDOrwrVLaG;Ln59X(}`iPk;$K04G1MzgH+{LbV^oxw}YSofhC-yqA1gg zf}rtt&z43EwjiOx9^F@bbX=F44y??-Kn& z)m@_ZEAH~Z+Ah&AQrac@h?QNUk6G9yGId?T0xr#}Ee|Q$68#c2TcSrP*-|Uc(x}Mt z4h31Fk6Vu=dW3Q;Gy#)NOEs1cQ;a40*tJ-q2bW@blu9ho$1lVZy;~iY_bbB^{Q^~3 zqIWIA@~$;lqK{sJC3@rvEcYqE68!@8SE7$uekFRp>MJBFVHe%2_R3?FUWqtmE$p))w`+@s>kqZM34eOz_g+kw#O_AkvH@CznA00km)tgub>zhDbU(Uzu zbbat!`F+CQEZ}jvUB}zJWmY~#R#O1>@l!_}w=u}o{G1*5qAyNUN*1kS_q}retIoa= zZX>^KIDK`^h7psNG6NC@d#CfOnF-0ZW%PU~SyWH?iMlSpg3I0v-RYro5nwf@-skeT zU6-%&p@!a;(DG&H9V(o?Q-QPSW7ao|K6-hx=%ZIRi++*fX3+y`o4sFYv*@E&HjA2t z&A#fauW0tT1o%6?`XbB#}#Ys9Gqy23o|iS`8HjwcFYM`Um{uO zsq|92XPQl`?1Fw_sxZ}jSXzb6)FUu~dY)Y&VEqs^=%O_x=uqk_LX6A}t4{HLO7F0x zIv=QrU9_f#o$8(MP{Qt^73`vqSHLd%CF<8jzexGI=;Kzei#~esy6B_Vu8SVAbltrx z*G0cb;kxLTs9P7UC|jqd%iUG$9;Ikq^o!K2i#~SAy66|ESQo7+Sf{YK`_-#^|8jNF zFHx;7dhB9#SgLMirMeGOs4n^?>eNLazf4{9QLEHNAHPUlw6;dwhbd7Peb@?htp)0$ zk6)iIYAsKP#p%}6rhDAdbkT>cOxIqRF8Tm<>DHE|i{7g$9oD23NI|;j z!S(3gyBuBgk*m=~rWhTTqN`P+`yhqr`qMkY)*r46U9_qS-G?kf7d>VTx|Jp9B*Vd2 zB`b^2HOjJ?NqqnMY|(wovpq_6w&)#-v%PD1wCKZBN5k4^AFDK4^pPv0MekS`?Y-)v zMYXbM>uREL5t-=}ZZ?Vm@@JGu`d)R?qK{uDE&AwH(pDzhCX;L4Mx;gf*_9Prhs=q6 z>X;$EDagdT&R|cZHQIlii?L6*MWXyRoN=wJjAq<3dSJPj(ew5;{IX+8zkQU-Z_)b} zetU4;x9EM!zI~LcZ_&pr`gTXnw|kX*d$)>j?_Tije)Zm>_b>PMKGoiuHDMlJ>+P?o z)Z3a$Z}%wl_A9CL7X1Qc-lC6K<*jzuZH>2gEb;aW7kGYiaV<17bFH^P52gRD-_o(emX+>|L|)E^hR zlH3C546S9YJ7;;=A5QQ0@LG*E8XHyfT(}~oaPH)a`-YAQr-iEtgY!Y;Mbe7fQ>bZQ zAbX*cL|o!CDCy?5tSG2*- zatEHi#rUggJXdH+lZD0fI3Y?6`tb!Ea)NRAngdGCpz(6p7qVBYA`Z6mS)S(Tf|?VF z*dm>|qsh>pkFxC=Wn!p!?=8)bSQczvwh@)a?Rb1P#*e6OwhD+`&cQv(aJtH@I~|jCh;6iT5if0?t@$=PFN<|w=j$F`&KB9#EbW#hY*~;G{L9bW6Z%2W2lrv{YX528^3&Rj z5O1+_u|(&zzU+^vq5N_3#~ui+B5VK2AWbHJJS2g8JSA5>`_eE=p zB}-VjQY*M%;v^~UU;v^WMuG^o8=NSNzD9dXR^kI7>bIzx@CKV;4vK7g5Le6dS+TrE z9h$!I6@d4;2dER)&&ytUd$lOYM*vDG!kF`7erq+uw#vWf_Nhc3Qt4#0@g2P9I+u(2 ztnDnJYrkDj#C^QJXK{4h!QPSFBkk~xk*ux$3-abHr_B2s3gwYkmXcoxFpQ~Vjoe3n zp5%UHYZ`=`TLwG=v zm+18itc9gG*?fAF)dMu=FI%`xBijkbMAdE;Ia=*-jRA5}b86CA&ZaQlio~6KMK0FV z1wdNN5DFnsXaKuqioT1>A)qmBu~NbuMpQlVYPsg!F7M%8jHt|lSs(Qvi(*>Bdli>y z$Oq{$T1!=XUDz3`Q<#W^Y2#L(_U=7|0$ioy6HI3=Kod6q2DNHd8hosr0`d|^d}D~_ zB(UfUU?fsf%`Y~ZGq}!lN3D%otPm)614zwgQ;Hl1o1pL+d-X}wYI90s&CqC z)ksX$5gv=sR6ST@s!F)EG-j%Le!K&FmE{_`hE^G_q;o50iZNOvv02~T!(7D)+YNGp zbwS#5$b(vC^lD)-))~#1c*~D5wx#05VK@)DMnFRz7o}$ℑc(WwUU~8|ChA- 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

yY6>DyCf6m00WALD2mo3pv`VbM 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%0DvJt7NlM-iLQ_e?NB$>kJ}4{J}l~@mW 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�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

)&y%A~m6_f_ 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∾=d-c{Ei{Ia?^uIJ!cT?DZlzKI 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

+ + diff --git a/maubot-src/maubot/management/frontend/public/manifest.json b/maubot-src/maubot/management/frontend/public/manifest.json new file mode 100644 index 0000000..a76f730 --- /dev/null +++ b/maubot-src/maubot/management/frontend/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "Maubot", + "name": "Maubot Manager", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 48x48 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#50D367", + "background_color": "#FAFAFA" +} diff --git a/maubot-src/maubot/management/frontend/src/api.js b/maubot-src/maubot/management/frontend/src/api.js new file mode 100644 index 0000000..27b3ff6 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/api.js @@ -0,0 +1,276 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +let BASE_PATH = "/_matrix/maubot/v1" + +export function setBasePath(basePath) { + BASE_PATH = basePath +} + +function getHeaders(contentType = "application/json") { + return { + "Content-Type": contentType, + "Authorization": `Bearer ${localStorage.accessToken}`, + } +} + +async function defaultDelete(type, id) { + const resp = await fetch(`${BASE_PATH}/${type}/${id}`, { + headers: getHeaders(), + method: "DELETE", + }) + if (resp.status === 204) { + return { + "success": true, + } + } + return await resp.json() +} + +async function defaultPut(type, entry, id = undefined, suffix = undefined) { + const resp = await fetch(`${BASE_PATH}/${type}/${id || entry.id}${suffix || ""}`, { + headers: getHeaders(), + body: JSON.stringify(entry), + method: "PUT", + }) + return await resp.json() +} + +async function defaultGet(path) { + const resp = await fetch(`${BASE_PATH}${path}`, { headers: getHeaders() }) + return await resp.json() +} + +export async function login(username, password) { + const resp = await fetch(`${BASE_PATH}/auth/login`, { + method: "POST", + body: JSON.stringify({ + username, + password, + }), + }) + return await resp.json() +} + +let features = null + +export async function ping() { + const response = await fetch(`${BASE_PATH}/auth/ping`, { + method: "POST", + headers: getHeaders(), + }) + const json = await response.json() + if (json.username) { + features = json.features + return json.username + } else if (json.errcode === "auth_token_missing" || json.errcode === "auth_token_invalid") { + if (!features) { + await remoteGetFeatures() + } + return null + } + throw json +} + +export const remoteGetFeatures = async () => { + features = await defaultGet("/features") +} + +export const getFeatures = () => features + +export async function openLogSocket() { + let protocol = window.location.protocol === "https:" ? "wss:" : "ws:" + const url = `${protocol}//${window.location.host}${BASE_PATH}/logs` + const wrapper = { + socket: null, + connected: false, + authenticated: false, + onLog: data => undefined, + onHistory: history => undefined, + fails: -1, + } + const openHandler = () => { + wrapper.socket.send(localStorage.accessToken) + wrapper.connected = true + } + const messageHandler = evt => { + // TODO use logs + const data = JSON.parse(evt.data) + if (data.auth_success !== undefined) { + if (data.auth_success) { + console.info("Websocket connection authentication successful") + wrapper.authenticated = true + wrapper.fails = -1 + } else { + console.info("Websocket connection authentication failed") + } + } else if (data.history) { + wrapper.onHistory(data.history) + } else { + wrapper.onLog(data) + } + } + const closeHandler = evt => { + if (evt) { + if (evt.code === 4000) { + console.error("Websocket connection failed: access token invalid or not provided") + } else if (evt.code === 1012) { + console.info("Websocket connection closed: server is restarting") + } + } + wrapper.connected = false + wrapper.socket = null + wrapper.fails++ + const SECOND = 1000 + setTimeout(() => { + wrapper.socket = new WebSocket(url) + wrapper.socket.onopen = openHandler + wrapper.socket.onmessage = messageHandler + wrapper.socket.onclose = closeHandler + }, Math.min(wrapper.fails * 5 * SECOND, 30 * SECOND)) + } + + closeHandler() + + return wrapper +} + +let _debugOpenFileEnabled = undefined +export const debugOpenFileEnabled = () => _debugOpenFileEnabled +export const updateDebugOpenFileEnabled = async () => { + const resp = await defaultGet("/debug/open") + _debugOpenFileEnabled = resp["enabled"] || false +} + +export async function debugOpenFile(path, line) { + const resp = await fetch(`${BASE_PATH}/debug/open`, { + headers: getHeaders(), + body: JSON.stringify({ path, line }), + method: "POST", + }) + return await resp.json() +} + +export const getInstances = () => defaultGet("/instances") +export const getInstance = id => defaultGet(`/instance/${id}`) +export const putInstance = (instance, id) => defaultPut("instance", instance, id) +export const deleteInstance = id => defaultDelete("instance", id) + +export const getInstanceDatabase = id => defaultGet(`/instance/${id}/database`) +export const queryInstanceDatabase = async (id, query) => { + const resp = await fetch(`${BASE_PATH}/instance/${id}/database/query`, { + headers: getHeaders(), + body: JSON.stringify({ query }), + method: "POST", + }) + return await resp.json() +} + +export const getPlugins = () => defaultGet("/plugins") +export const getPlugin = id => defaultGet(`/plugin/${id}`) +export const deletePlugin = id => defaultDelete("plugin", id) + +export async function uploadPlugin(data, id) { + let resp + if (id) { + resp = await fetch(`${BASE_PATH}/plugin/${id}`, { + headers: getHeaders("application/zip"), + body: data, + method: "PUT", + }) + } else { + resp = await fetch(`${BASE_PATH}/plugins/upload`, { + headers: getHeaders("application/zip"), + body: data, + method: "POST", + }) + } + return await resp.json() +} + +export const getClients = () => defaultGet("/clients") +export const getClient = id => defaultGet(`/clients/${id}`) + +export async function uploadAvatar(id, data, mime) { + const resp = await fetch(`${BASE_PATH}/proxy/${id}/_matrix/media/v3/upload`, { + headers: getHeaders(mime), + body: data, + method: "POST", + }) + return await resp.json() +} + +export function getAvatarURL({ id, avatar_url }) { + if (!avatar_url?.startsWith("mxc://")) { + return null + } + avatar_url = avatar_url.substring("mxc://".length) + // Note: the maubot backend will replace the query param with an authorization header + return `${BASE_PATH}/proxy/${id}/_matrix/client/v1/media/download/${avatar_url}?access_token=${ + localStorage.accessToken}` +} + +export const putClient = client => defaultPut("client", client) +export const deleteClient = id => defaultDelete("client", id) + +export async function clearClientCache(id) { + const resp = await fetch(`${BASE_PATH}/client/${id}/clearcache`, { + headers: getHeaders(), + method: "POST", + }) + return await resp.json() +} + +export async function verifyClient(id, recovery_key) { + const resp = await fetch(`${BASE_PATH}/client/${id}/verify`, { + headers: getHeaders(), + method: "POST", + body: JSON.stringify({ recovery_key }), + }) + return await resp.json() +} + +export async function generateRecoveryKey(id) { + const resp = await fetch(`${BASE_PATH}/client/${id}/generate_recovery_key`, { + headers: getHeaders(), + method: "POST", + }) + return await resp.json() +} + +export const getClientAuthServers = () => defaultGet("/client/auth/servers") + +export async function doClientAuth(server, type, username, password) { + const resp = await fetch(`${BASE_PATH}/client/auth/${server}/${type}`, { + headers: getHeaders(), + body: JSON.stringify({ username, password }), + method: "POST", + }) + return await resp.json() +} + +// eslint-disable-next-line import/no-anonymous-default-export +export default { + login, ping, setBasePath, getFeatures, remoteGetFeatures, + openLogSocket, + debugOpenFile, debugOpenFileEnabled, updateDebugOpenFileEnabled, + getInstances, getInstance, putInstance, deleteInstance, + getInstanceDatabase, queryInstanceDatabase, + getPlugins, getPlugin, uploadPlugin, deletePlugin, + getClients, getClient, uploadAvatar, getAvatarURL, putClient, deleteClient, clearClientCache, + verifyClient, generateRecoveryKey, + getClientAuthServers, doClientAuth, +} diff --git a/maubot-src/maubot/management/frontend/src/components/PreferenceTable.js b/maubot-src/maubot/management/frontend/src/components/PreferenceTable.js new file mode 100644 index 0000000..ca965a0 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/components/PreferenceTable.js @@ -0,0 +1,71 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React from "react" +import Select from "react-select" +import CreatableSelect from "react-select/creatable" +import Switch from "./Switch" + +export const PrefTable = ({ children, wrapperClass }) => { + if (wrapperClass) { + return ( +
+
+ {children} +
+
+ ) + } + return ( +
+ {children} +
+ ) +} + +export const PrefRow = + ({ name, fullWidth = false, labelFor = undefined, changed = false, children }) => ( +
+ +
{children}
+
+ ) + +export const PrefInput = ({ rowName, value, origValue, fullWidth = false, ...args }) => ( + + + +) + +export const PrefSwitch = ({ rowName, active, origActive, fullWidth = false, ...args }) => ( + + + +) + +export const PrefSelect = ({ + rowName, value, origValue, fullWidth = false, creatable = false, ...args +}) => ( + + {creatable + ? + : + + + {this.state.error &&
{this.state.error}
} + + + } +} + +export default Login diff --git a/maubot-src/maubot/management/frontend/src/pages/Main.js b/maubot-src/maubot/management/frontend/src/pages/Main.js new file mode 100644 index 0000000..5ee374e --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/Main.js @@ -0,0 +1,91 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component } from "react" +import { HashRouter as Router, Switch } from "react-router-dom" +import PrivateRoute from "../components/PrivateRoute" +import Spinner from "../components/Spinner" +import api from "../api" +import Dashboard from "./dashboard" +import Login from "./Login" + +class Main extends Component { + constructor(props) { + super(props) + this.state = { + pinged: false, + authed: false, + } + } + + async componentDidMount() { + await this.getBasePath() + if (localStorage.accessToken) { + await this.ping() + } else { + await api.remoteGetFeatures() + } + this.setState({ pinged: true }) + } + + async getBasePath() { + try { + const resp = await fetch(process.env.PUBLIC_URL + "/paths.json", { + headers: { "Content-Type": "application/json" }, + }) + const apiPaths = await resp.json() + api.setBasePath(apiPaths.api_path) + } catch (err) { + console.error("Failed to get API path:", err) + } + } + + + async ping() { + try { + const username = await api.ping() + if (username) { + localStorage.username = username + this.setState({ authed: true }) + } else { + delete localStorage.accessToken + } + } catch (err) { + console.error(err) + } + } + + login = async (token) => { + localStorage.accessToken = token + await this.ping() + } + + render() { + if (!this.state.pinged) { + return + } + return +
+ + } + authed={!this.state.authed} to="/"/> + + +
+
+ } +} + +export default Main diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/BaseMainView.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/BaseMainView.js new file mode 100644 index 0000000..dd77081 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/BaseMainView.js @@ -0,0 +1,98 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component } from "react" +import { Link } from "react-router-dom" +import api from "../../api" + +class BaseMainView extends Component { + constructor(props) { + super(props) + this.state = Object.assign(this.initialState, props.entry) + } + + UNSAFE_componentWillReceiveProps(nextProps) { + const newState = Object.assign(this.initialState, nextProps.entry) + for (const key of this.entryKeys) { + if (this.props.entry[key] === nextProps.entry[key]) { + newState[key] = this.state[key] + } + } + this.setState(newState) + } + + delete = async () => { + if (!window.confirm(`Are you sure you want to delete ${this.state.id}?`)) { + return + } + this.setState({ deleting: true }) + const resp = await this.deleteFunc(this.state.id) + if (resp.success) { + this.props.history.push("/") + this.props.onDelete() + } else { + this.setState({ deleting: false, error: resp.error }) + } + } + + get entryKeys() { + return [] + } + + get initialState() { + return {} + } + + get hasInstances() { + return this.state.instances && this.state.instances.length > 0 + } + + get isNew() { + return !this.props.entry.id + } + + inputChange = event => { + if (!event.target.name) { + return + } + this.setState({ [event.target.name]: event.target.value }) + } + + async readFile(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader() + reader.readAsArrayBuffer(file) + reader.onload = evt => resolve(evt.target.result) + reader.onerror = err => reject(err) + }) + } + + renderInstances = () => !this.isNew && ( +
+

{this.hasInstances ? "Instances" : "No instances :("}

+ {this.state.instances.map(instance => ( + + {instance.id} + + ))} +
+ ) + + renderLogButton = (filter) => !this.isNew && api.getFeatures().log &&
+ +
+} + +export default BaseMainView diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/Client.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/Client.js new file mode 100644 index 0000000..1504337 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/Client.js @@ -0,0 +1,392 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React from "react" +import { NavLink, withRouter } from "react-router-dom" +import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg" +import { ReactComponent as UploadButton } from "../../res/upload.svg" +import { ReactComponent as NoAvatarIcon } from "../../res/bot.svg" +import { PrefTable, PrefSwitch, PrefInput, PrefSelect } from "../../components/PreferenceTable" +import Spinner from "../../components/Spinner" +import api from "../../api" +import BaseMainView from "./BaseMainView" + +const ClientListEntry = ({ entry }) => { + const classes = ["client", "entry"] + if (!entry.enabled) { + classes.push("disabled") + } else if (!entry.started) { + classes.push("stopped") + } + const avatarMXC = entry.avatar_url === "disable" + ? entry.remote_avatar_url + : entry.avatar_url + const avatarURL = avatarMXC && api.getAvatarURL({ + id: entry.id, + avatar_url: avatarMXC, + }) + const displayname = ( + entry.displayname === "disable" + ? entry.remote_displayname + : entry.displayname + ) || entry.id + return ( + + {avatarURL + ? + : } + {displayname} + + + ) +} + +class Client extends BaseMainView { + static ListEntry = ClientListEntry + + constructor(props) { + super(props) + this.deleteFunc = api.deleteClient + this.recovery_key = null + this.homeserverOptions = [] + } + + get entryKeys() { + return ["id", "displayname", "homeserver", "avatar_url", "access_token", "device_id", + "sync", "autojoin", "online", "enabled", "started", "trust_state"] + } + + get initialState() { + return { + id: "", + displayname: "disable", + homeserver: "", + avatar_url: "disable", + access_token: "", + device_id: "", + fingerprint: null, + sync: true, + autojoin: true, + enabled: true, + online: true, + started: false, + trust_state: null, + + instances: [], + + uploadingAvatar: false, + saving: false, + deleting: false, + verifying: false, + startingOrStopping: false, + clearingCache: false, + error: "", + } + } + + get clientInState() { + const client = Object.assign({}, this.state) + delete client.uploadingAvatar + delete client.saving + delete client.deleting + delete client.startingOrStopping + delete client.clearingCache + delete client.error + delete client.instances + return client + } + + get selectedHomeserver() { + return this.state.homeserver + ? this.homeserverEntry([this.props.ctx.homeserversByURL[this.state.homeserver], + this.state.homeserver]) + : {} + } + + homeserverEntry = ([serverName, serverURL]) => serverURL && { + id: serverURL, + value: serverURL, + label: serverName || serverURL, + } + + componentDidUpdate(prevProps) { + this.updateHomeserverOptions() + } + + updateHomeserverOptions() { + this.homeserverOptions = Object + .entries(this.props.ctx.homeserversByName) + .map(this.homeserverEntry) + } + + isValidHomeserver(value) { + try { + return Boolean(new URL(value)) + } catch (err) { + return false + } + } + + avatarUpload = async event => { + const file = event.target.files[0] + this.setState({ + uploadingAvatar: true, + }) + const data = await this.readFile(file) + const resp = await api.uploadAvatar(this.state.id, data, file.type) + this.setState({ + uploadingAvatar: false, + avatar_url: resp.content_uri, + }) + } + + save = async () => { + this.setState({ saving: true }) + const resp = await api.putClient(this.clientInState) + if (resp.id) { + if (this.isNew) { + this.props.history.push(`/client/${resp.id}`) + } else { + this.setState({ saving: false, error: "" }) + } + this.props.onChange(resp) + } else { + this.setState({ saving: false, error: resp.error }) + } + } + + startOrStop = async () => { + this.setState({ startingOrStopping: true }) + const resp = await api.putClient({ + id: this.props.entry.id, + started: !this.props.entry.started, + }) + if (resp.id) { + this.props.onChange(resp) + this.setState({ startingOrStopping: false, error: "" }) + } else { + this.setState({ startingOrStopping: false, error: resp.error }) + } + } + + clearCache = async () => { + this.setState({ clearingCache: true }) + const resp = await api.clearClientCache(this.props.entry.id) + if (resp.success) { + this.setState({ clearingCache: false, error: "" }) + } else { + this.setState({ clearingCache: false, error: resp.error }) + } + } + + verifyRecoveryKey = async () => { + const recoveryKey = window.prompt("Enter recovery key") + if (!recoveryKey) { + return + } + this.setState({ verifying: true }) + const resp = await api.verifyClient(this.props.entry.id, recoveryKey) + if (resp.success) { + this.setState({ verifying: false, error: "" }) + } else { + this.setState({ verifying: false, error: resp.error }) + } + } + + generateRecoveryKey = async () => { + this.setState({ verifying: true }) + const resp = await api.generateRecoveryKey(this.props.entry.id) + if (resp.success) { + this.recovery_key = resp.recovery_key + this.setState({ verifying: false, error: "" }) + } else { + this.setState({ verifying: false, error: resp.error }) + } + } + + get loading() { + return this.state.saving || this.state.startingOrStopping + || this.clearingCache || this.state.deleting || this.state.verifying + } + + renderStartedContainer = () => { + let text + if (this.props.entry.started) { + if (this.props.entry.sync_ok) { + text = "Started" + } else { + text = "Erroring" + } + } else if (this.props.entry.enabled) { + text = "Stopped" + } else { + text = "Disabled" + } + return
+ + {text} +
+ } + + get avatarMXC() { + if (this.state.avatar_url === "disable") { + return this.props.entry.remote_avatar_url + } else if (!this.state.avatar_url?.startsWith("mxc://")) { + return null + } + return this.state.avatar_url + } + + get avatarURL() { + return api.getAvatarURL({ + id: this.state.id, + avatar_url: this.avatarMXC, + }) + } + + renderSidebar = () => !this.isNew && ( +
+
+ {this.avatarMXC && Avatar} + + evt.target.parentElement.classList.add("drag")} + onDragLeave={evt => evt.target.parentElement.classList.remove("drag")}/> + {this.state.uploadingAvatar && } +
+ {this.renderStartedContainer()} + {(this.props.entry.started || this.props.entry.enabled) && <> + + + } +
+ ) + + renderPreferences = () => ( + + + {api.getFeatures().client_auth ? ( + this.setState({ homeserver: value })} + creatable={true} isValidNewOption={this.isValidHomeserver}/> + ) : ( + + )} + + + {this.props.entry.fingerprint && <> + + + } + + + this.setState({ sync })}/> + this.setState({ autojoin })}/> + this.setState({ + enabled, + started: enabled && this.state.started, + })}/> + this.setState({ online })} /> + + ) + + renderPrefButtons = () => <> +
+ {!this.isNew && ( + + )} + +
+ {this.renderLogButton(this.state.id)} +
{this.state.error}
+ + + renderVerifyButtons = () => <> +
+ + +
+ {this.recovery_key &&
+ Recovery key: {this.recovery_key} +
} + + + render() { + return <> +
+ {this.renderSidebar()} +
+ {this.renderPreferences()} + {this.renderPrefButtons()} + {this.props.entry.fingerprint && this.renderVerifyButtons()} + {this.renderInstances()} +
+
+ + } +} + +export default withRouter(Client) diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/Home.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/Home.js new file mode 100644 index 0000000..e78354f --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/Home.js @@ -0,0 +1,30 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component } from "react" + +class Home extends Component { + render() { + return <> +
+ See sidebar to get started +
+
+
+ + } +} + +export default Home diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/Instance.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/Instance.js new file mode 100644 index 0000000..049c5e5 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/Instance.js @@ -0,0 +1,233 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React from "react" +import { Link, NavLink, Route, Switch, withRouter } from "react-router-dom" +import AceEditor from "react-ace" +import "ace-builds/src-noconflict/mode-yaml" +import "ace-builds/src-noconflict/theme-github" +import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg" +import { ReactComponent as NoAvatarIcon } from "../../res/bot.svg" +import PrefTable, { PrefInput, PrefSelect, PrefSwitch } from "../../components/PreferenceTable" +import api from "../../api" +import Spinner from "../../components/Spinner" +import BaseMainView from "./BaseMainView" +import InstanceDatabase from "./InstanceDatabase" + +const InstanceListEntry = ({ entry }) => ( + + {entry.id} + + +) + +class Instance extends BaseMainView { + static ListEntry = InstanceListEntry + + constructor(props) { + super(props) + this.deleteFunc = api.deleteInstance + this.updateClientOptions() + } + + get entryKeys() { + return ["id", "primary_user", "enabled", "started", "type", "config", "database_engine"] + } + + get initialState() { + return { + id: "", + primary_user: "", + enabled: true, + started: true, + type: "", + config: "", + database_engine: "", + + saving: false, + deleting: false, + error: "", + } + } + + get instanceInState() { + const instance = Object.assign({}, this.state) + delete instance.saving + delete instance.deleting + delete instance.error + return instance + } + + componentDidUpdate(prevProps) { + this.updateClientOptions() + } + + getAvatarMXC(client) { + return client.avatar_url === "disable" ? client.remote_avatar_url : client.avatar_url + } + + getAvatarURL(client) { + return api.getAvatarURL({ + id: client.id, + avatar_url: this.getAvatarMXC(client), + }) + } + + clientSelectEntry = client => client && { + id: client.id, + value: client.id, + label: ( +
+ {this.getAvatarMXC(client) + ? + : } + { + (client.displayname === "disable" + ? client.remote_displayname + : client.displayname + ) || client.id + } +
+ ), + } + + updateClientOptions() { + this.clientOptions = Object.values(this.props.ctx.clients).map(this.clientSelectEntry) + } + + save = async () => { + this.setState({ saving: true }) + const resp = await api.putInstance(this.instanceInState, this.props.entry + ? this.props.entry.id : undefined) + if (resp.id) { + if (this.isNew) { + this.props.history.push(`/instance/${resp.id}`) + } else { + if (resp.id !== this.props.entry.id) { + this.props.history.replace(`/instance/${resp.id}`) + } + this.setState({ saving: false, error: "" }) + } + this.props.onChange(resp) + } else { + this.setState({ saving: false, error: resp.error }) + } + } + + get selectedClientEntry() { + return this.state.primary_user + ? this.clientSelectEntry(this.props.ctx.clients[this.state.primary_user]) + : {} + } + + get selectedPluginEntry() { + return { + id: this.state.type, + value: this.state.type, + label: this.state.type, + } + } + + get typeOptions() { + return Object.values(this.props.ctx.plugins).map(plugin => plugin && { + id: plugin.id, + value: plugin.id, + label: plugin.id, + }) + } + + get loading() { + return this.state.deleting || this.state.saving + } + + get isValid() { + return this.state.id && this.state.primary_user && this.state.type + } + + render() { + return + + + + } + + renderDatabase = () => + + renderMain = () =>
+ + + this.setState({ enabled })}/> + this.setState({ started })}/> + {api.getFeatures().client ? ( + this.setState({ primary_user: id })}/> + ) : ( + + )} + {api.getFeatures().plugin ? ( + this.setState({ type: id })}/> + ) : ( + + )} + + {!this.isNew && Boolean(this.props.entry.base_config) && + this.setState({ config })} + name="config" value={this.state.config} + editorProps={{ + fontSize: "10pt", + $blockScrolling: true, + }}/>} +
+ {!this.isNew && ( + + )} + +
+ {!this.isNew &&
+ {this.props.entry.database && ( + + View database + + )} + {api.getFeatures().log && + } +
} +
{this.state.error}
+
+} + +export default withRouter(Instance) diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/InstanceDatabase.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/InstanceDatabase.js new file mode 100644 index 0000000..2f3f525 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/InstanceDatabase.js @@ -0,0 +1,332 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component } from "react" +import { NavLink, Link, withRouter } from "react-router-dom" +import { ContextMenu, ContextMenuTrigger, MenuItem } from "react-contextmenu" +import { ReactComponent as ChevronLeft } from "../../res/chevron-left.svg" +import { ReactComponent as OrderDesc } from "../../res/sort-down.svg" +import { ReactComponent as OrderAsc } from "../../res/sort-up.svg" +import api from "../../api" +import Spinner from "../../components/Spinner" + +// eslint-disable-next-line no-extend-native +Map.prototype.map = function(func) { + const res = [] + for (const [key, value] of this) { + res.push(func(value, key, this)) + } + return res +} + +class InstanceDatabase extends Component { + constructor(props) { + super(props) + this.state = { + tables: null, + header: null, + content: null, + query: "", + selectedTable: null, + + error: null, + + prevQuery: null, + statusMsg: null, + rowCount: null, + insertedPrimaryKey: null, + } + this.order = new Map() + } + + async componentDidMount() { + const tables = new Map(Object.entries(await api.getInstanceDatabase(this.props.instanceID))) + for (const [name, table] of tables) { + table.name = name + table.columns = new Map(Object.entries(table.columns)) + for (const [columnName, column] of table.columns) { + column.name = columnName + column.sort = null + } + } + this.setState({ tables }) + this.checkLocationTable() + } + + componentDidUpdate(prevProps) { + if (this.props.location !== prevProps.location) { + this.order = new Map() + this.setState({ header: null, content: null }) + this.checkLocationTable() + } + } + + checkLocationTable() { + const prefix = `/instance/${this.props.instanceID}/database/` + if (this.props.location.pathname.startsWith(prefix)) { + const table = this.props.location.pathname.substr(prefix.length) + this.setState({ selectedTable: table }) + this.buildSQLQuery(table) + } + } + + getSortQueryParams(table) { + const order = [] + for (const [column, sort] of Array.from(this.order.entries()).reverse()) { + order.push(`order=${column}:${sort}`) + } + return order + } + + buildSQLQuery(table = this.state.selectedTable, resetContent = true) { + let query = `SELECT * FROM "${table}"` + + if (this.order.size > 0) { + const order = Array.from(this.order.entries()).reverse() + .map(([column, sort]) => `${column} ${sort}`) + query += ` ORDER BY ${order.join(", ")}` + } + + query += " LIMIT 100" + this.setState({ query }, () => this.reloadContent(resetContent)) + } + + reloadContent = async (resetContent = true) => { + this.setState({ loading: true }) + const res = await api.queryInstanceDatabase(this.props.instanceID, this.state.query) + this.setState({ loading: false }) + if (resetContent) { + this.setState({ + prevQuery: null, + rowCount: null, + insertedPrimaryKey: null, + statusMsg: null, + error: null, + }) + } + if (!res.ok) { + this.setState({ + error: res.error, + }) + } else if (res.rows) { + this.setState({ + header: res.columns, + content: res.rows, + }) + } else { + this.setState({ + prevQuery: res.query, + rowCount: res.rowcount, + insertedPrimaryKey: res.inserted_primary_key, + statusMsg: res.status_msg, + }) + this.buildSQLQuery(this.state.selectedTable, false) + } + } + + toggleSort(column) { + const oldSort = this.order.get(column) || "auto" + this.order.delete(column) + switch (oldSort) { + case "auto": + this.order.set(column, "DESC") + break + case "DESC": + this.order.set(column, "ASC") + break + case "ASC": + default: + break + } + this.buildSQLQuery() + } + + getSortIcon(column) { + switch (this.order.get(column)) { + case "DESC": + return + case "ASC": + return + default: + return null + } + } + + getColumnInfo(columnName) { + const table = this.state.tables.get(this.state.selectedTable) + if (!table) { + return null + } + const column = table.columns.get(columnName) + if (!column) { + return null + } + if (column.primary) { + return  (pk) + } else if (column.unique) { + return  (u) + } + return null + } + + getColumnType(columnName) { + const table = this.state.tables.get(this.state.selectedTable) + if (!table) { + return null + } + const column = table.columns.get(columnName) + if (!column) { + return null + } + return column.type + } + + deleteRow = async (_, data) => { + const values = this.state.content[data.row] + const keys = this.state.header + const condition = [] + for (const [index, key] of Object.entries(keys)) { + const val = values[index] + condition.push(`${key}='${this.sqlEscape(val.toString())}'`) + } + const query = `DELETE FROM "${this.state.selectedTable}" WHERE ${condition.join(" AND ")}` + const res = await api.queryInstanceDatabase(this.props.instanceID, query) + this.setState({ + prevQuery: `DELETE FROM "${this.state.selectedTable}" ...`, + rowCount: res.rowcount, + }) + await this.reloadContent(false) + } + + editCell = async (evt, data) => { + console.log("Edit", data) + } + + collectContextMeta = props => ({ + row: props.row, + col: props.col, + }) + + // eslint-disable-next-line no-control-regex + sqlEscape = str => str.replace(/[\0\x08\x09\x1a\n\r"'\\%]/g, char => { + switch (char) { + case "\0": + return "\\0" + case "\x08": + return "\\b" + case "\x09": + return "\\t" + case "\x1a": + return "\\z" + case "\n": + return "\\n" + case "\r": + return "\\r" + case "\"": + case "'": + case "\\": + case "%": + return "\\" + char + default: + return char + } + }) + + renderTable = () =>
+ {this.state.header ? <> + + + + {this.state.header.map(column => ( + + ))} + + + + {this.state.content.map((row, rowIndex) => ( + + {row.map((cell, colIndex) => ( + + {cell} + + ))} + + ))} + +
+ this.toggleSort(column)} + title={this.getColumnType(column)}> + {column} + {this.getColumnInfo(column)} + {this.getSortIcon(column)} + +
+ + Delete row + Edit cell + + : this.state.loading ? : null} +
+ + renderContent() { + return <> +
+ {this.state.tables.map((_, tbl) => ( + + {tbl} + + ))} +
+
+ this.setState({ query: evt.target.value })}/> + +
+ {this.state.error &&
+ {this.state.error} +
} + {this.state.prevQuery &&
+

+ Executed {this.state.prevQuery} - { + this.state.statusMsg + || <>affected {this.state.rowCount} rows. + } +

+ {this.state.insertedPrimaryKey &&

+ Inserted primary key: {this.state.insertedPrimaryKey} +

} +
} + {this.renderTable()} + + } + + render() { + return
+
+ + + Back + +
+ {this.state.tables + ? this.renderContent() + : } +
+ } +} + +export default withRouter(InstanceDatabase) diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/Log.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/Log.js new file mode 100644 index 0000000..b80e6ad --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/Log.js @@ -0,0 +1,191 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { PureComponent } from "react" +import { Link } from "react-router-dom" +import { JSONTree } from "react-json-tree" +import api from "../../api" +import Modal from "./Modal" + +class LogEntry extends PureComponent { + static contextType = Modal.Context + + renderName() { + const line = this.props.line + if (line.nameLink) { + const modal = this.context + return <> + + {line.name} + + {line.nameSuffix} + + } + return line.name + } + + renderContent() { + if (this.props.line.matrix_http_request) { + const req = this.props.line.matrix_http_request + + return <> + {req.method} {req.url || req.path} +
+ {Object.entries(req.content || {}).length > 0 + && } +
+ + } + return this.props.line.msg + } + + onClickOpen(path, line) { + return () => { + if (api.debugOpenFileEnabled()) { + api.debugOpenFile(path, line) + } + return false + } + } + + renderTimeTitle() { + return this.props.line.time.toDateString() + } + + renderTime() { + return
+ {this.props.line.time.toLocaleTimeString("en-GB")} + + } + + renderLevelName() { + return + {this.props.line.levelname} + + } + + get unfocused() { + return this.props.focus && this.props.line.name !== this.props.focus + ? "unfocused" + : "" + } + + renderRow(content) { + return ( +
+ {this.renderTime()} + {this.renderLevelName()} + {this.renderName()} + {content} +
+ ) + } + + renderExceptionInfo() { + if (!api.debugOpenFileEnabled()) { + return this.props.line.exc_info + } + const fileLinks = [] + let str = this.props.line.exc_info.replace( + /File "(.+)", line ([0-9]+), in (.+)/g, + (_, file, line, method) => { + fileLinks.push( + + File "{file}", line {line}, in {method} + , + ) + return "||EDGE||" + }) + fileLinks.reverse() + + const result = [] + let key = 0 + for (const part of str.split("||EDGE||")) { + result.push( + {part} + {fileLinks.pop()} + ) + } + return result + } + + render() { + return <> + {this.renderRow(this.renderContent())} + {this.props.line.exc_info && this.renderRow(this.renderExceptionInfo())} + + } +} + +class Log extends PureComponent { + constructor(props) { + super(props) + + this.linesRef = React.createRef() + this.linesBottomRef = React.createRef() + } + + getSnapshotBeforeUpdate() { + if (this.linesRef.current && this.linesBottomRef.current) { + return Log.isVisible(this.linesRef.current, this.linesBottomRef.current) + } + return false + } + + + componentDidUpdate(_1, _2, wasVisible) { + if (wasVisible) { + Log.scrollParentToChild(this.linesRef.current, this.linesBottomRef.current) + } + } + + componentDidMount() { + if (this.linesRef.current && this.linesBottomRef.current) { + Log.scrollParentToChild(this.linesRef.current, this.linesBottomRef.current) + } + } + + static scrollParentToChild(parent, child) { + const parentRect = parent.getBoundingClientRect() + const childRect = child.getBoundingClientRect() + + if (!Log.isVisible(parent, child)) { + parent.scrollBy({ top: (childRect.top + parent.scrollTop) - parentRect.top }) + } + } + + static isVisible(parent, child) { + const parentRect = parent.getBoundingClientRect() + const childRect = child.getBoundingClientRect() + return (childRect.top >= parentRect.top) + && (childRect.top <= parentRect.top + parent.clientHeight) + } + + render() { + return ( +
+
+ {this.props.lines.map(data => )} +
+
+
+ ) + } +} + +export default Log diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/Modal.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/Modal.js new file mode 100644 index 0000000..924079f --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/Modal.js @@ -0,0 +1,52 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component, createContext } from "react" + +const rem = 16 + +class Modal extends Component { + static Context = createContext(null) + + constructor(props) { + super(props) + this.state = { + open: false, + } + this.wrapper = { clientWidth: 9001 } + } + + open = () => this.setState({ open: true }) + close = () => this.setState({ open: false }) + isOpen = () => this.state.open + + render() { + return this.state.open && ( +
this.wrapper = ref} + onClick={() => this.wrapper.clientWidth > 45 * rem && this.close()}> +
evt.stopPropagation()}> + +
+ + {this.props.children} + +
+
+
+ ) + } +} + +export default Modal diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/Plugin.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/Plugin.js new file mode 100644 index 0000000..923a397 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/Plugin.js @@ -0,0 +1,104 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React from "react" +import { NavLink, withRouter } from "react-router-dom" +import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg" +import { ReactComponent as UploadButton } from "../../res/upload.svg" +import PrefTable, { PrefInput } from "../../components/PreferenceTable" +import Spinner from "../../components/Spinner" +import api from "../../api" +import BaseMainView from "./BaseMainView" + +const PluginListEntry = ({ entry }) => ( + + {entry.id} + + +) + + +class Plugin extends BaseMainView { + static ListEntry = PluginListEntry + + constructor(props) { + super(props) + this.deleteFunc = api.deletePlugin + } + + get initialState() { + return { + id: "", + version: "", + + instances: [], + + uploading: false, + deleting: false, + error: "", + } + } + + upload = async event => { + const file = event.target.files[0] + this.setState({ + uploadingAvatar: true, + }) + const data = await this.readFile(file) + const resp = await api.uploadPlugin(data, this.state.id) + if (resp.id) { + if (this.isNew) { + this.props.history.push(`/plugin/${resp.id}`) + } else { + this.setState({ saving: false, error: "" }) + } + this.props.onChange(resp) + } else { + this.setState({ saving: false, error: resp.error }) + } + } + + render() { + return
+ {!this.isNew && + + + } + {api.getFeatures().plugin_upload && +
+ + evt.target.parentElement.classList.add("drag")} + onDragLeave={evt => evt.target.parentElement.classList.remove("drag")}/> + {this.state.uploading && } +
} + {!this.isNew &&
+ +
} + {this.renderLogButton("loader.zip")} +
{this.state.error}
+ {this.renderInstances()} +
+ } +} + +export default withRouter(Plugin) diff --git a/maubot-src/maubot/management/frontend/src/pages/dashboard/index.js b/maubot-src/maubot/management/frontend/src/pages/dashboard/index.js new file mode 100644 index 0000000..9655a00 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/pages/dashboard/index.js @@ -0,0 +1,272 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component } from "react" +import { Route, Switch, Link, withRouter } from "react-router-dom" +import api from "../../api" +import { ReactComponent as Plus } from "../../res/plus.svg" +import Instance from "./Instance" +import Client from "./Client" +import Plugin from "./Plugin" +import Home from "./Home" +import Log from "./Log" +import Modal from "./Modal" + +class Dashboard extends Component { + constructor(props) { + super(props) + this.state = { + instances: {}, + clients: {}, + plugins: {}, + homeserversByName: {}, + homeserversByURL: {}, + sidebarOpen: false, + modalOpen: false, + logFocus: null, + logLines: [], + } + this.logModal = { + open: () => undefined, + isOpen: () => false, + } + window.maubot = this + } + + componentDidUpdate(prevProps) { + if (this.props.location !== prevProps.location) { + this.setState({ sidebarOpen: false }) + } + } + + async componentDidMount() { + const [instanceList, clientList, pluginList, homeservers] = await Promise.all([ + api.getInstances(), api.getClients(), api.getPlugins(), api.getClientAuthServers(), + api.updateDebugOpenFileEnabled()]) + const instances = {} + if (api.getFeatures().instance) { + for (const instance of instanceList) { + instances[instance.id] = instance + } + } + const clients = {} + if (api.getFeatures().client) { + for (const client of clientList) { + clients[client.id] = client + } + } + const plugins = {} + if (api.getFeatures().plugin) { + for (const plugin of pluginList) { + plugins[plugin.id] = plugin + } + } + const homeserversByName = homeservers + const homeserversByURL = {} + if (api.getFeatures().client_auth) { + for (const [key, value] of Object.entries(homeservers)) { + homeserversByURL[value] = key + } + } + this.setState({ instances, clients, plugins, homeserversByName, homeserversByURL }) + + await this.enableLogs() + } + + async enableLogs() { + if (!api.getFeatures().log) { + return + } + + const logs = await api.openLogSocket() + + const processEntry = (entry) => { + entry.time = new Date(entry.time) + entry.nameSuffix = "" + if (entry.name.startsWith("maubot.client.")) { + if (entry.name.endsWith(".crypto")) { + entry.name = entry.name.slice(0, -".crypto".length) + entry.nameSuffix = "/crypto" + } + entry.name = `client/${entry.name.slice("maubot.client.".length)}` + entry.nameLink = `/${entry.name}` + } else if (entry.name.startsWith("maubot.instance.")) { + entry.name = `instance/${entry.name.slice("maubot.instance.".length)}` + entry.nameLink = `/${entry.name}` + } else if (entry.name.startsWith("maubot.instance_db.")) { + entry.nameSuffix = "/db" + entry.name = `instance/${entry.name.slice("maubot.instance_db.".length)}` + entry.nameLink = `/${entry.name}` + } + } + + logs.onHistory = history => { + for (const data of history) { + processEntry(data) + } + this.setState({ + logLines: history, + }) + } + logs.onLog = data => { + processEntry(data) + this.setState({ + logLines: this.state.logLines.concat(data), + }) + } + } + + renderList(field, type) { + return this.state[field] && Object.values(this.state[field]).map(entry => + React.createElement(type, { key: entry.id, entry })) + } + + delete(stateField, id) { + const data = Object.assign({}, this.state[stateField]) + delete data[id] + this.setState({ [stateField]: data }) + } + + add(stateField, entry, oldID = undefined) { + const data = Object.assign({}, this.state[stateField]) + if (oldID && oldID !== entry.id) { + delete data[oldID] + } + data[entry.id] = entry + this.setState({ [stateField]: data }) + } + + renderView(field, type, id) { + const typeName = field.slice(0, -1) + if (!api.getFeatures()[typeName]) { + return this.renderDisabled(typeName) + } + const entry = this.state[field][id] + if (!entry) { + return this.renderNotFound(typeName) + } + return React.createElement(type, { + entry, + onDelete: () => this.delete(field, id), + onChange: newEntry => this.add(field, newEntry, id), + openLog: this.openLog, + ctx: this.state, + }) + } + + openLog = filter => { + this.setState({ + logFocus: typeof filter === "string" ? filter : null, + }) + this.logModal.open() + } + + renderNotFound = (thing = "path") => ( +
+ Oops! I'm afraid that {thing} couldn't be found. +
+ ) + + renderDisabled = (thing = "path") => ( +
+ The {thing} API has been disabled in the maubot config. +
+ ) + + renderMain() { + return
+ + + Maubot Manager + +
+ {localStorage.username} +
+ + + +
this.setState({ sidebarOpen: !this.state.sidebarOpen })}> +
+ +
+
+ +
+ + }/> + + this.add("instances", newEntry)} + entry={{}} ctx={this.state}/>}/> + + this.add("clients", newEntry)} + entry={{}} ctx={this.state}/>}/> + + this.add("plugins", newEntry)} + entry={{}} ctx={this.state}/>}/> + + this.renderView("instances", Instance, match.params.id)}/> + + this.renderView("clients", Client, match.params.id)}/> + + this.renderView("plugins", Plugin, match.params.id)}/> + this.renderNotFound()}/> + +
+
+ } + + renderModal() { + return this.logModal = ref}> + + + } + + render() { + return <> + {this.renderMain()} + {this.renderModal()} + + } +} + +export default withRouter(Dashboard) diff --git a/maubot-src/maubot/management/frontend/src/res/bot.svg b/maubot-src/maubot/management/frontend/src/res/bot.svg new file mode 100644 index 0000000..3c690fb --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/res/bot.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/maubot-src/maubot/management/frontend/src/res/chevron-left.svg b/maubot-src/maubot/management/frontend/src/res/chevron-left.svg new file mode 100644 index 0000000..714c0b1 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/res/chevron-left.svg @@ -0,0 +1 @@ + diff --git a/maubot-src/maubot/management/frontend/src/res/chevron-right.svg b/maubot-src/maubot/management/frontend/src/res/chevron-right.svg new file mode 100644 index 0000000..265effd --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/res/chevron-right.svg @@ -0,0 +1 @@ + diff --git a/maubot-src/maubot/management/frontend/src/res/plus.svg b/maubot-src/maubot/management/frontend/src/res/plus.svg new file mode 100644 index 0000000..8030204 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/res/plus.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/maubot-src/maubot/management/frontend/src/res/sort-down.svg b/maubot-src/maubot/management/frontend/src/res/sort-down.svg new file mode 100644 index 0000000..bb5413b --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/res/sort-down.svg @@ -0,0 +1 @@ + diff --git a/maubot-src/maubot/management/frontend/src/res/sort-up.svg b/maubot-src/maubot/management/frontend/src/res/sort-up.svg new file mode 100644 index 0000000..84ad364 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/res/sort-up.svg @@ -0,0 +1 @@ + diff --git a/maubot-src/maubot/management/frontend/src/res/upload.svg b/maubot-src/maubot/management/frontend/src/res/upload.svg new file mode 100644 index 0000000..f1deea6 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/res/upload.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/maubot-src/maubot/management/frontend/src/setupProxy.js b/maubot-src/maubot/management/frontend/src/setupProxy.js new file mode 100644 index 0000000..fedb271 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/setupProxy.js @@ -0,0 +1,6 @@ +const proxy = require("http-proxy-middleware") + +module.exports = function(app) { + app.use(proxy("/_matrix/maubot/v1", { target: process.env.PROXY || "http://localhost:29316" })) + app.use(proxy("/_matrix/maubot/v1/logs", { target: process.env.PROXY || "http://localhost:29316", ws: true })) +} diff --git a/maubot-src/maubot/management/frontend/src/style/base/body.sass b/maubot-src/maubot/management/frontend/src/style/base/body.sass new file mode 100644 index 0000000..a3c6fb3 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/base/body.sass @@ -0,0 +1,39 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +body + font-family: $font-stack + margin: 0 + padding: 0 + font-size: 16px + +#root + position: fixed + top: 0 + bottom: 0 + right: 0 + left: 0 + +.maubot-wrapper + position: absolute + top: 0 + bottom: 0 + left: 0 + right: 0 + background-color: $background-dark + +.maubot-loading + margin-top: 10rem + width: 10rem diff --git a/maubot-src/maubot/management/frontend/src/style/base/elements.sass b/maubot-src/maubot/management/frontend/src/style/base/elements.sass new file mode 100644 index 0000000..5de0577 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/base/elements.sass @@ -0,0 +1,120 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +=button($width: null, $height: null, $padding: .375rem 1rem) + font-family: $font-stack + padding: $padding + width: $width + height: $height + background-color: $background + border: none + border-radius: .25rem + color: $text-color + box-sizing: border-box + font-size: 1rem + + &.disabled-bg + background-color: $background-dark + + &:not(:disabled) + cursor: pointer + + &:hover + background-color: darken($background, 10%) + +=link-button() + display: inline-block + text-align: center + text-decoration: none + +=main-color-button() + background-color: $primary + color: $inverted-text-color + &:hover:not(:disabled) + background-color: $primary-dark + + &:disabled.disabled-bg + background-color: $background-dark !important + color: $text-color + +.button + +button + + &.main-color + +main-color-button + +=button-group() + width: 100% + display: flex + > button, > .button + flex: 1 + + &:first-child + margin-right: .5rem + + &:last-child + margin-left: .5rem + + &:first-child:last-child + margin: 0 + +=vertical-button-group() + display: flex + flex-direction: column + > button, > .button + flex: 1 + border-radius: 0 + + &:first-of-type + border-radius: .25rem .25rem 0 0 + + &:last-of-type + border-radius: 0 0 .25rem .25rem + + &:first-of-type:last-of-type + border-radius: .25rem + +=input($width: null, $height: null, $vertical-padding: .375rem, $horizontal-padding: 1rem, $font-size: 1rem) + font-family: $font-stack + border: 1px solid $border-color + background-color: $background + color: $text-color + width: $width + height: $height + box-sizing: border-box + border-radius: .25rem + padding: $vertical-padding $horizontal-padding + font-size: $font-size + resize: vertical + + &:hover, &:focus + border-color: $primary + + &:focus + border-width: 2px + padding: calc(#{$vertical-padding} - 1px) calc(#{$horizontal-padding} - 1px) + +.input, .textarea + +input + +input + font-family: $font-stack + +=notification($border: $error-dark, $background: transparentize($error-light, 0.5)) + padding: 1rem + border-radius: .25rem + border: 2px solid $border + background-color: $background diff --git a/maubot-src/maubot/management/frontend/src/style/base/fonts.sass b/maubot-src/maubot/management/frontend/src/style/base/fonts.sass new file mode 100644 index 0000000..89a09a9 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/base/fonts.sass @@ -0,0 +1,30 @@ +@font-face + font-family: 'Raleway' + font-style: normal + font-weight: 300 + src: local('Raleway Light'), local('Raleway-Light'), url('../../fonts/raleway-light.woff2') format('woff2') + +@font-face + font-family: 'Raleway' + font-style: normal + font-weight: 400 + src: local('Raleway'), local('Raleway-Regular'), url('../../fonts/raleway-regular.woff2') format('woff2') + +@font-face + font-family: 'Raleway' + font-style: normal + font-weight: 700 + src: local('Raleway Bold'), local('Raleway-Bold'), url('../../fonts/raleway-bold.woff2') format('woff2') + + +@font-face + font-family: 'Fira Code' + src: url('../../fonts/firacode-regular.woff2') format('woff2') + font-weight: 400 + font-style: normal + +@font-face + font-family: 'Fira Code' + src: url('../../fonts/firacode-bold.woff2') format('woff2') + font-weight: 700 + font-style: normal diff --git a/maubot-src/maubot/management/frontend/src/style/base/vars.sass b/maubot-src/maubot/management/frontend/src/style/base/vars.sass new file mode 100644 index 0000000..36c8028 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/base/vars.sass @@ -0,0 +1,33 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +$primary: #00C853 +$primary-dark: #009624 +$primary-light: #5EFC82 +$secondary: #00B8D4 +$secondary-dark: #0088A3 +$secondary-light: #62EBFF +$error: #B71C1C +$error-dark: #7F0000 +$error-light: #F05545 +$warning: orange + +$border-color: #DDD +$text-color: #212121 +$background: #FAFAFA +$background-dark: #E7E7E7 +$inverted-text-color: $background +$font-stack: Raleway, sans-serif diff --git a/maubot-src/maubot/management/frontend/src/style/index.sass b/maubot-src/maubot/management/frontend/src/style/index.sass new file mode 100644 index 0000000..05dd369 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/index.sass @@ -0,0 +1,33 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +@import lib/spinner +@import lib/contextmenu + +@import base/fonts +@import base/vars +@import base/body +@import base/elements + +@import lib/preferencetable +@import lib/switch + +@import pages/mixins/upload-container +@import pages/mixins/instancelist + +@import pages/login +@import pages/dashboard +@import pages/modal +@import pages/log diff --git a/maubot-src/maubot/management/frontend/src/style/lib/contextmenu.scss b/maubot-src/maubot/management/frontend/src/style/lib/contextmenu.scss new file mode 100644 index 0000000..5575fb4 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/lib/contextmenu.scss @@ -0,0 +1,80 @@ +.react-contextmenu { + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, .15); + border-radius: .25rem; + color: #373a3c; + font-size: 16px; + margin: 2px 0 0; + min-width: 160px; + outline: none; + opacity: 0; + padding: 5px 0; + pointer-events: none; + text-align: left; + transition: opacity 250ms ease !important; +} + +.react-contextmenu.react-contextmenu--visible { + opacity: 1; + pointer-events: auto; + z-index: 9999; +} + +.react-contextmenu-item { + background: 0 0; + border: 0; + color: #373a3c; + cursor: pointer; + font-weight: 400; + line-height: 1.5; + padding: 3px 20px; + text-align: inherit; + white-space: nowrap; +} + +.react-contextmenu-item.react-contextmenu-item--active, +.react-contextmenu-item.react-contextmenu-item--selected { + color: #fff; + background-color: #20a0ff; + border-color: #20a0ff; + text-decoration: none; +} + +.react-contextmenu-item.react-contextmenu-item--disabled, +.react-contextmenu-item.react-contextmenu-item--disabled:hover { + background-color: transparent; + border-color: rgba(0, 0, 0, .15); + color: #878a8c; +} + +.react-contextmenu-item--divider { + border-bottom: 1px solid rgba(0, 0, 0, .15); + cursor: inherit; + margin-bottom: 3px; + padding: 2px 0; +} + +.react-contextmenu-item--divider:hover { + background-color: transparent; + border-color: rgba(0, 0, 0, .15); +} + +.react-contextmenu-item.react-contextmenu-submenu { + padding: 0; +} + +.react-contextmenu-item.react-contextmenu-submenu > .react-contextmenu-item { +} + +.react-contextmenu-item.react-contextmenu-submenu > .react-contextmenu-item:after { + content: "▶"; + display: inline-block; + position: absolute; + right: 7px; +} + +.example-multiple-targets::after { + content: attr(data-count); + display: block; +} diff --git a/maubot-src/maubot/management/frontend/src/style/lib/preferencetable.sass b/maubot-src/maubot/management/frontend/src/style/lib/preferencetable.sass new file mode 100644 index 0000000..5c671c9 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/lib/preferencetable.sass @@ -0,0 +1,85 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +.preference-table + display: flex + + width: 100% + + flex-wrap: wrap + + > .entry + display: block + + @media screen and (max-width: 55rem) + width: calc(100% - 1rem) + width: calc(50% - 1rem) + margin: .5rem + + &.full-width + width: 100% + + &.changed > label + font-weight: bold + &:after + content: "*" + + > label, > .value + display: block + width: 100% + + > label + font-size: 0.875rem + padding-bottom: .25rem + font-weight: lighter + + > .value + > .switch + width: auto + height: 2rem + + > .select + height: 2.5rem + box-sizing: border-box + + > input + border: none + height: 2rem + width: 100% + color: $text-color + + box-sizing: border-box + + padding: .375rem 0 calc(.375rem + 1px) + background-color: $background + + font-size: 1rem + + border-bottom: 1px solid $background + + &.id:disabled + font-family: "Fira Code", monospace + font-weight: bold + + &:not(:disabled) + border-bottom: 1px dotted $primary + + &:hover + border-bottom: 1px solid $primary + + &:focus + border-bottom: 2px solid $primary + padding-bottom: .375rem diff --git a/maubot-src/maubot/management/frontend/src/style/lib/spinner.sass b/maubot-src/maubot/management/frontend/src/style/lib/spinner.sass new file mode 100644 index 0000000..d164586 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/lib/spinner.sass @@ -0,0 +1,65 @@ +$green: #008744 +$blue: #0057e7 +$red: #d62d20 +$yellow: #ffa700 + +.spinner + position: relative + margin: 0 auto + width: 5rem + + &:before + content: "" + display: block + padding-top: 100% + + svg + animation: rotate 2s linear infinite + height: 100% + transform-origin: center center + width: 100% + position: absolute + top: 0 + bottom: 0 + left: 0 + right: 0 + margin: auto + + circle + stroke-dasharray: 1, 200 + stroke-dashoffset: 0 + animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite + stroke-linecap: round + +=white-spinner() + circle + stroke: white !important + +=thick-spinner($thickness: 5) + svg > circle + stroke-width: $thickness + +@keyframes rotate + 100% + transform: rotate(360deg) + +@keyframes dash + 0% + stroke-dasharray: 1, 200 + stroke-dashoffset: 0 + 50% + stroke-dasharray: 89, 200 + stroke-dashoffset: -35px + 100% + stroke-dasharray: 89, 200 + stroke-dashoffset: -124px + +@keyframes color + 100%, 0% + stroke: $red + 40% + stroke: $blue + 66% + stroke: $green + 80%, 90% + stroke: $yellow diff --git a/maubot-src/maubot/management/frontend/src/style/lib/switch.sass b/maubot-src/maubot/management/frontend/src/style/lib/switch.sass new file mode 100644 index 0000000..9a47ce9 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/lib/switch.sass @@ -0,0 +1,77 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +.switch + display: flex + + width: 100% + height: 2rem + + cursor: pointer + + border: 1px solid $error-light + border-radius: .25rem + background-color: $background + + box-sizing: border-box + + > .box + display: flex + box-sizing: border-box + width: 50% + height: 100% + + transition: .5s + text-align: center + + border-radius: .15rem 0 0 .15rem + background-color: $error-light + color: $inverted-text-color + + align-items: center + + > .text + box-sizing: border-box + width: 100% + + text-align: center + vertical-align: middle + + color: $inverted-text-color + font-size: 1rem + + user-select: none + + .on + display: none + + .off + display: inline + + + &[data-active=true] + border: 1px solid $primary + > .box + background-color: $primary + transform: translateX(100%) + + border-radius: 0 .15rem .15rem 0 + + .on + display: inline + + .off + display: none diff --git a/maubot-src/maubot/management/frontend/src/style/pages/client/avatar.sass b/maubot-src/maubot/management/frontend/src/style/pages/client/avatar.sass new file mode 100644 index 0000000..36856c3 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/client/avatar.sass @@ -0,0 +1,62 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> div.avatar-container + +upload-box + + width: 8rem + height: 8rem + border-radius: 50% + + @media screen and (max-width: 40rem) + margin: 0 auto 1rem + + > img.avatar + position: absolute + display: block + max-width: 8rem + max-height: 8rem + user-select: none + + > svg.upload + visibility: hidden + + width: 6rem + height: 6rem + + > input.file-selector + width: 8rem + height: 8rem + + &:not(.uploading) + &:hover, &.drag + > img.avatar + opacity: .25 + + > svg.upload + visibility: visible + + &.no-avatar + > img.avatar + visibility: hidden + + > svg.upload + visibility: visible + opacity: .5 + + &.uploading + > img.avatar + opacity: .25 diff --git a/maubot-src/maubot/management/frontend/src/style/pages/client/index.sass b/maubot-src/maubot/management/frontend/src/style/pages/client/index.sass new file mode 100644 index 0000000..18db567 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/client/index.sass @@ -0,0 +1,48 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> div.client + display: flex + + > div.sidebar + vertical-align: top + text-align: center + width: 8rem + margin-right: 1rem + + > * + margin-bottom: 1rem + + @import avatar + @import started + + > div.info + vertical-align: top + flex: 1 + + > div.instances + +instancelist + + input.fingerprint + font-family: "Fira Code", monospace + font-size: 0.8em + + @media screen and (max-width: 40rem) + flex-wrap: wrap + + > div.sidebar, > div.info + width: 100% + margin-right: 0 diff --git a/maubot-src/maubot/management/frontend/src/style/pages/client/started.sass b/maubot-src/maubot/management/frontend/src/style/pages/client/started.sass new file mode 100644 index 0000000..1292e86 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/client/started.sass @@ -0,0 +1,46 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> div.started-container + display: inline-flex + + > span.started + display: inline-block + height: 0 + width: 0 + border-radius: 50% + margin: .5rem + + &.true + &.sync_ok + background-color: $primary + box-shadow: 0 0 .75rem .75rem $primary + + &.sync_error + background-color: $warning + box-shadow: 0 0 .75rem .75rem $warning + + &.false + background-color: $error-light + box-shadow: 0 0 .75rem .75rem $error-light + + &.disabled + background-color: $border-color + box-shadow: 0 0 .75rem .75rem $border-color + + > span.text + display: inline-block + margin-left: 1rem diff --git a/maubot-src/maubot/management/frontend/src/style/pages/dashboard-grid.scss b/maubot-src/maubot/management/frontend/src/style/pages/dashboard-grid.scss new file mode 100644 index 0000000..5f12093 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/dashboard-grid.scss @@ -0,0 +1,19 @@ +.dashboard { + grid-template: + [row1-start] "title main" 3.5rem [row1-end] + [row2-start] "user main" 2.5rem [row2-end] + [row3-start] "sidebar main" auto [row3-end] + / 15rem auto; +} + + +@media screen and (max-width: 35rem) { + .dashboard { + grid-template: + [row1-start] "title topbar" 3.5rem [row1-end] + [row2-start] "user main" 2.5rem [row2-end] + [row3-start] "sidebar main" auto [row3-end] + / 15rem 100%; + overflow-x: hidden; + } +} diff --git a/maubot-src/maubot/management/frontend/src/style/pages/dashboard.sass b/maubot-src/maubot/management/frontend/src/style/pages/dashboard.sass new file mode 100644 index 0000000..9887fa1 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/dashboard.sass @@ -0,0 +1,129 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +@import "dashboard-grid" + +.dashboard + display: grid + height: 100% + max-width: 60rem + margin: auto + box-shadow: 0 .5rem .5rem rgba(0, 0, 0, 0.5) + background-color: $background + + > a.title + grid-area: title + background-color: white + display: flex + align-items: center + justify-content: center + + font-size: 1.35rem + font-weight: bold + + color: $text-color + text-decoration: none + + > img + max-width: 2rem + margin-right: .5rem + + > div.user + grid-area: user + background-color: white + border-bottom: 1px solid $border-color + display: flex + align-items: center + justify-content: center + span + display: flex + align-items: center + justify-content: center + background-color: $primary + color: $inverted-text-color + margin: .375rem .5rem + width: 100% + height: calc(100% - .375rem) + box-sizing: border-box + border-radius: .25rem + + @import sidebar + @import topbar + + @media screen and (max-width: 35rem) + &:not(.sidebar-open) > * + transform: translateX(-15rem) + > * + transition: transform 0.4s + + > main.view + grid-area: main + border-left: 1px solid $border-color + + overflow-y: auto + + @import client/index + @import instance + @import instance-database + @import plugin + + > div + margin: 2rem 4rem + + @media screen and (max-width: 50rem) + margin: 1rem + + > div.not-found, > div.home + text-align: center + margin-top: 5rem + font-size: 1.5rem + + div.buttons + +button-group + display: flex + margin: 1rem .5rem + width: calc(100% - 1rem) + + button.open-log, a.open-database + +button + +main-color-button + + a.open-database + +link-button + + div.error + +notification($error) + margin: 1rem .5rem + + &:empty + display: none + + button.delete + background-color: $error-light !important + + &:hover + background-color: $error !important + + button.save, button.clearcache, button.delete, button.verify + +button + +main-color-button + width: 100% + height: 2.5rem + padding: 0 + + > .spinner + +thick-spinner + +white-spinner + width: 2rem diff --git a/maubot-src/maubot/management/frontend/src/style/pages/instance-database.sass b/maubot-src/maubot/management/frontend/src/style/pages/instance-database.sass new file mode 100644 index 0000000..6477aa4 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/instance-database.sass @@ -0,0 +1,101 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> div.instance-database + margin: 0 + + > div.topbar + background-color: $primary-light + + display: flex + justify-items: center + align-items: center + + > a + display: flex + justify-items: center + align-items: center + text-decoration: none + user-select: none + + height: 2.5rem + width: 100% + + > *:not(.topbar) + margin: 2rem 4rem + + @media screen and (max-width: 50rem) + margin: 1rem + + > div.tables + display: flex + flex-wrap: wrap + + > a + +link-button + color: black + flex: 1 + + border-bottom: 2px solid $primary + + padding: .25rem + margin: .25rem + + &:hover + background-color: $primary-light + border-bottom: 2px solid $primary-dark + + &.active + background-color: $primary + + > div.query + display: flex + + > input + +input + font-family: "Fira Code", monospace + flex: 1 + margin-right: .5rem + + > button + +button + +main-color-button + + > div.prev-query + +notification($primary, $primary-light) + + span.query + font-family: "Fira Code", monospace + + p + margin: 0 + + > div.table + overflow-x: auto + overflow-y: hidden + + table + font-family: "Fira Code", monospace + width: 100% + box-sizing: border-box + + > thead + > tr > td > span + align-items: center + justify-items: center + display: flex + cursor: pointer + user-select: none diff --git a/maubot-src/maubot/management/frontend/src/style/pages/instance.sass b/maubot-src/maubot/management/frontend/src/style/pages/instance.sass new file mode 100644 index 0000000..e1da481 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/instance.sass @@ -0,0 +1,35 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> div.instance + > div.preference-table + .select-client + display: flex + align-items: center + + img.avatar, svg.avatar + max-height: 1.375rem + border-radius: 50% + margin-right: .5rem + + > div.ace_editor + z-index: 0 + height: 15rem !important + width: calc(100% - 1rem) !important + font-size: 12px + font-family: "Fira Code", monospace + + margin: .75rem .5rem 1.5rem diff --git a/maubot-src/maubot/management/frontend/src/style/pages/log.sass b/maubot-src/maubot/management/frontend/src/style/pages/log.sass new file mode 100644 index 0000000..db7d91d --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/log.sass @@ -0,0 +1,89 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +div.log + height: 100% + width: 100% + overflow: auto + +div.log > div.lines + text-align: left + font-size: 12px + max-height: 100% + min-width: 100% + font-family: "Fira Code", monospace + display: table + +div.log > div.lines > div.row + display: table-row + white-space: pre + + &.trace + opacity: .75 + + &.debug, &.trace + background-color: $background + + &:nth-child(odd) + background-color: $background-dark + + &.info + background-color: #AAFAFA + + &:nth-child(odd) + background-color: #66FAFA + + &.warning, &.warn + background-color: #FABB77 + + &:nth-child(odd) + background-color: #FAAA55 + + &.error + background-color: #FAAAAA + + &:nth-child(odd) + background-color: #FA9999 + + &.fatal + background-color: #CC44CC + + &:nth-child(odd) + background-color: #AA44AA + + &.unfocused + opacity: .25 + + > span + padding: .125rem .25rem + display: table-cell + + &:first-child + padding-left: 0 + + &:last-child + padding-right: 0 + + a + color: inherit + text-decoration: none + + &:hover + text-decoration: underline + + > span.text + > div.content > * + background-color: inherit !important + margin: 0 !important diff --git a/maubot-src/maubot/management/frontend/src/style/pages/login.sass b/maubot-src/maubot/management/frontend/src/style/pages/login.sass new file mode 100644 index 0000000..5a9e139 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/login.sass @@ -0,0 +1,62 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +.maubot-wrapper:not(.authenticated) + background-color: $primary + + text-align: center + +.login + width: 25rem + height: 23rem + display: inline-block + box-sizing: border-box + background-color: white + border-radius: .25rem + margin-top: 3rem + + @media screen and (max-width: 27rem) + margin: 3rem 1rem 0 + width: calc(100% - 2rem) + + h1 + color: $primary + margin: 3rem 0 + + input, button + margin: .5rem 2.5rem + height: 3rem + width: calc(100% - 5rem) + box-sizing: border-box + + input + +input + + button + +button($width: calc(100% - 5rem), $height: 3rem, $padding: 0) + +main-color-button + + .spinner + +white-spinner + +thick-spinner + width: 2rem + + &.errored + height: 26.5rem + + .error + +notification($error) + margin: .5rem 2.5rem diff --git a/maubot-src/maubot/management/frontend/src/style/pages/mixins/instancelist.sass b/maubot-src/maubot/management/frontend/src/style/pages/mixins/instancelist.sass new file mode 100644 index 0000000..886d542 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/mixins/instancelist.sass @@ -0,0 +1,40 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +=instancelist() + margin: 1rem 0 + + display: flex + flex-wrap: wrap + + > h3 + margin: .5rem + width: 100% + + > a.instance + display: block + width: calc(50% - 1rem) + padding: .375rem .5rem + margin: .5rem + background-color: white + border-radius: .25rem + color: $text-color + text-decoration: none + box-sizing: border-box + border: 1px solid $primary + + &:hover + background-color: $primary diff --git a/maubot-src/maubot/management/frontend/src/style/pages/mixins/upload-container.sass b/maubot-src/maubot/management/frontend/src/style/pages/mixins/upload-container.sass new file mode 100644 index 0000000..05af405 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/mixins/upload-container.sass @@ -0,0 +1,43 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +=upload-box() + position: relative + overflow: hidden + + display: flex + align-items: center + justify-content: center + + > svg.upload + position: absolute + display: block + + padding: 1rem + user-select: none + + + > input.file-selector + position: absolute + user-select: none + opacity: 0 + + > div.spinner + +thick-spinner + + &:not(.uploading) + > input.file-selector + cursor: pointer diff --git a/maubot-src/maubot/management/frontend/src/style/pages/modal.sass b/maubot-src/maubot/management/frontend/src/style/pages/modal.sass new file mode 100644 index 0000000..76056f0 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/modal.sass @@ -0,0 +1,71 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +div.modal-wrapper-wrapper + z-index: 9001 + position: fixed + top: 0 + bottom: 0 + left: 0 + right: 0 + background-color: rgba(0, 0, 0, 0.5) + + --modal-margin: 2.5rem + --button-height: 0rem + + @media screen and (max-width: 45rem) + --modal-margin: 1rem + --button-height: 2.5rem + + @media screen and (max-width: 35rem) + --modal-margin: 0rem + --button-height: 3rem + + button.close + +button + + display: none + + width: 100% + height: var(--button-height) + border-radius: .25rem .25rem 0 0 + + @media screen and (max-width: 45rem) + display: block + @media screen and (max-width: 35rem) + border-radius: 0 + + div.modal-wrapper + width: calc(100% - 2 * var(--modal-margin)) + height: calc(100% - 2 * var(--modal-margin) - var(--button-height)) + margin: var(--modal-margin) + border-radius: .25rem + + @media screen and (max-width: 35rem) + border-radius: 0 + + div.modal + padding: 1rem + height: 100% + width: 100% + background-color: $background + box-sizing: border-box + border-radius: .25rem + + @media screen and (max-width: 45rem) + border-radius: 0 0 .25rem .25rem + @media screen and (max-width: 35rem) + border-radius: 0 + padding: .5rem diff --git a/maubot-src/maubot/management/frontend/src/style/pages/plugin.sass b/maubot-src/maubot/management/frontend/src/style/pages/plugin.sass new file mode 100644 index 0000000..3e358d7 --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/plugin.sass @@ -0,0 +1,53 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> .plugin + > .upload-box + +upload-box + + width: calc(100% - 1rem) + height: 10rem + margin: .5rem + border-radius: .5rem + box-sizing: border-box + + border: .25rem dotted $primary + + > svg.upload + width: 8rem + height: 8rem + + opacity: .5 + + > input.file-selector + width: 100% + height: 100% + + &:not(.uploading):hover, &:not(.uploading).drag + border: .25rem solid $primary + background-color: $primary-light + + > svg.upload + opacity: 1 + + &.uploading + > svg.upload + visibility: hidden + > input.file-selector + cursor: default + + > div.instances + +instancelist diff --git a/maubot-src/maubot/management/frontend/src/style/pages/sidebar.sass b/maubot-src/maubot/management/frontend/src/style/pages/sidebar.sass new file mode 100644 index 0000000..7d68cab --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/sidebar.sass @@ -0,0 +1,79 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> nav.sidebar + grid-area: sidebar + background-color: white + + padding: .5rem + + overflow-y: auto + + div.buttons + margin-bottom: 1.5rem + + button + +button + background-color: white + width: 100% + + div.list + &:not(:last-of-type) + margin-bottom: 1.5rem + + div.title + h2 + display: inline-block + margin: 0 0 .25rem 0 + font-size: 1.25rem + + a + display: inline-block + float: right + + a.entry + display: block + color: $text-color + text-decoration: none + padding: .25rem + border-radius: .25rem + height: 2rem + box-sizing: border-box + white-space: nowrap + overflow-x: hidden + + &:not(:hover) > svg.chevron + display: none + + > svg.chevron + float: right + + &:hover + background-color: $primary-light + + &.active + background-color: $primary + color: white + + &.client + img.avatar, svg.avatar + max-height: 1.5rem + border-radius: 100% + vertical-align: middle + + span.displayname, span.id + margin-left: .25rem + vertical-align: middle diff --git a/maubot-src/maubot/management/frontend/src/style/pages/topbar.sass b/maubot-src/maubot/management/frontend/src/style/pages/topbar.sass new file mode 100644 index 0000000..51a8c3d --- /dev/null +++ b/maubot-src/maubot/management/frontend/src/style/pages/topbar.sass @@ -0,0 +1,79 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2022 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General 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 General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> .topbar + background-color: $primary + + display: flex + justify-items: center + align-items: center + padding: 0 .75rem + + @media screen and (min-width: calc(35rem + 1px)) + display: none + +// Hamburger menu based on "Pure CSS Hamburger fold-out menu" codepen by Erik Terwan (MIT license) +// https://codepen.io/erikterwan/pen/EVzeRP + +> .topbar + user-select: none + +> .topbar > .hamburger + display: block + user-select: none + cursor: pointer + + > span + display: block + width: 29px + height: 4px + margin-bottom: 5px + position: relative + + background: white + border-radius: 3px + user-select: none + + z-index: 1 + + transform-origin: 4px 0 + + transition: transform 0.4s cubic-bezier(0.77, 0.2, 0.05, 1.0), background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0), opacity 0.55s ease + + &:nth-of-type(1) + transform-origin: 0 0 + + &:nth-of-type(3) + transform-origin: 0 100% + + transform: translateY(2px) + transition: transform 0.4s cubic-bezier(0.77, 0.2, 0.05, 1.0) + + &.active + transform: translateX(1px) translateY(4px) + + &.active > span + opacity: 1 + + &:nth-of-type(1) + transform: rotate(45deg) translate(-2px, -1px) + + &:nth-of-type(2) + opacity: 0 + transform: rotate(0deg) scale(0.2, 0.2) + + &:nth-of-type(3) + transform: rotate(-45deg) translate(0, -1px) diff --git a/maubot-src/maubot/management/frontend/yarn.lock b/maubot-src/maubot/management/frontend/yarn.lock new file mode 100644 index 0000000..31b86b2 --- /dev/null +++ b/maubot-src/maubot/management/frontend/yarn.lock @@ -0,0 +1,8963 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" + integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.0" + +"@apideck/better-ajv-errors@^0.3.1": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.3.tgz#ab0b1e981e1749bf59736cf7ebe25cfc9f949c15" + integrity sha512-9o+HO2MbJhJHjDYZaDxJmSDckvDpiuItEsrIShV0DXeCshXWRHhqYyU/PKHMkuClOmFnZhRd6wzv4vpDu/dRKg== + dependencies: + json-schema "^0.4.0" + jsonpointer "^5.0.0" + leven "^3.1.0" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.8.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== + +"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + +"@babel/eslint-parser@^7.16.3": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz#eabb24ad9f0afa80e5849f8240d0e5facc2d90d6" + integrity sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA== + dependencies: + eslint-scope "^5.1.1" + eslint-visitor-keys "^2.1.0" + semver "^6.3.0" + +"@babel/generator@^7.17.3", "@babel/generator@^7.17.7", "@babel/generator@^7.7.2": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== + dependencies: + "@babel/types" "^7.17.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" + integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" + integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + +"@babel/helper-create-regexp-features-plugin@^7.16.7": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz#1dcc7d40ba0c6b6b25618997c5dbfd310f186fe1" + integrity sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + regexpu-core "^5.0.1" + +"@babel/helper-define-polyfill-provider@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" + integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-explode-assignable-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" + integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-member-expression-to-functions@^7.16.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== + dependencies: + "@babel/types" "^7.17.0" + +"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + +"@babel/helper-optimise-call-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + +"@babel/helper-remap-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" + integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-wrap-function" "^7.16.8" + "@babel/types" "^7.16.8" + +"@babel/helper-replace-supers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" + integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== + dependencies: + "@babel/types" "^7.17.0" + +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helper-wrap-function@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" + integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== + dependencies: + "@babel/helper-function-name" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.8" + "@babel/types" "^7.16.8" + +"@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" + integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" + integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + +"@babel/plugin-proposal-async-generator-functions@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" + integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.16.0", "@babel/plugin-proposal-class-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" + integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-proposal-class-static-block@^7.16.7": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz#164e8fd25f0d80fa48c5a4d1438a6629325ad83c" + integrity sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.17.6" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-decorators@^7.16.4": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.8.tgz#4f0444e896bee85d35cf714a006fc5418f87ff00" + integrity sha512-U69odN4Umyyx1xO1rTII0IDkAEC+RNlcKXtqOblfpzqy1C+aOplb76BQNq0+XdpVkOaPlpEDwd++joY8FNFJKA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.17.6" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/plugin-syntax-decorators" "^7.17.0" + charcodes "^0.2.0" + +"@babel/plugin-proposal-dynamic-import@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" + integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" + integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" + integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" + integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" + integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.16.0", "@babel/plugin-proposal-numeric-separator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" + integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.16.7": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390" + integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw== + dependencies: + "@babel/compat-data" "^7.17.0" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.7" + +"@babel/plugin-proposal-optional-catch-binding@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" + integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.16.0", "@babel/plugin-proposal-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" + integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.16.0", "@babel/plugin-proposal-private-methods@^7.16.11": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" + integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.10" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-proposal-private-property-in-object@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" + integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" + integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz#a2be3b2c9fe7d78bd4994e790896bc411e2f166d" + integrity sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-flow@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz#202b147e5892b8452bbb0bb269c7ed2539ab8832" + integrity sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" + integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-arrow-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" + integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" + integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + +"@babel/plugin-transform-block-scoped-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" + integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-block-scoping@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" + integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-classes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" + integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" + integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-destructuring@^7.16.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" + integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" + integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-duplicate-keys@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" + integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-exponentiation-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" + integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-flow-strip-types@^7.16.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.16.7.tgz#291fb140c78dabbf87f2427e7c7c332b126964b8" + integrity sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-flow" "^7.16.7" + +"@babel/plugin-transform-for-of@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" + integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" + integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== + dependencies: + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" + integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-member-expression-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" + integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-modules-amd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" + integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.16.8": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" + integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== + dependencies: + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.16.7": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" + integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== + dependencies: + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" + integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" + integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + +"@babel/plugin-transform-new-target@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" + integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-object-super@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" + integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + +"@babel/plugin-transform-parameters@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" + integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-property-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" + integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-react-constant-elements@^7.12.1": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.17.6.tgz#6cc273c2f612a6a50cb657e63ee1303e5e68d10a" + integrity sha512-OBv9VkyyKtsHZiHLoSfCn+h6yU7YKX8nrs32xUmOa1SRSk+t03FosB6fBZ0Yz4BpD1WV7l73Nsad+2Tz7APpqw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-react-display-name@^7.16.0", "@babel/plugin-transform-react-display-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" + integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-react-jsx-development@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz#43a00724a3ed2557ed3f276a01a929e6686ac7b8" + integrity sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.16.7" + +"@babel/plugin-transform-react-jsx@^7.16.7": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1" + integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-jsx" "^7.16.7" + "@babel/types" "^7.17.0" + +"@babel/plugin-transform-react-pure-annotations@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz#232bfd2f12eb551d6d7d01d13fe3f86b45eb9c67" + integrity sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-regenerator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" + integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" + integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-runtime@^7.16.4": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz#0a2e08b5e2b2d95c4b1d3b3371a2180617455b70" + integrity sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" + integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-spread@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" + integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + +"@babel/plugin-transform-sticky-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" + integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-template-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" + integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-typeof-symbol@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" + integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-typescript@^7.16.7": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" + integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-typescript" "^7.16.7" + +"@babel/plugin-transform-unicode-escapes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" + integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-unicode-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" + integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" + integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g== + dependencies: + "@babel/compat-data" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-async-generator-functions" "^7.16.8" + "@babel/plugin-proposal-class-properties" "^7.16.7" + "@babel/plugin-proposal-class-static-block" "^7.16.7" + "@babel/plugin-proposal-dynamic-import" "^7.16.7" + "@babel/plugin-proposal-export-namespace-from" "^7.16.7" + "@babel/plugin-proposal-json-strings" "^7.16.7" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" + "@babel/plugin-proposal-numeric-separator" "^7.16.7" + "@babel/plugin-proposal-object-rest-spread" "^7.16.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-private-methods" "^7.16.11" + "@babel/plugin-proposal-private-property-in-object" "^7.16.7" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.16.7" + "@babel/plugin-transform-async-to-generator" "^7.16.8" + "@babel/plugin-transform-block-scoped-functions" "^7.16.7" + "@babel/plugin-transform-block-scoping" "^7.16.7" + "@babel/plugin-transform-classes" "^7.16.7" + "@babel/plugin-transform-computed-properties" "^7.16.7" + "@babel/plugin-transform-destructuring" "^7.16.7" + "@babel/plugin-transform-dotall-regex" "^7.16.7" + "@babel/plugin-transform-duplicate-keys" "^7.16.7" + "@babel/plugin-transform-exponentiation-operator" "^7.16.7" + "@babel/plugin-transform-for-of" "^7.16.7" + "@babel/plugin-transform-function-name" "^7.16.7" + "@babel/plugin-transform-literals" "^7.16.7" + "@babel/plugin-transform-member-expression-literals" "^7.16.7" + "@babel/plugin-transform-modules-amd" "^7.16.7" + "@babel/plugin-transform-modules-commonjs" "^7.16.8" + "@babel/plugin-transform-modules-systemjs" "^7.16.7" + "@babel/plugin-transform-modules-umd" "^7.16.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" + "@babel/plugin-transform-new-target" "^7.16.7" + "@babel/plugin-transform-object-super" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-property-literals" "^7.16.7" + "@babel/plugin-transform-regenerator" "^7.16.7" + "@babel/plugin-transform-reserved-words" "^7.16.7" + "@babel/plugin-transform-shorthand-properties" "^7.16.7" + "@babel/plugin-transform-spread" "^7.16.7" + "@babel/plugin-transform-sticky-regex" "^7.16.7" + "@babel/plugin-transform-template-literals" "^7.16.7" + "@babel/plugin-transform-typeof-symbol" "^7.16.7" + "@babel/plugin-transform-unicode-escapes" "^7.16.7" + "@babel/plugin-transform-unicode-regex" "^7.16.7" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.16.8" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + core-js-compat "^3.20.2" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.12.5", "@babel/preset-react@^7.16.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" + integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-react-display-name" "^7.16.7" + "@babel/plugin-transform-react-jsx" "^7.16.7" + "@babel/plugin-transform-react-jsx-development" "^7.16.7" + "@babel/plugin-transform-react-pure-annotations" "^7.16.7" + +"@babel/preset-typescript@^7.16.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" + integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-typescript" "^7.16.7" + +"@babel/runtime-corejs3@^7.10.2": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.8.tgz#d7dd49fb812f29c61c59126da3792d8740d4e284" + integrity sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ== + dependencies: + core-js-pure "^3.20.2" + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.16.3", "@babel/runtime@^7.16.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3", "@babel/traverse@^7.7.2": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" + integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.3" + "@babel/types" "^7.17.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@csstools/normalize.css@*": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-12.0.0.tgz#a9583a75c3f150667771f30b60d9f059473e62c4" + integrity sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg== + +"@csstools/postcss-color-function@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-1.0.3.tgz#251c961a852c99e9aabdbbdbefd50e9a96e8a9ff" + integrity sha512-J26I69pT2B3MYiLY/uzCGKVJyMYVg9TCpXkWsRlt+Yfq+nELUEm72QXIMYXs4xA9cJA4Oqs2EylrfokKl3mJEQ== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-font-format-keywords@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.0.tgz#7e7df948a83a0dfb7eb150a96e2390ac642356a1" + integrity sha512-oO0cZt8do8FdVBX8INftvIA4lUrKUSCcWUf9IwH9IPWOgKT22oAZFXeHLoDK7nhB2SmkNycp5brxfNMRLIhd6Q== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-hwb-function@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.0.tgz#d6785c1c5ba8152d1d392c66f3a6a446c6034f6d" + integrity sha512-VSTd7hGjmde4rTj1rR30sokY3ONJph1reCBTUXqeW1fKwETPy1x4t/XIeaaqbMbC5Xg4SM/lyXZ2S8NELT2TaA== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-ic-unit@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.0.tgz#f484db59fc94f35a21b6d680d23b0ec69b286b7f" + integrity sha512-i4yps1mBp2ijrx7E96RXrQXQQHm6F4ym1TOD0D69/sjDjZvQ22tqiEvaNw7pFZTUO5b9vWRHzbHzP9+UKuw+bA== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-is-pseudo-class@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.1.tgz#472fff2cf434bdf832f7145b2a5491587e790c9e" + integrity sha512-Og5RrTzwFhrKoA79c3MLkfrIBYmwuf/X83s+JQtz/Dkk/MpsaKtqHV1OOzYkogQ+tj3oYp5Mq39XotBXNqVc3Q== + dependencies: + postcss-selector-parser "^6.0.9" + +"@csstools/postcss-normalize-display-values@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.0.tgz#ce698f688c28517447aedf15a9037987e3d2dc97" + integrity sha512-bX+nx5V8XTJEmGtpWTO6kywdS725t71YSLlxWt78XoHUbELWgoCXeOFymRJmL3SU1TLlKSIi7v52EWqe60vJTQ== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-oklab-function@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.0.2.tgz#87cd646e9450347a5721e405b4f7cc35157b7866" + integrity sha512-QwhWesEkMlp4narAwUi6pgc6kcooh8cC7zfxa9LSQNYXqzcdNUtNBzbGc5nuyAVreb7uf5Ox4qH1vYT3GA1wOg== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-progressive-custom-properties@^1.1.0", "@csstools/postcss-progressive-custom-properties@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz#542292558384361776b45c85226b9a3a34f276fa" + integrity sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA== + dependencies: + postcss-value-parser "^4.2.0" + +"@emotion/babel-plugin@^11.7.1": + version "11.7.2" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0" + integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ== + dependencies: + "@babel/helper-module-imports" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/runtime" "^7.13.10" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.2" + babel-plugin-macros "^2.6.1" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.0.13" + +"@emotion/cache@^11.4.0", "@emotion/cache@^11.7.1": + version "11.7.1" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539" + integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.1.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "4.0.13" + +"@emotion/hash@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + +"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/react@^11.1.1": + version "11.8.2" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.8.2.tgz#e51f5e6372e22e82780836c9288da19af4b51e70" + integrity sha512-+1bcHBaNJv5nkIIgnGKVsie3otS0wF9f1T1hteF3WeVvMNQEtfZ4YyFpnphGoot3ilU/wWMgP2SgIDuHLE/wAA== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/cache" "^11.7.1" + "@emotion/serialize" "^1.0.2" + "@emotion/utils" "^1.1.0" + "@emotion/weak-memoize" "^0.2.5" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" + integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2" + integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== + +"@emotion/unitless@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + +"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf" + integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ== + +"@emotion/weak-memoize@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + +"@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== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.1" + globals "^13.9.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.0.4" + 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== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" + integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + +"@jest/core@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" + integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/reporters" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^27.5.1" + jest-config "^27.5.1" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-resolve-dependencies "^27.5.1" + jest-runner "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + jest-watcher "^27.5.1" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== + dependencies: + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + +"@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== + dependencies: + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +"@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" + +"@jest/reporters@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" + integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-haste-map "^27.5.1" + jest-resolve "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + +"@jest/source-map@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" + integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.9" + source-map "^0.6.0" + +"@jest/test-result@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" + integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== + dependencies: + "@jest/console" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" + integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== + dependencies: + "@jest/test-result" "^27.5.1" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-runtime "^27.5.1" + +"@jest/transform@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" + integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.5.1" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-regex-util "^27.5.1" + jest-util "^27.5.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" + integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.11" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" + integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + +"@jridgewell/trace-mapping@^0.3.0": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" + integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@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", "@nodelib/fs.stat@^2.0.2": + 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.3": + 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" + +"@pmmmwh/react-refresh-webpack-plugin@^0.5.3": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz#df0d0d855fc527db48aac93c218a0bf4ada41f99" + integrity sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw== + dependencies: + ansi-html-community "^0.0.8" + common-path-prefix "^3.0.0" + core-js-pure "^3.8.1" + error-stack-parser "^2.0.6" + find-up "^5.0.0" + html-entities "^2.1.0" + loader-utils "^2.0.0" + schema-utils "^3.0.0" + source-map "^0.7.3" + +"@rollup/plugin-babel@^5.2.0": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" + integrity sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@rollup/pluginutils" "^3.1.0" + +"@rollup/plugin-node-resolve@^11.2.1": + version "11.2.1" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60" + integrity sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg== + dependencies: + "@rollup/pluginutils" "^3.1.0" + "@types/resolve" "1.17.1" + builtin-modules "^3.1.0" + deepmerge "^4.2.2" + is-module "^1.0.0" + resolve "^1.19.0" + +"@rollup/plugin-replace@^2.4.1": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz#a2d539314fbc77c244858faa523012825068510a" + integrity sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg== + dependencies: + "@rollup/pluginutils" "^3.1.0" + magic-string "^0.25.7" + +"@rollup/pluginutils@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" + integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== + dependencies: + "@types/estree" "0.0.39" + estree-walker "^1.0.1" + picomatch "^2.2.2" + +"@rushstack/eslint-patch@^1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.1.tgz#782fa5da44c4f38ae9fd38e9184b54e451936118" + integrity sha512-BUyKJGdDWqvWC5GEhyOiUrGNi9iJUr4CU0O2WxJL6QJhHeeA/NVBalH+FeK0r/x/W0rPymXt5s78TDS7d6lCwg== + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@surma/rollup-plugin-off-main-thread@^2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053" + integrity sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ== + dependencies: + ejs "^3.1.6" + json5 "^2.2.0" + magic-string "^0.25.0" + string.prototype.matchall "^4.0.6" + +"@svgr/babel-plugin-add-jsx-attribute@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906" + integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg== + +"@svgr/babel-plugin-remove-jsx-attribute@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef" + integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg== + +"@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd" + integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897" + integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ== + +"@svgr/babel-plugin-svg-dynamic-title@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7" + integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg== + +"@svgr/babel-plugin-svg-em-dimensions@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0" + integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw== + +"@svgr/babel-plugin-transform-react-native-svg@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80" + integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q== + +"@svgr/babel-plugin-transform-svg-component@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz#583a5e2a193e214da2f3afeb0b9e8d3250126b4a" + integrity sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ== + +"@svgr/babel-preset@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-5.5.0.tgz#8af54f3e0a8add7b1e2b0fcd5a882c55393df327" + integrity sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "^5.4.0" + "@svgr/babel-plugin-remove-jsx-attribute" "^5.4.0" + "@svgr/babel-plugin-remove-jsx-empty-expression" "^5.0.1" + "@svgr/babel-plugin-replace-jsx-attribute-value" "^5.0.1" + "@svgr/babel-plugin-svg-dynamic-title" "^5.4.0" + "@svgr/babel-plugin-svg-em-dimensions" "^5.4.0" + "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0" + "@svgr/babel-plugin-transform-svg-component" "^5.5.0" + +"@svgr/core@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-5.5.0.tgz#82e826b8715d71083120fe8f2492ec7d7874a579" + integrity sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ== + dependencies: + "@svgr/plugin-jsx" "^5.5.0" + camelcase "^6.2.0" + cosmiconfig "^7.0.0" + +"@svgr/hast-util-to-babel-ast@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz#5ee52a9c2533f73e63f8f22b779f93cd432a5461" + integrity sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ== + dependencies: + "@babel/types" "^7.12.6" + +"@svgr/plugin-jsx@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz#1aa8cd798a1db7173ac043466d7b52236b369000" + integrity sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA== + dependencies: + "@babel/core" "^7.12.3" + "@svgr/babel-preset" "^5.5.0" + "@svgr/hast-util-to-babel-ast" "^5.5.0" + svg-parser "^2.0.2" + +"@svgr/plugin-svgo@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz#02da55d85320549324e201c7b2e53bf431fcc246" + integrity sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ== + dependencies: + cosmiconfig "^7.0.0" + deepmerge "^4.2.2" + svgo "^1.2.2" + +"@svgr/webpack@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-5.5.0.tgz#aae858ee579f5fa8ce6c3166ef56c6a1b381b640" + integrity sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g== + dependencies: + "@babel/core" "^7.12.3" + "@babel/plugin-transform-react-constant-elements" "^7.12.1" + "@babel/preset-env" "^7.12.1" + "@babel/preset-react" "^7.12.5" + "@svgr/core" "^5.5.0" + "@svgr/plugin-jsx" "^5.5.0" + "@svgr/plugin-svgo" "^5.5.0" + loader-utils "^2.0.0" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.1.19" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/base16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/base16/-/base16-1.0.2.tgz#eb3a07db52309bfefb9ba010dfdb3c0784971f65" + integrity sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg== + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" + integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + dependencies: + "@types/node" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" + integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.3" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" + integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.4.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.1.tgz#c48251553e8759db9e656de3efc846954ac32304" + integrity sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/eslint@^7.28.2": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.29.0.tgz#e56ddc8e542815272720bb0b4ccc2aff9c3e1c78" + integrity sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^0.0.51": + version "0.0.51" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + +"@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": + version "4.17.28" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" + integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" + integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/html-minifier-terser@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== + +"@types/http-proxy@^1.17.8": + version "1.17.8" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.8.tgz#968c66903e7e42b483608030ee85800f22d03f55" + integrity sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/lodash@^4.14.178": + version "4.14.180" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" + integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== + +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + +"@types/node@*": + version "17.0.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" + integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prettier@^2.1.5": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" + integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== + +"@types/prop-types@*", "@types/prop-types@^15.7.4": + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + +"@types/q@^1.5.1": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" + integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/react-transition-group@^4.4.0": + version "4.4.4" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" + integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "17.0.43" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55" + integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/resolve@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" + integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== + dependencies: + "@types/node" "*" + +"@types/retry@^0.12.0": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.1.tgz#d8f1c0d0dc23afad6dc16a9e993a0865774b4065" + integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g== + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + +"@types/serve-index@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" + integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + dependencies: + "@types/express" "*" + +"@types/serve-static@*": + version "1.13.10" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" + integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/sockjs@^0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" + integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + dependencies: + "@types/node" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/trusted-types@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" + integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== + +"@types/ws@^8.2.2": + version "8.5.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" + integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== + dependencies: + "@types/node" "*" + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.5.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" + integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw== + dependencies: + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/type-utils" "5.16.0" + "@typescript-eslint/utils" "5.16.0" + debug "^4.3.2" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.2.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@^5.0.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.16.0.tgz#0b852567efa10660047f281cf004ed3db32866da" + integrity sha512-bitZtqO13XX64/UOQKoDbVg2H4VHzbHnWWlTRc7ofq7SuQyPCwEycF1Zmn5ZAMTJZ3p5uMS7xJGUdOtZK7LrNw== + dependencies: + "@typescript-eslint/utils" "5.16.0" + +"@typescript-eslint/parser@^5.5.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.16.0.tgz#e4de1bde4b4dad5b6124d3da227347616ed55508" + integrity sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA== + dependencies: + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/typescript-estree" "5.16.0" + debug "^4.3.2" + +"@typescript-eslint/scope-manager@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a" + integrity sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ== + dependencies: + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/visitor-keys" "5.16.0" + +"@typescript-eslint/type-utils@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692" + integrity sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ== + dependencies: + "@typescript-eslint/utils" "5.16.0" + debug "^4.3.2" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee" + integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g== + +"@typescript-eslint/typescript-estree@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61" + integrity sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ== + dependencies: + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/visitor-keys" "5.16.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.16.0", "@typescript-eslint/utils@^5.13.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679" + integrity sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/typescript-estree" "5.16.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb" + integrity sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g== + dependencies: + "@typescript-eslint/types" "5.16.0" + eslint-visitor-keys "^3.0.0" + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +ace-builds@^1.4.13: + version "1.4.14" + resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.14.tgz#2c41ccbccdd09e665d3489f161a20baeb3a3c852" + integrity sha512-NBOQlm9+7RBqRqZwimpgquaLeTJFayqb9UEPtTkpC3TkkwDnlsT/TwsCC0svjt9kEZ6G9mH5AEOHSz6Q/HrzQQ== + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-import-assertions@^1.7.6: + version "1.8.0" + 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: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-node@^1.6.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + +acorn-walk@^7.0.0, acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.0.0, acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, 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== + +address@^1.0.1, address@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" + integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== + +adjust-sourcemap-loader@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz#fc4a0fd080f7d10471f30a7320f25560ade28c99" + integrity sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A== + dependencies: + loader-utils "^2.0.0" + regex-parser "^2.2.11" + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.6.0, ajv@^8.8.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3, 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== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.1.tgz#eb0c9a8f77786cad2af8ff2b862899842d7b6adb" + integrity sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" + integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA== + dependencies: + "@babel/runtime" "^7.10.2" + "@babel/runtime-corejs3" "^7.10.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-includes@^3.1.3, array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +array.prototype.flatmap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" + integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +asap@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + +async@0.9.x: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +autoprefixer@^10.4.4: + version "10.4.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" + integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== + dependencies: + browserslist "^4.20.2" + caniuse-lite "^1.0.30001317" + fraction.js "^4.2.0" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + +axe-core@^4.3.5: + version "4.4.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413" + integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw== + +axobject-query@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" + integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== + +babel-jest@^27.4.2, babel-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" + integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== + dependencies: + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-loader@^8.2.3: + version "8.2.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.4.tgz#95f5023c791b2e9e2ca6f67b0984f39c82ff384b" + integrity sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^2.0.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" + integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-macros@^2.6.1: + version "2.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + +babel-plugin-macros@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +babel-plugin-named-asset-import@^0.3.8: + version "0.3.8" + resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz#6b7fa43c59229685368683c28bc9734f24524cc2" + integrity sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q== + +babel-plugin-polyfill-corejs2@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" + integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.3.1" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" + integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.1" + core-js-compat "^3.21.0" + +babel-plugin-polyfill-regenerator@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" + integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.1" + +babel-plugin-transform-react-remove-prop-types@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" + integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" + integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== + dependencies: + babel-plugin-jest-hoist "^27.5.1" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-react-app@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz#ed6005a20a24f2c88521809fa9aea99903751584" + integrity sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg== + dependencies: + "@babel/core" "^7.16.0" + "@babel/plugin-proposal-class-properties" "^7.16.0" + "@babel/plugin-proposal-decorators" "^7.16.4" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.0" + "@babel/plugin-proposal-numeric-separator" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-private-methods" "^7.16.0" + "@babel/plugin-transform-flow-strip-types" "^7.16.0" + "@babel/plugin-transform-react-display-name" "^7.16.0" + "@babel/plugin-transform-runtime" "^7.16.4" + "@babel/preset-env" "^7.16.4" + "@babel/preset-react" "^7.16.0" + "@babel/preset-typescript" "^7.16.0" + "@babel/runtime" "^7.16.3" + babel-plugin-macros "^3.1.0" + babel-plugin-transform-react-remove-prop-types "^0.4.24" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base16@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" + integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bfj@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.0.2.tgz#1988ce76f3add9ac2913fd8ba47aad9e651bfbb2" + integrity sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw== + dependencies: + bluebird "^3.5.5" + check-types "^11.1.1" + hoopy "^0.1.4" + tryer "^1.0.1" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +body-parser@1.19.2: + version "1.19.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e" + integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.7" + raw-body "2.4.3" + type-is "~1.6.18" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1, browserslist@^4.20.2: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== + dependencies: + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" + escalade "^3.1.1" + node-releases "^2.0.2" + picocolors "^1.0.0" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +builtin-modules@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" + integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0, camelcase@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: + version "1.0.30001320" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" + integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== + +case-sensitive-paths-webpack-plugin@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" + integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== + +chalk@^2.0.0, chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +char-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-2.0.1.tgz#6dafdb25f9d3349914079f010ba8d0e6ff9cd01e" + integrity sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw== + +charcodes@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/charcodes/-/charcodes-0.2.0.tgz#5208d327e6cc05f99eb80ffc814707572d1f14e4" + integrity sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ== + +check-types@^11.1.1: + version "11.1.2" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.1.2.tgz#86a7c12bf5539f6324eb0e70ca8896c0e38f3e2f" + integrity sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ== + +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.2, chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +classnames@^2.2.5: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + +clean-css@^5.2.2: + version "5.2.4" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.4.tgz#982b058f8581adb2ae062520808fb2429bd487a4" + integrity sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg== + dependencies: + source-map "~0.6.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0, color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa" + integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colord@^2.9.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" + integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== + +colorette@^2.0.10: + version "2.0.16" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" + integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +common-path-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" + integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== + +common-tags@^1.8.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +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= + +confusing-browser-globals@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" + integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +core-js-compat@^3.20.2, core-js-compat@^3.21.0: + version "3.21.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.21.1.tgz#cac369f67c8d134ff8f9bd1623e3bc2c42068c82" + integrity sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g== + dependencies: + browserslist "^4.19.1" + semver "7.0.0" + +core-js-pure@^3.20.2, core-js-pure@^3.8.1: + version "3.21.1" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.1.tgz#8c4d1e78839f5f46208de7230cebfb72bc3bdb51" + integrity sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ== + +core-js@^3.19.2: + version "3.21.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94" + integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + +cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +css-blank-pseudo@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz#36523b01c12a25d812df343a32c322d2a2324561" + integrity sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ== + dependencies: + postcss-selector-parser "^6.0.9" + +css-declaration-sorter@^6.0.3: + version "6.1.4" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz#b9bfb4ed9a41f8dcca9bf7184d849ea94a8294b4" + integrity sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw== + dependencies: + timsort "^0.3.0" + +css-has-pseudo@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz#57f6be91ca242d5c9020ee3e51bbb5b89fc7af73" + integrity sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw== + dependencies: + postcss-selector-parser "^6.0.9" + +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== + dependencies: + icss-utils "^5.1.0" + postcss "^8.4.7" + 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" + +css-minimizer-webpack-plugin@^3.2.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz#ab78f781ced9181992fe7b6e4f3422e76429878f" + integrity sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q== + dependencies: + cssnano "^5.0.6" + jest-worker "^27.0.2" + postcss "^8.3.5" + schema-utils "^4.0.0" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + +css-prefers-color-scheme@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz#ca8a22e5992c10a5b9d315155e7caee625903349" + integrity sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA== + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-select@^4.1.3: + version "4.2.1" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" + integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ== + dependencies: + boolbase "^1.0.0" + css-what "^5.1.0" + domhandler "^4.3.0" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^3.2.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" + integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== + +css-what@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== + +cssdb@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-6.5.0.tgz#61264b71f29c834f09b59cb3e5b43c8226590122" + integrity sha512-Rh7AAopF2ckPXe/VBcoUS9JrCZNSyc60+KpgE6X25vpVxA32TmiqvExjkfhwP4wGSb6Xe8Z/JIyGqwgx/zZYFA== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.5.tgz#267ded811a3e1664d78707f5355fcd89feeb38ac" + integrity sha512-WopL7PzN7sos3X8B54/QGl+CZUh1f0qN4ds+y2d5EPwRSSc3jsitVw81O+Uyop0pXyOfPfZxnc+LmA8w/Ki/WQ== + dependencies: + css-declaration-sorter "^6.0.3" + cssnano-utils "^3.1.0" + postcss-calc "^8.2.3" + postcss-colormin "^5.3.0" + postcss-convert-values "^5.1.0" + postcss-discard-comments "^5.1.1" + postcss-discard-duplicates "^5.1.0" + postcss-discard-empty "^5.1.1" + postcss-discard-overridden "^5.1.0" + postcss-merge-longhand "^5.1.3" + postcss-merge-rules "^5.1.1" + postcss-minify-font-values "^5.1.0" + postcss-minify-gradients "^5.1.1" + postcss-minify-params "^5.1.2" + postcss-minify-selectors "^5.2.0" + postcss-normalize-charset "^5.1.0" + postcss-normalize-display-values "^5.1.0" + postcss-normalize-positions "^5.1.0" + postcss-normalize-repeat-style "^5.1.0" + postcss-normalize-string "^5.1.0" + postcss-normalize-timing-functions "^5.1.0" + postcss-normalize-unicode "^5.1.0" + postcss-normalize-url "^5.1.0" + postcss-normalize-whitespace "^5.1.1" + postcss-ordered-values "^5.1.1" + postcss-reduce-initial "^5.1.0" + postcss-reduce-transforms "^5.1.0" + postcss-svgo "^5.1.0" + postcss-unique-selectors "^5.1.1" + +cssnano-utils@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" + integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== + +cssnano@^5.0.6: + version "5.1.5" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.5.tgz#5f3f519538c7f1c182c527096892243db3e17397" + integrity sha512-VZO1e+bRRVixMeia1zKagrv0lLN1B/r/u12STGNNUFxnp97LIFgZHQa0JxqlwEkvzUyA9Oz/WnCTAFkdEbONmg== + dependencies: + cssnano-preset-default "^5.2.5" + lilconfig "^2.0.3" + yaml "^1.10.2" + +csso@^4.0.2, csso@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +csstype@^3.0.10, csstype@^3.0.2: + version "3.0.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== + +damerau-levenshtein@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +debug@2.6.9, debug@^2.6.0, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^3.1.1, debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + +deep-equal@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= + +del@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952" + integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ== + dependencies: + globby "^11.0.1" + graceful-fs "^4.2.4" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.2" + p-map "^4.0.0" + rimraf "^3.0.2" + slash "^3.0.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +detect-port-alt@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== + dependencies: + address "^1.0.1" + debug "^2.6.0" + +detective@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" + integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== + dependencies: + acorn-node "^1.6.1" + defined "^1.0.0" + minimist "^1.1.1" + +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + +diff-match-patch@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" + integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== + +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +domelementtype@1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== + dependencies: + domelementtype "^2.2.0" + +domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dotenv-expand@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" + integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== + +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + +duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +ejs@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a" + integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw== + dependencies: + jake "^10.6.1" + +electron-to-chromium@^1.4.84: + version "1.4.93" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.93.tgz#2e87ac28721cb31d472ec2bd04f7daf9f2e13de2" + integrity sha512-ywq9Pc5Gwwpv7NG767CtoU8xF3aAUQJjH9//Wy3MBCg4w5JSLbJUq2L8IsCdzPMjvSgxuue9WcVaTOyyxCL0aQ== + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +enhanced-resolve@^5.9.2: + version "5.9.2" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" + integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error-stack-parser@^2.0.6: + version "2.0.7" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.7.tgz#b0c6e2ce27d0495cf78ad98715e0cad1219abb57" + integrity sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA== + dependencies: + stackframe "^1.1.1" + +es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-config-react-app@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-7.0.0.tgz#0fa96d5ec1dfb99c029b1554362ab3fa1c3757df" + integrity sha512-xyymoxtIt1EOsSaGag+/jmcywRuieQoA2JbPCjnw9HukFj9/97aGPoZVFioaotzk1K5Qt9sHO5EutZbkrAXS0g== + dependencies: + "@babel/core" "^7.16.0" + "@babel/eslint-parser" "^7.16.3" + "@rushstack/eslint-patch" "^1.1.0" + "@typescript-eslint/eslint-plugin" "^5.5.0" + "@typescript-eslint/parser" "^5.5.0" + babel-preset-react-app "^10.0.1" + confusing-browser-globals "^1.0.11" + eslint-plugin-flowtype "^8.0.3" + eslint-plugin-import "^2.25.3" + eslint-plugin-jest "^25.3.0" + eslint-plugin-jsx-a11y "^6.5.1" + eslint-plugin-react "^7.27.1" + eslint-plugin-react-hooks "^4.3.0" + eslint-plugin-testing-library "^5.0.1" + +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + +eslint-module-utils@^2.7.2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== + dependencies: + debug "^3.2.7" + find-up "^2.1.0" + +eslint-plugin-flowtype@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz#e1557e37118f24734aa3122e7536a038d34a4912" + integrity sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ== + dependencies: + lodash "^4.17.21" + string-natural-compare "^3.0.1" + +eslint-plugin-import@^2.25.3: + version "2.25.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" + integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.2" + has "^1.0.3" + is-core-module "^2.8.0" + is-glob "^4.0.3" + minimatch "^3.0.4" + object.values "^1.1.5" + resolve "^1.20.0" + tsconfig-paths "^3.12.0" + +eslint-plugin-jest@^25.3.0: + version "25.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz#ff4ac97520b53a96187bad9c9814e7d00de09a6a" + integrity sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ== + dependencies: + "@typescript-eslint/experimental-utils" "^5.0.0" + +eslint-plugin-jsx-a11y@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" + integrity sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g== + dependencies: + "@babel/runtime" "^7.16.3" + aria-query "^4.2.2" + array-includes "^3.1.4" + ast-types-flow "^0.0.7" + axe-core "^4.3.5" + axobject-query "^2.2.0" + damerau-levenshtein "^1.0.7" + emoji-regex "^9.2.2" + has "^1.0.3" + jsx-ast-utils "^3.2.1" + language-tags "^1.0.5" + minimatch "^3.0.4" + +eslint-plugin-react-hooks@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" + integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== + +eslint-plugin-react@^7.27.1: + version "7.29.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" + integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== + dependencies: + array-includes "^3.1.4" + array.prototype.flatmap "^1.2.5" + doctrine "^2.1.0" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.0" + object.values "^1.1.5" + prop-types "^15.8.1" + resolve "^2.0.0-next.3" + semver "^6.3.0" + string.prototype.matchall "^4.0.6" + +eslint-plugin-testing-library@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.1.0.tgz#6ad539a53d4e897d3045902f8e534e07cebd4e8b" + integrity sha512-YSNzasJUbyhOTe14ZPygeOBvcPvcaNkwHwrj4vdf+uirr2D32JTDaKi6CP5Os2aWtOcvt4uBSPXp9h5xGoqvWQ== + dependencies: + "@typescript-eslint/utils" "^5.13.0" + +eslint-scope@5.1.1, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint-webpack-plugin@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz#83dad2395e5f572d6f4d919eedaa9cf902890fcb" + integrity sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg== + dependencies: + "@types/eslint" "^7.28.2" + jest-worker "^27.3.1" + micromatch "^4.0.4" + normalize-path "^3.0.0" + schema-utils "^3.1.1" + +eslint@^8.3.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" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" + 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" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + 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" + 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.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== + dependencies: + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" + integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expect@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== + dependencies: + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + +express@^4.17.1: + version "4.17.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1" + integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.19.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.4.2" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.9.7" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.17.2" + serve-static "1.14.2" + setprototypeof "1.2.0" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.11, fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, 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= + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +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" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +filelist@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b" + integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ== + dependencies: + minimatch "^3.0.4" + +filesize@^8.0.6: + version "8.0.7" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8" + integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + 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" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.5" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" + integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== + +follow-redirects@^1.0.0: + version "1.14.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" + integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== + +fork-ts-checker-webpack-plugin@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz#0282b335fa495a97e167f69018f566ea7d2a2b5e" + integrity sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw== + dependencies: + "@babel/code-frame" "^7.8.3" + "@types/json-schema" "^7.0.5" + chalk "^4.1.0" + chokidar "^3.4.2" + cosmiconfig "^6.0.0" + deepmerge "^4.2.2" + fs-extra "^9.0.0" + glob "^7.1.6" + memfs "^3.1.2" + minimatch "^3.0.4" + schema-utils "2.7.0" + semver "^7.3.2" + tapable "^1.0.0" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-extra@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8" + integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^9.0.0, fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-monkey@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + +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= + +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "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== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +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== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.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.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" + integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.1, globby@^11.0.4: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== + dependencies: + duplexer "^0.1.2" + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +harmony-reflect@^1.4.6: + version "1.6.2" + resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.2.tgz#31ecbd32e648a34d030d86adb67d4d47547fe710" + integrity sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g== + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +hoopy@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" + integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-entities@^2.1.0, html-entities@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.2.tgz#760b404685cb1d794e4f4b744332e3b00dcfe488" + integrity sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-minifier-terser@^6.0.2: + version "6.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" + integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== + dependencies: + camel-case "^4.1.2" + clean-css "^5.2.2" + commander "^8.3.0" + he "^1.2.0" + param-case "^3.0.4" + relateurl "^0.2.7" + terser "^5.10.0" + +html-webpack-plugin@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" + integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== + dependencies: + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" + tapable "^2.0.0" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.6.tgz#2e02406ab2df8af8a7abfba62e0da01c62b95afd" + integrity sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA== + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-proxy-middleware@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz#03af0f4676d172ae775cb5c33f592f40e1a4e07a" + integrity sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg== + dependencies: + "@types/http-proxy" "^1.17.8" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +idb@^6.1.4: + version "6.1.5" + resolved "https://registry.yarnpkg.com/idb/-/idb-6.1.5.tgz#dbc53e7adf1ac7c59f9b2bf56e00b4ea4fce8c7b" + integrity sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw== + +identity-obj-proxy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14" + integrity sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ= + dependencies: + harmony-reflect "^1.4.6" + +ignore@^5.1.8, 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== + +immer@^9.0.7: + version "9.0.12" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20" + integrity sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA== + +immutable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" + integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== + +import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +ip@^1.1.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-core-module@^2.2.0, is-core-module@^2.8.0, is-core-module@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= + +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-inside@^3.0.2: + 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-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-regex@^1.0.4, is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-root@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jake@^10.6.1: + version "10.8.4" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.4.tgz#f6a8b7bf90c6306f768aa82bb7b98bf4ca15e84a" + integrity sha512-MtWeTkl1qGsWUtbl/Jsca/8xSoK3x0UmS82sNbjqxxG/de/M/3b1DntdjHgPMC50enlTNwXOCRqPXLLt5cCfZA== + dependencies: + async "0.9.x" + chalk "^4.0.2" + filelist "^1.0.1" + minimatch "^3.0.4" + +jest-changed-files@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" + integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== + dependencies: + "@jest/types" "^27.5.1" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" + integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" + integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== + dependencies: + "@jest/core" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" + integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.5.1" + "@jest/types" "^27.5.1" + babel-jest "^27.5.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.9" + jest-circus "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-get-type "^27.5.1" + jest-jasmine2 "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runner "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^27.5.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-docblock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" + integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" + integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + jest-get-type "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + +jest-environment-jsdom@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" + integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + jsdom "^16.6.0" + +jest-environment-node@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" + integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + +jest-haste-map@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" + integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== + dependencies: + "@jest/types" "^27.5.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^27.5.1" + jest-serializer "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" + integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + throat "^6.0.1" + +jest-leak-detector@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" + integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== + dependencies: + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-matcher-utils@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.5.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^27.0.0, jest-regex-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== + +jest-resolve-dependencies@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" + integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== + dependencies: + "@jest/types" "^27.5.1" + jest-regex-util "^27.5.1" + jest-snapshot "^27.5.1" + +jest-resolve@^27.4.2, jest-resolve@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" + integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.5.1" + jest-validate "^27.5.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" + integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + graceful-fs "^4.2.9" + jest-docblock "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-haste-map "^27.5.1" + jest-leak-detector "^27.5.1" + jest-message-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runtime "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" + integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/globals" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-serializer@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.9" + +jest-snapshot@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" + integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.5.1" + graceful-fs "^4.2.9" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + jest-haste-map "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + natural-compare "^1.4.0" + pretty-format "^27.5.1" + semver "^7.3.2" + +jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" + integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== + dependencies: + "@jest/types" "^27.5.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.5.1" + leven "^3.1.0" + pretty-format "^27.5.1" + +jest-watch-typeahead@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-1.0.0.tgz#4de2ca1eb596acb1889752afbab84b74fcd99173" + integrity sha512-jxoszalAb394WElmiJTFBMzie/RDCF+W7Q29n5LzOPtcoQoHWfdUtHFkbhgf5NwWe8uMOxvKb/g7ea7CshfkTw== + dependencies: + ansi-escapes "^4.3.1" + chalk "^4.0.0" + jest-regex-util "^27.0.0" + jest-watcher "^27.0.0" + slash "^4.0.0" + string-length "^5.0.1" + strip-ansi "^7.0.1" + +jest-watcher@^27.0.0, jest-watcher@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" + integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== + dependencies: + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.5.1" + string-length "^4.0.1" + +jest-worker@^26.2.1: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest-worker@^27.0.2, jest-worker@^27.3.1, jest-worker@^27.4.5, jest-worker@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.4.3: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" + integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== + dependencies: + "@jest/core" "^27.5.1" + import-local "^3.0.2" + jest-cli "^27.5.1" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +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= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2, json5@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonpointer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.0.tgz#f802669a524ec4805fa7389eadbc9921d5dc8072" + integrity sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg== + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" + integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== + dependencies: + array-includes "^3.1.3" + object.assign "^4.1.2" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +klona@^2.0.4, klona@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" + integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== + +language-subtag-registry@~0.3.2: + version "0.3.21" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" + integrity sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg== + +language-tags@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" + integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo= + dependencies: + language-subtag-registry "~0.3.2" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lilconfig@^2.0.3, lilconfig@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" + integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +loader-runner@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" + integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== + +loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +loader-utils@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.0.tgz#bcecc51a7898bee7473d4bc6b845b23af8304d4f" + integrity sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ== + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + 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.curry@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" + integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.25.0, magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memfs@^3.1.2, memfs@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.1.tgz#b78092f466a0dce054d63d39275b24c71d3f1305" + integrity sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw== + dependencies: + fs-monkey "1.0.3" + +memoize-one@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-create-react-context@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" + integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== + dependencies: + "@babel/runtime" "^7.12.1" + tiny-warning "^1.0.3" + +mini-css-extract-plugin@^2.4.5: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" + integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== + dependencies: + schema-utils "^4.0.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +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== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4, 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" + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +mkdirp@^0.5.5, mkdirp@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nanoid@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +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= + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-forge@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2" + integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-releases@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" + integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== + +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== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nth-check@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +nth-check@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== + dependencies: + boolbase "^1.0.0" + +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-hash@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.entries@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.fromentries@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" + integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.hasown@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" + integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.values@^1.1.0, object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.9, open@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + 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@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + 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-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-retry@^4.5.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.1.tgz#8fcddd5cdf7a67a0911a9cf2ef0e5df7f602316c" + integrity sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA== + dependencies: + "@types/retry" "^0.12.0" + retry "^0.13.1" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0, parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +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= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6, path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkg-dir@^4.1.0, pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + +portfinder@^1.0.28: + version "1.0.28" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.5" + +postcss-attribute-case-insensitive@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.0.tgz#39cbf6babf3ded1e4abf37d09d6eda21c644105c" + integrity sha512-b4g9eagFGq9T5SWX4+USfVyjIb3liPnjhHHRMP7FMB2kFVpYyfEscV0wP3eaXhKlcHKUut8lt5BGoeylWA/dBQ== + dependencies: + postcss-selector-parser "^6.0.2" + +postcss-browser-comments@^4: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz#bcfc86134df5807f5d3c0eefa191d42136b5e72a" + integrity sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg== + +postcss-calc@^8.2.3: + version "8.2.4" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5" + integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q== + dependencies: + postcss-selector-parser "^6.0.9" + postcss-value-parser "^4.2.0" + +postcss-clamp@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-clamp/-/postcss-clamp-4.1.0.tgz#7263e95abadd8c2ba1bd911b0b5a5c9c93e02363" + integrity sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-functional-notation@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.2.tgz#f59ccaeb4ee78f1b32987d43df146109cc743073" + integrity sha512-DXVtwUhIk4f49KK5EGuEdgx4Gnyj6+t2jBSEmxvpIK9QI40tWrpS2Pua8Q7iIZWBrki2QOaeUdEaLPPa91K0RQ== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-hex-alpha@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.3.tgz#61a0fd151d28b128aa6a8a21a2dad24eebb34d52" + integrity sha512-fESawWJCrBV035DcbKRPAVmy21LpoyiXdPTuHUfWJ14ZRjY7Y7PA6P4g8z6LQGYhU1WAxkTxjIjurXzoe68Glw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-rebeccapurple@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.0.2.tgz#5d397039424a58a9ca628762eb0b88a61a66e079" + integrity sha512-SFc3MaocHaQ6k3oZaFwH8io6MdypkUtEy/eXzXEB1vEQlO3S3oDc/FSZA8AsS04Z25RirQhlDlHLh3dn7XewWw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-colormin@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a" + integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.2.0" + +postcss-convert-values@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.0.tgz#f8d3abe40b4ce4b1470702a0706343eac17e7c10" + integrity sha512-GkyPbZEYJiWtQB0KZ0X6qusqFHUepguBCNFi9t5JJc7I2OTXG7C0twbTLvCfaKOLl3rSXmpAwV7W5txd91V84g== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-custom-media@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz#1be6aff8be7dc9bf1fe014bde3b71b92bb4552f1" + integrity sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g== + +postcss-custom-properties@^12.1.5: + version "12.1.5" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-12.1.5.tgz#e669cfff89b0ea6fc85c45864a32b450cb6b196f" + integrity sha512-FHbbB/hRo/7cxLGkc2NS7cDRIDN1oFqQnUKBiyh4b/gwk8DD8udvmRDpUhEK836kB8ggUCieHVOvZDnF9XhI3g== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-custom-selectors@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-6.0.0.tgz#022839e41fbf71c47ae6e316cb0e6213012df5ef" + integrity sha512-/1iyBhz/W8jUepjGyu7V1OPcGbc636snN1yXEQCinb6Bwt7KxsiU7/bLQlp8GwAXzCh7cobBU5odNn/2zQWR8Q== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-dir-pseudo-class@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.4.tgz#9afe49ea631f0cb36fa0076e7c2feb4e7e3f049c" + integrity sha512-I8epwGy5ftdzNWEYok9VjW9whC4xnelAtbajGv4adql4FIF09rnrxnA9Y8xSHN47y7gqFIv10C5+ImsLeJpKBw== + dependencies: + postcss-selector-parser "^6.0.9" + +postcss-discard-comments@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz#e90019e1a0e5b99de05f63516ce640bd0df3d369" + integrity sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ== + +postcss-discard-duplicates@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" + integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== + +postcss-discard-empty@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" + integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== + +postcss-discard-overridden@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e" + integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw== + +postcss-double-position-gradients@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.1.tgz#a12cfdb7d11fa1a99ccecc747f0c19718fb37152" + integrity sha512-jM+CGkTs4FcG53sMPjrrGE0rIvLDdCrqMzgDC5fLI7JHDO7o6QG8C5TQBtExb13hdBdoH9C2QVbG4jo2y9lErQ== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +postcss-env-function@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-4.0.6.tgz#7b2d24c812f540ed6eda4c81f6090416722a8e7a" + integrity sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-flexbugs-fixes@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz#2028e145313074fc9abe276cb7ca14e5401eb49d" + integrity sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ== + +postcss-focus-visible@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz#50c9ea9afa0ee657fb75635fabad25e18d76bf9e" + integrity sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw== + dependencies: + postcss-selector-parser "^6.0.9" + +postcss-focus-within@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz#5b1d2ec603195f3344b716c0b75f61e44e8d2e20" + integrity sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ== + dependencies: + postcss-selector-parser "^6.0.9" + +postcss-font-variant@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz#efd59b4b7ea8bb06127f2d031bfbb7f24d32fa66" + integrity sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA== + +postcss-gap-properties@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz#6401bb2f67d9cf255d677042928a70a915e6ba60" + integrity sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ== + +postcss-image-set-function@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-4.0.6.tgz#bcff2794efae778c09441498f40e0c77374870a9" + integrity sha512-KfdC6vg53GC+vPd2+HYzsZ6obmPqOk6HY09kttU19+Gj1nC3S3XBVEXDHxkhxTohgZqzbUb94bKXvKDnYWBm/A== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-initial@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-4.0.1.tgz#529f735f72c5724a0fb30527df6fb7ac54d7de42" + integrity sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ== + +postcss-js@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" + integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ== + dependencies: + camelcase-css "^2.0.1" + +postcss-lab-function@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-4.1.2.tgz#b75afe43ba9c1f16bfe9bb12c8109cabd55b5fc2" + integrity sha512-isudf5ldhg4fk16M8viAwAbg6Gv14lVO35N3Z/49NhbwPQ2xbiEoHgrRgpgQojosF4vF7jY653ktB6dDrUOR8Q== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +postcss-load-config@^3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.3.tgz#21935b2c43b9a86e6581a576ca7ee1bde2bd1d23" + integrity sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw== + dependencies: + lilconfig "^2.0.4" + yaml "^1.10.2" + +postcss-loader@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef" + integrity sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q== + dependencies: + cosmiconfig "^7.0.0" + klona "^2.0.5" + semver "^7.3.5" + +postcss-logical@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-5.0.4.tgz#ec75b1ee54421acc04d5921576b7d8db6b0e6f73" + integrity sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g== + +postcss-media-minmax@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz#7140bddec173e2d6d657edbd8554a55794e2a5b5" + integrity sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ== + +postcss-merge-longhand@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.3.tgz#a49e2be6237316e3b55e329e0a8da15d1f9f47ab" + integrity sha512-lX8GPGvZ0iGP/IboM7HXH5JwkXvXod1Rr8H8ixwiA372hArk0zP4ZcCy4z4Prg/bfNlbbTf0KCOjCF9kKnpP/w== + dependencies: + postcss-value-parser "^4.2.0" + stylehacks "^5.1.0" + +postcss-merge-rules@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.1.tgz#d327b221cd07540bcc8d9ff84446d8b404d00162" + integrity sha512-8wv8q2cXjEuCcgpIB1Xx1pIy8/rhMPIQqYKNzEdyx37m6gpq83mQQdCxgIkFgliyEnKvdwJf/C61vN4tQDq4Ww== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + cssnano-utils "^3.1.0" + postcss-selector-parser "^6.0.5" + +postcss-minify-font-values@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b" + integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-minify-gradients@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c" + integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw== + dependencies: + colord "^2.9.1" + cssnano-utils "^3.1.0" + postcss-value-parser "^4.2.0" + +postcss-minify-params@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.2.tgz#77e250780c64198289c954884ebe3ee4481c3b1c" + integrity sha512-aEP+p71S/urY48HWaRHasyx4WHQJyOYaKpQ6eXl8k0kxg66Wt/30VR6/woh8THgcpRbonJD5IeD+CzNhPi1L8g== + dependencies: + browserslist "^4.16.6" + cssnano-utils "^3.1.0" + postcss-value-parser "^4.2.0" + +postcss-minify-selectors@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.0.tgz#17c2be233e12b28ffa8a421a02fc8b839825536c" + integrity sha512-vYxvHkW+iULstA+ctVNx0VoRAR4THQQRkG77o0oa4/mBS0OzGvvzLIvHDv/nNEM0crzN2WIyFU5X7wZhaUK3RA== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-nested@5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" + integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== + dependencies: + postcss-selector-parser "^6.0.6" + +postcss-nesting@^10.1.3: + version "10.1.3" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-10.1.3.tgz#f0b1cd7ae675c697ab6a5a5ca1feea4784a2ef77" + integrity sha512-wUC+/YCik4wH3StsbC5fBG1s2Z3ZV74vjGqBFYtmYKlVxoio5TYGM06AiaKkQPPlkXWn72HKfS7Cw5PYxnoXSw== + dependencies: + postcss-selector-parser "^6.0.9" + +postcss-normalize-charset@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed" + integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg== + +postcss-normalize-display-values@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8" + integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-positions@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.0.tgz#902a7cb97cf0b9e8b1b654d4a43d451e48966458" + integrity sha512-8gmItgA4H5xiUxgN/3TVvXRoJxkAWLW6f/KKhdsH03atg0cB8ilXnrB5PpSshwVu/dD2ZsRFQcR1OEmSBDAgcQ== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-repeat-style@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.0.tgz#f6d6fd5a54f51a741cc84a37f7459e60ef7a6398" + integrity sha512-IR3uBjc+7mcWGL6CtniKNQ4Rr5fTxwkaDHwMBDGGs1x9IVRkYIT/M4NelZWkAOBdV6v3Z9S46zqaKGlyzHSchw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-string@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228" + integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-timing-functions@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb" + integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-unicode@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.0.tgz#3d23aede35e160089a285e27bf715de11dc9db75" + integrity sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ== + dependencies: + browserslist "^4.16.6" + postcss-value-parser "^4.2.0" + +postcss-normalize-url@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc" + integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew== + dependencies: + normalize-url "^6.0.1" + postcss-value-parser "^4.2.0" + +postcss-normalize-whitespace@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" + integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize/-/postcss-normalize-10.0.1.tgz#464692676b52792a06b06880a176279216540dd7" + integrity sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA== + dependencies: + "@csstools/normalize.css" "*" + postcss-browser-comments "^4" + sanitize.css "*" + +postcss-opacity-percentage@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz#bd698bb3670a0a27f6d657cc16744b3ebf3b1145" + integrity sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w== + +postcss-ordered-values@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.1.tgz#0b41b610ba02906a3341e92cab01ff8ebc598adb" + integrity sha512-7lxgXF0NaoMIgyihL/2boNAEZKiW0+HkMhdKMTD93CjW8TdCy2hSdj8lsAo+uwm7EDG16Da2Jdmtqpedl0cMfw== + dependencies: + cssnano-utils "^3.1.0" + postcss-value-parser "^4.2.0" + +postcss-overflow-shorthand@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz#ebcfc0483a15bbf1b27fdd9b3c10125372f4cbc2" + integrity sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg== + +postcss-page-break@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-3.0.4.tgz#7fbf741c233621622b68d435babfb70dd8c1ee5f" + integrity sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ== + +postcss-place@^7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-7.0.4.tgz#eb026650b7f769ae57ca4f938c1addd6be2f62c9" + integrity sha512-MrgKeiiu5OC/TETQO45kV3npRjOFxEHthsqGtkh3I1rPbZSbXGD/lZVi9j13cYh+NA8PIAPyk6sGjT9QbRyvSg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-preset-env@^7.0.1: + version "7.4.3" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-7.4.3.tgz#fb1c8b4cb405da042da0ddb8c5eda7842c08a449" + integrity sha512-dlPA65g9KuGv7YsmGyCKtFkZKCPLkoVMUE3omOl6yM+qrynVHxFvf0tMuippIrXB/sB/MyhL1FgTIbrO+qMERg== + dependencies: + "@csstools/postcss-color-function" "^1.0.3" + "@csstools/postcss-font-format-keywords" "^1.0.0" + "@csstools/postcss-hwb-function" "^1.0.0" + "@csstools/postcss-ic-unit" "^1.0.0" + "@csstools/postcss-is-pseudo-class" "^2.0.1" + "@csstools/postcss-normalize-display-values" "^1.0.0" + "@csstools/postcss-oklab-function" "^1.0.2" + "@csstools/postcss-progressive-custom-properties" "^1.3.0" + autoprefixer "^10.4.4" + browserslist "^4.20.2" + css-blank-pseudo "^3.0.3" + css-has-pseudo "^3.0.4" + css-prefers-color-scheme "^6.0.3" + cssdb "^6.5.0" + postcss-attribute-case-insensitive "^5.0.0" + postcss-clamp "^4.1.0" + postcss-color-functional-notation "^4.2.2" + postcss-color-hex-alpha "^8.0.3" + postcss-color-rebeccapurple "^7.0.2" + postcss-custom-media "^8.0.0" + postcss-custom-properties "^12.1.5" + postcss-custom-selectors "^6.0.0" + postcss-dir-pseudo-class "^6.0.4" + postcss-double-position-gradients "^3.1.1" + postcss-env-function "^4.0.6" + postcss-focus-visible "^6.0.4" + postcss-focus-within "^5.0.4" + postcss-font-variant "^5.0.0" + postcss-gap-properties "^3.0.3" + postcss-image-set-function "^4.0.6" + postcss-initial "^4.0.1" + postcss-lab-function "^4.1.2" + postcss-logical "^5.0.4" + postcss-media-minmax "^5.0.0" + postcss-nesting "^10.1.3" + postcss-opacity-percentage "^1.1.2" + postcss-overflow-shorthand "^3.0.3" + postcss-page-break "^3.0.4" + postcss-place "^7.0.4" + postcss-pseudo-class-any-link "^7.1.1" + postcss-replace-overflow-wrap "^4.0.0" + postcss-selector-not "^5.0.0" + postcss-value-parser "^4.2.0" + +postcss-pseudo-class-any-link@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.1.tgz#534eb1dadd9945eb07830dbcc06fb4d5d865b8e0" + integrity sha512-JRoLFvPEX/1YTPxRxp1JO4WxBVXJYrSY7NHeak5LImwJ+VobFMwYDQHvfTXEpcn+7fYIeGkC29zYFhFWIZD8fg== + dependencies: + postcss-selector-parser "^6.0.9" + +postcss-reduce-initial@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.0.tgz#fc31659ea6e85c492fb2a7b545370c215822c5d6" + integrity sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + +postcss-reduce-transforms@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9" + integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-replace-overflow-wrap@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz#d2df6bed10b477bf9c52fab28c568b4b29ca4319" + integrity sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw== + +postcss-selector-not@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz#ac5fc506f7565dd872f82f5314c0f81a05630dc7" + integrity sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ== + dependencies: + balanced-match "^1.0.0" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9: + 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-svgo@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d" + integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA== + dependencies: + postcss-value-parser "^4.2.0" + svgo "^2.7.0" + +postcss-unique-selectors@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" + integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== + dependencies: + postcss-selector-parser "^6.0.5" + +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== + +postcss@^7.0.35: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.3.5, postcss@^8.4.4, postcss@^8.4.6, postcss@^8.4.7: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== + dependencies: + nanoid "^3.3.1" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== + dependencies: + lodash "^4.17.20" + renderkid "^3.0.0" + +pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" + integrity sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q== + dependencies: + asap "~2.0.6" + +prompts@^2.0.1, prompts@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.9.7: + version "6.9.7" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" + integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== + +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== + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +raf@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== + dependencies: + performance-now "^2.1.0" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" + integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g== + dependencies: + bytes "3.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-ace@^9.4.1: + version "9.5.0" + resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-9.5.0.tgz#b6c32b70d404dd821a7e01accc2d76da667ff1f7" + integrity sha512-4l5FgwGh6K7A0yWVMQlPIXDItM4Q9zzXRqOae8KkCl6MkOob7sC1CzHxZdOGvV+QioKWbX2p5HcdOVUv6cAdSg== + dependencies: + ace-builds "^1.4.13" + diff-match-patch "^1.0.5" + lodash.get "^4.4.2" + lodash.isequal "^4.5.0" + prop-types "^15.7.2" + +react-app-polyfill@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz#95221e0a9bd259e5ca6b177c7bb1cb6768f68fd7" + integrity sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w== + dependencies: + core-js "^3.19.2" + object-assign "^4.1.1" + promise "^8.1.0" + raf "^3.4.1" + regenerator-runtime "^0.13.9" + whatwg-fetch "^3.6.2" + +react-base16-styling@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.9.1.tgz#4906b4c0a51636f2dca2cea8b682175aa8bd0c92" + integrity sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw== + dependencies: + "@babel/runtime" "^7.16.7" + "@types/base16" "^1.0.2" + "@types/lodash" "^4.14.178" + base16 "^1.0.0" + color "^3.2.1" + csstype "^3.0.10" + lodash.curry "^4.1.1" + +react-contextmenu@^2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/react-contextmenu/-/react-contextmenu-2.14.0.tgz#d8966f30614b9b780b928be4c8d92bd740d55cdd" + integrity sha512-ktqMOuad6sCFNJs/ltEwppN8F0YeXmqoZfwycgtZR/MxOXMYx1xgYC44SzWH259HdGyshk1/7sXGuIRwj9hzbw== + dependencies: + classnames "^2.2.5" + object-assign "^4.1.0" + +react-dev-utils@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.0.tgz#4eab12cdb95692a077616770b5988f0adf806526" + integrity sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ== + dependencies: + "@babel/code-frame" "^7.16.0" + address "^1.1.2" + browserslist "^4.18.1" + chalk "^4.1.2" + cross-spawn "^7.0.3" + detect-port-alt "^1.1.6" + escape-string-regexp "^4.0.0" + filesize "^8.0.6" + find-up "^5.0.0" + fork-ts-checker-webpack-plugin "^6.5.0" + global-modules "^2.0.0" + globby "^11.0.4" + gzip-size "^6.0.0" + immer "^9.0.7" + is-root "^2.1.0" + loader-utils "^3.2.0" + open "^8.4.0" + pkg-up "^3.1.0" + prompts "^2.4.2" + react-error-overlay "^6.0.10" + recursive-readdir "^2.2.2" + shell-quote "^1.7.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + +react-error-overlay@^6.0.10: + version "6.0.10" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6" + integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA== + +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-json-tree@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/react-json-tree/-/react-json-tree-0.16.1.tgz#dd40a4f759c173873d28e51316c29150e2473de5" + integrity sha512-VYvU/tgekJUrPhEVR6ZC789b3x9QPO7LmRX1YMZfWpqbC8pvXb7D74S0+CE6RVk55bXOS2VH1+8ZWA2PioEyqg== + dependencies: + "@babel/runtime" "^7.16.7" + "@types/prop-types" "^15.7.4" + prop-types "^15.8.1" + react-base16-styling "^0.9.1" + +react-refresh@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" + integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== + +react-router-dom@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363" + integrity sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ== + dependencies: + "@babel/runtime" "^7.12.13" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.1" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.1.tgz#4d2e4e9d5ae9425091845b8dbc6d9d276239774d" + integrity sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ== + dependencies: + "@babel/runtime" "^7.12.13" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-scripts@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.0.tgz#6547a6d7f8b64364ef95273767466cc577cb4b60" + integrity sha512-3i0L2CyIlROz7mxETEdfif6Sfhh9Lfpzi10CtcGs1emDQStmZfWjJbAIMtRD0opVUjQuFWqHZyRZ9PPzKCFxWg== + dependencies: + "@babel/core" "^7.16.0" + "@pmmmwh/react-refresh-webpack-plugin" "^0.5.3" + "@svgr/webpack" "^5.5.0" + babel-jest "^27.4.2" + babel-loader "^8.2.3" + babel-plugin-named-asset-import "^0.3.8" + babel-preset-react-app "^10.0.1" + bfj "^7.0.2" + browserslist "^4.18.1" + camelcase "^6.2.1" + case-sensitive-paths-webpack-plugin "^2.4.0" + css-loader "^6.5.1" + css-minimizer-webpack-plugin "^3.2.0" + dotenv "^10.0.0" + dotenv-expand "^5.1.0" + eslint "^8.3.0" + eslint-config-react-app "^7.0.0" + eslint-webpack-plugin "^3.1.1" + file-loader "^6.2.0" + fs-extra "^10.0.0" + html-webpack-plugin "^5.5.0" + identity-obj-proxy "^3.0.0" + jest "^27.4.3" + jest-resolve "^27.4.2" + jest-watch-typeahead "^1.0.0" + mini-css-extract-plugin "^2.4.5" + postcss "^8.4.4" + postcss-flexbugs-fixes "^5.0.2" + postcss-loader "^6.2.1" + postcss-normalize "^10.0.1" + postcss-preset-env "^7.0.1" + prompts "^2.4.2" + react-app-polyfill "^3.0.0" + react-dev-utils "^12.0.0" + react-refresh "^0.11.0" + resolve "^1.20.0" + resolve-url-loader "^4.0.0" + sass-loader "^12.3.0" + semver "^7.3.5" + source-map-loader "^3.0.0" + style-loader "^3.3.1" + tailwindcss "^3.0.2" + terser-webpack-plugin "^5.2.5" + webpack "^5.64.4" + webpack-dev-server "^4.6.0" + webpack-manifest-plugin "^4.0.2" + workbox-webpack-plugin "^6.4.1" + optionalDependencies: + fsevents "^2.3.2" + +react-select@^5.2.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.2.2.tgz#3d5edf0a60f1276fd5f29f9f90a305f0a25a5189" + integrity sha512-miGS2rT1XbFNjduMZT+V73xbJEeMzVkJOz727F6MeAr2hKE0uUSA8Ff7vD44H32x2PD3SRB6OXTY/L+fTV3z9w== + dependencies: + "@babel/runtime" "^7.12.0" + "@emotion/cache" "^11.4.0" + "@emotion/react" "^11.1.1" + "@types/react-transition-group" "^4.4.0" + memoize-one "^5.0.0" + prop-types "^15.6.0" + react-transition-group "^4.3.0" + +react-transition-group@^4.3.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" + integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +readable-stream@^2.0.1: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +recursive-readdir@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" + integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== + dependencies: + minimatch "3.0.4" + +regenerate-unicode-properties@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" + integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.9: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-parser@^2.2.11: + version "2.2.11" + resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" + integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== + +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" + integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" + integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.0.1" + regjsgen "^0.6.0" + regjsparser "^0.8.2" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +regjsgen@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" + integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== + +regjsparser@^0.8.2: + version "0.8.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" + integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== + dependencies: + jsesc "~0.5.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^6.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + +resolve-url-loader@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz#d50d4ddc746bb10468443167acf800dcd6c3ad57" + integrity sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA== + dependencies: + adjust-sourcemap-loader "^4.0.0" + convert-source-map "^1.7.0" + loader-utils "^2.0.0" + postcss "^7.0.35" + source-map "0.6.1" + +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== + dependencies: + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.3: + version "2.0.0-next.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" + integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +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.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup-plugin-terser@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" + integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== + dependencies: + "@babel/code-frame" "^7.10.4" + jest-worker "^26.2.1" + serialize-javascript "^4.0.0" + terser "^5.0.0" + +rollup@^2.43.1: + version "2.70.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.1.tgz#824b1f1f879ea396db30b0fc3ae8d2fead93523e" + integrity sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA== + optionalDependencies: + fsevents "~2.3.2" + +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.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sanitize.css@*: + version "13.0.0" + resolved "https://registry.yarnpkg.com/sanitize.css/-/sanitize.css-13.0.0.tgz#2675553974b27964c75562ade3bd85d79879f173" + integrity sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA== + +sass-loader@^12.3.0: + version "12.6.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.6.0.tgz#5148362c8e2cdd4b950f3c63ac5d16dbfed37bcb" + integrity sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA== + dependencies: + klona "^2.0.4" + neo-async "^2.6.2" + +sass@^1.34.1: + version "1.49.9" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.9.tgz#b15a189ecb0ca9e24634bae5d1ebc191809712f9" + integrity sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + +sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +schema-utils@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" + integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== + dependencies: + "@types/json-schema" "^7.0.4" + ajv "^6.12.2" + ajv-keywords "^3.4.1" + +schema-utils@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.0.tgz#e927cd5377cbb0a1075302cff8df1042cc2bce5b" + integrity sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ== + dependencies: + node-forge "^1.2.0" + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.2, 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== + dependencies: + lru-cache "^6.0.0" + +send@0.17.2: + version "0.17.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "1.8.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.14.2: + version "1.14.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" + integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.2" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" + integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== + +sockjs@^0.3.21: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +source-list-map@^2.0.0, source-list-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-loader@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.1.tgz#9ae5edc7c2d42570934be4c95d1ccc6352eba52d" + integrity sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA== + dependencies: + abab "^2.0.5" + iconv-lite "^0.6.3" + source-map-js "^1.0.1" + +source-map-support@^0.5.6, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.5.0, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.7.3, source-map@~0.7.2: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +source-map@^0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +stackframe@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.1.tgz#1033a3473ee67f08e2f2fc8eba6aef4f845124e1" + integrity sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg== + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-length@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-5.0.1.tgz#3d647f497b6e8e8d41e422f7e0b23bc536c8381e" + integrity sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow== + dependencies: + char-regex "^2.0.0" + strip-ansi "^7.0.1" + +string-natural-compare@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" + integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.matchall@^4.0.6: + version "4.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.4.1" + side-channel "^1.0.4" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +stringify-object@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.0, strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-comments@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b" + integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" + integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== + +stylehacks@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" + integrity sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q== + dependencies: + browserslist "^4.16.6" + postcss-selector-parser "^6.0.4" + +stylis@4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" + integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +svg-parser@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + +svgo@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +svgo@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +tailwindcss@^3.0.2: + version "3.0.23" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.23.tgz#c620521d53a289650872a66adfcb4129d2200d10" + integrity sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA== + dependencies: + arg "^5.0.1" + chalk "^4.1.2" + chokidar "^3.5.3" + color-name "^1.1.4" + cosmiconfig "^7.0.1" + detective "^5.2.0" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.11" + glob-parent "^6.0.2" + is-glob "^4.0.3" + normalize-path "^3.0.0" + object-hash "^2.2.0" + postcss "^8.4.6" + postcss-js "^4.0.0" + postcss-load-config "^3.1.0" + postcss-nested "5.0.6" + postcss-selector-parser "^6.0.9" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.0" + +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +temp-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" + integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== + +tempy@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.6.0.tgz#65e2c35abc06f1124a97f387b08303442bde59f3" + integrity sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw== + dependencies: + is-stream "^2.0.0" + temp-dir "^2.0.0" + type-fest "^0.16.0" + unique-string "^2.0.0" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.2.5: + version "5.3.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz#0320dcc270ad5372c1e8993fabbd927929773e54" + integrity sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g== + dependencies: + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.2" + +terser@^5.0.0, terser@^5.10.0, terser@^5.7.2: + version "5.12.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" + integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== + dependencies: + acorn "^8.5.0" + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.20" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +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= + +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +tiny-invariant@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + +tiny-warning@^1.0.0, tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +tryer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" + integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== + +tsconfig-paths@^3.12.0: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860" + integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +upath@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +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== + +v8-to-istanbul@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" + integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +watchpack@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" + integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +webpack-dev-middleware@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz#aa079a8dedd7e58bfeab358a9af7dab304cee57f" + integrity sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg== + dependencies: + colorette "^2.0.10" + memfs "^3.4.1" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@^4.6.0: + version "4.7.4" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.7.4.tgz#d0ef7da78224578384e795ac228d8efb63d5f945" + integrity sha512-nfdsb02Zi2qzkNmgtZjkrMOcXnYZ6FLKcQwpxT7MvmHKc+oTtDsBju8j+NMyAygZ9GW1jMEUpy3itHtqgEhe1A== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.2.2" + ansi-html-community "^0.0.8" + bonjour "^3.5.0" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + default-gateway "^6.0.3" + del "^6.0.0" + express "^4.17.1" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.0" + ipaddr.js "^2.0.1" + open "^8.0.9" + p-retry "^4.5.0" + portfinder "^1.0.28" + schema-utils "^4.0.0" + selfsigned "^2.0.0" + serve-index "^1.9.1" + sockjs "^0.3.21" + spdy "^4.0.2" + strip-ansi "^7.0.0" + webpack-dev-middleware "^5.3.1" + ws "^8.4.2" + +webpack-manifest-plugin@^4.0.2: + version "4.1.1" + resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz#10f8dbf4714ff93a215d5a45bcc416d80506f94f" + integrity sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow== + dependencies: + tapable "^2.0.0" + webpack-sources "^2.2.0" + +webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-sources@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd" + integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA== + dependencies: + source-list-map "^2.0.1" + source-map "^0.6.1" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.64.4: + version "5.70.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.70.0.tgz#3461e6287a72b5e6e2f4872700bc8de0d7500e6d" + integrity sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^0.0.51" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.9.2" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-better-errors "^1.0.2" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.3.1" + webpack-sources "^3.2.3" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-fetch@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +workbox-background-sync@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-6.5.2.tgz#28be9bf89b8e4e0379d45903280c7c12f4df836f" + integrity sha512-EjG37LSMDJ1TFlFg56wx6YXbH4/NkG09B9OHvyxx+cGl2gP5OuOzsCY3rOPJSpbcz6jpuA40VIC3HzSD4OvE1g== + dependencies: + idb "^6.1.4" + workbox-core "6.5.2" + +workbox-broadcast-update@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-6.5.2.tgz#b1f32bb40a9dcb5b05ca27e09fb7c01a0a126182" + integrity sha512-DjJYraYnprTZE/AQNoeogaxI1dPuYmbw+ZJeeP8uXBSbg9SNv5wLYofQgywXeRepv4yr/vglMo9yaHUmBMc+4Q== + dependencies: + workbox-core "6.5.2" + +workbox-build@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-6.5.2.tgz#774faafd84b1dc94b74739ceb5d8ff367748523b" + integrity sha512-TVi4Otf6fgwikBeMpXF9n0awHfZTMNu/nwlMIT9W+c13yvxkmDFMPb7vHYK6RUmbcxwPnz4I/R+uL76+JxG4JQ== + dependencies: + "@apideck/better-ajv-errors" "^0.3.1" + "@babel/core" "^7.11.1" + "@babel/preset-env" "^7.11.0" + "@babel/runtime" "^7.11.2" + "@rollup/plugin-babel" "^5.2.0" + "@rollup/plugin-node-resolve" "^11.2.1" + "@rollup/plugin-replace" "^2.4.1" + "@surma/rollup-plugin-off-main-thread" "^2.2.3" + ajv "^8.6.0" + common-tags "^1.8.0" + fast-json-stable-stringify "^2.1.0" + fs-extra "^9.0.1" + glob "^7.1.6" + lodash "^4.17.20" + pretty-bytes "^5.3.0" + rollup "^2.43.1" + rollup-plugin-terser "^7.0.0" + source-map "^0.8.0-beta.0" + stringify-object "^3.3.0" + strip-comments "^2.0.1" + tempy "^0.6.0" + upath "^1.2.0" + workbox-background-sync "6.5.2" + workbox-broadcast-update "6.5.2" + workbox-cacheable-response "6.5.2" + workbox-core "6.5.2" + workbox-expiration "6.5.2" + workbox-google-analytics "6.5.2" + workbox-navigation-preload "6.5.2" + workbox-precaching "6.5.2" + workbox-range-requests "6.5.2" + workbox-recipes "6.5.2" + workbox-routing "6.5.2" + workbox-strategies "6.5.2" + workbox-streams "6.5.2" + workbox-sw "6.5.2" + workbox-window "6.5.2" + +workbox-cacheable-response@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-6.5.2.tgz#d9252eb99f0d0fceb70f63866172f4eaac56a3e8" + integrity sha512-UnHGih6xqloV808T7ve1iNKZMbpML0jGLqkkmyXkJbZc5j16+HRSV61Qrh+tiq3E3yLvFMGJ3AUBODOPNLWpTg== + dependencies: + workbox-core "6.5.2" + +workbox-core@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-6.5.2.tgz#f5e06a22c6cb4651d3e13107443d972fdbd47364" + integrity sha512-IlxLGQf+wJHCR+NM0UWqDh4xe/Gu6sg2i4tfZk6WIij34IVk9BdOQgi6WvqSHd879jbQIUgL2fBdJUJyAP5ypQ== + +workbox-expiration@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-6.5.2.tgz#ee6ed755a220a0b375d67831f9237e4dcbccb59c" + integrity sha512-5Hfp0uxTZJrgTiy9W7AjIIec+9uTOtnxY/tRBm4DbqcWKaWbVTa+izrKzzOT4MXRJJIJUmvRhWw4oo8tpmMouw== + dependencies: + idb "^6.1.4" + workbox-core "6.5.2" + +workbox-google-analytics@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-6.5.2.tgz#a79fa7a40824873baaa333dcd72d1fdf1c53adf5" + integrity sha512-8SMar+N0xIreP5/2we3dwtN1FUmTMScoopL86aKdXBpio8vXc8Oqb5fCJG32ialjN8BAOzDqx/FnGeCtkIlyvw== + dependencies: + workbox-background-sync "6.5.2" + workbox-core "6.5.2" + workbox-routing "6.5.2" + workbox-strategies "6.5.2" + +workbox-navigation-preload@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-6.5.2.tgz#ffb3d9d5cdb881a3824851707da221dbb0bb3f23" + integrity sha512-iqDNWWMswjCsZuvGFDpcX1Z8InBVAlVBELJ28xShsWWntALzbtr0PXMnm2WHkXCc56JimmGldZi1N5yDPiTPOg== + dependencies: + workbox-core "6.5.2" + +workbox-precaching@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-6.5.2.tgz#a3117b4d3eb61ce8d01b9dfc063c48155bd7f9d3" + integrity sha512-OZAlQ8AAT20KugGKKuJMHdQ8X1IyNQaLv+mPTHj+8Dmv8peBq5uWNzs4g/1OSFmXsbXZ6a1CBC6YtQWVPhJQ9w== + dependencies: + workbox-core "6.5.2" + workbox-routing "6.5.2" + workbox-strategies "6.5.2" + +workbox-range-requests@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-6.5.2.tgz#b8b7e5b5830fecc22f0a1d8815457921df2e5bf9" + integrity sha512-zi5VqF1mWqfCyJLTMXn1EuH/E6nisqWDK1VmOJ+TnjxGttaQrseOhMn+BMvULFHeF8AvrQ0ogfQ6bSv0rcfAlg== + dependencies: + workbox-core "6.5.2" + +workbox-recipes@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-recipes/-/workbox-recipes-6.5.2.tgz#19f47ec25a8788c65d0cc8d217cbebc0bbbb5c63" + integrity sha512-2lcUKMYDiJKvuvRotOxLjH2z9K7jhj8GNUaHxHNkJYbTCUN3LsX1cWrsgeJFDZ/LgI565t3fntpbG9J415ZBXA== + dependencies: + workbox-cacheable-response "6.5.2" + workbox-core "6.5.2" + workbox-expiration "6.5.2" + workbox-precaching "6.5.2" + workbox-routing "6.5.2" + workbox-strategies "6.5.2" + +workbox-routing@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-6.5.2.tgz#e0ad46246ba51224fd57eff0dd46891b3220cb9a" + integrity sha512-nR1w5PjF6IVwo0SX3oE88LhmGFmTnqqU7zpGJQQPZiKJfEKgDENQIM9mh3L1ksdFd9Y3CZVkusopHfxQvit/BA== + dependencies: + workbox-core "6.5.2" + +workbox-strategies@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-6.5.2.tgz#56b02e6959c6391351011fc2e5b0829aff1ed859" + integrity sha512-fgbwaUMxbG39BHjJIs2y2X21C0bmf1Oq3vMQxJ1hr6y5JMJIm8rvKCcf1EIdAr+PjKdSk4ddmgyBQ4oO8be4Uw== + dependencies: + workbox-core "6.5.2" + +workbox-streams@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-6.5.2.tgz#2fb6ba307f7d2cbda63f64522a197be868b4ea25" + integrity sha512-ovD0P4UrgPtZ2Lfc/8E8teb1RqNOSZr+1ZPqLR6sGRZnKZviqKbQC3zVvvkhmOIwhWbpL7bQlWveLVONHjxd5w== + dependencies: + workbox-core "6.5.2" + workbox-routing "6.5.2" + +workbox-sw@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-6.5.2.tgz#2f5dca0e96c61a450fccf0405095ddf1b6f43bc7" + integrity sha512-2KhlYqtkoqlnPdllj2ujXUKRuEFsRDIp6rdE4l1PsxiFHRAFaRTisRQpGvRem5yxgXEr+fcEKiuZUW2r70KZaw== + +workbox-webpack-plugin@^6.4.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-6.5.2.tgz#0cf6e1d23d5107a88fd8502fd4f534215e1dd298" + integrity sha512-StrJ7wKp5tZuGVcoKLVjFWlhDy+KT7ZWsKnNcD6F08wA9Cpt6JN+PLIrplcsTHbQpoAV8+xg6RvcG0oc9z+RpQ== + dependencies: + fast-json-stable-stringify "^2.1.0" + pretty-bytes "^5.4.1" + upath "^1.2.0" + webpack-sources "^1.4.3" + workbox-build "6.5.2" + +workbox-window@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-6.5.2.tgz#46d6412cd57039bdf3d5dd914ad21fb3f98fe980" + integrity sha512-2kZH37r9Wx8swjEOL4B8uGM53lakMxsKkQ7mOKzGA/QAn/DQTEZGrdHWtypk2tbhKY5S0jvPS+sYDnb2Z3378A== + dependencies: + "@types/trusted-types" "^2.0.2" + workbox-core "6.5.2" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^7.4.6: + version "7.5.7" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" + integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== + +ws@^8.4.2: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +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== + +yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +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== diff --git a/maubot-src/maubot/matrix.py b/maubot-src/maubot/matrix.py new file mode 100644 index 0000000..8a811af --- /dev/null +++ b/maubot-src/maubot/matrix.py @@ -0,0 +1,314 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import Any, Awaitable +from html import escape +import asyncio + +import attr + +from mautrix.client import Client as MatrixClient, SyncStream +from mautrix.errors import DecryptionError +from mautrix.types import ( + BaseMessageEventContentFuncs, + EncryptedEvent, + Event, + EventID, + EventType, + Format, + MessageEvent, + MessageEventContent, + MessageType, + RelatesTo, + RoomID, + TextMessageEventContent, +) +from mautrix.util import markdown +from mautrix.util.formatter import EntityType, MarkdownString, MatrixParser + + +class HumanReadableString(MarkdownString): + def format(self, entity_type: EntityType, **kwargs) -> MarkdownString: + if entity_type == EntityType.URL and kwargs["url"] != self.text: + self.text = f"{self.text} ({kwargs['url']})" + return self + return super(HumanReadableString, self).format(entity_type, **kwargs) + + +class MaubotHTMLParser(MatrixParser[HumanReadableString]): + fs = HumanReadableString + + +async def parse_formatted( + message: str, allow_html: bool = False, render_markdown: bool = True +) -> tuple[str, str]: + if render_markdown: + html = markdown.render(message, allow_html=allow_html) + elif allow_html: + html = message + else: + return message, escape(message) + text = (await MaubotHTMLParser().parse(html)).text + if len(text) > 100 and len(text) + len(html) > 40000: + text = text[:100] + "[long message cut off]" + return text, html + + +class MaubotMessageEvent(MessageEvent): + client: MaubotMatrixClient + disable_reply: bool + + def __init__(self, base: MessageEvent, client: MaubotMatrixClient): + super().__init__( + **{a.name.lstrip("_"): getattr(base, a.name) for a in attr.fields(MessageEvent)} + ) + self.client = client + self.disable_reply = client.disable_replies + + async def respond( + self, + content: str | MessageEventContent, + event_type: EventType = EventType.ROOM_MESSAGE, + markdown: bool = True, + allow_html: bool = False, + reply: bool | str = False, + in_thread: bool | None = None, + edits: EventID | MessageEvent | None = None, + extra_content: dict[str, Any] | None = None, + ) -> EventID: + """ + Respond to the message. + + Args: + content: The content to respond with. If this is a string, it will be passed to + :func:`parse_formatted` with the markdown and allow_html flags. + Otherwise, the content is used as-is + event_type: The type of event to send. + markdown: When content is a string, should it be parsed as markdown? + allow_html: When content is a string, should it allow raw HTML? + reply: Should the response be sent as a reply to this event? + in_thread: Should the response be sent in a thread with this event? + By default (``None``), the response will be in a thread if this event is in a + thread. If set to ``False``, the response will never be in a thread. If set to + ``True``, the response will always be in a thread, creating one with this event as + the root if necessary. + edits: An event ID or MessageEvent to edit. If set, the reply and in_thread parameters + are ignored, as edits can't change the reply or thread status. + extra_content: Extra content to add to the event. + + Returns: + The ID of the response event. + """ + if isinstance(content, str): + content = TextMessageEventContent(msgtype=MessageType.NOTICE, body=content) + if allow_html or markdown: + content.format = Format.HTML + content.body, content.formatted_body = await parse_formatted( + content.body, render_markdown=markdown, allow_html=allow_html + ) + if edits: + content.set_edit(edits) + if ( + not edits + and in_thread is not False + and ( + in_thread + or ( + isinstance(self.content, BaseMessageEventContentFuncs) + and self.content.get_thread_parent() + ) + ) + ): + content.set_thread_parent(self) + if reply and not edits: + if reply != "force" and self.disable_reply: + content.body = f"{self.sender}: {content.body}" + fmt_body = content.formatted_body or escape(content.body).replace("\n", "
") + content.formatted_body = ( + f'' + f"{self.sender}" + f": {fmt_body}" + ) + else: + content.set_reply(self) + if extra_content: + for k, v in extra_content.items(): + content[k] = v + return await self.client.send_message_event(self.room_id, event_type, content) + + def reply( + self, + content: str | MessageEventContent, + event_type: EventType = EventType.ROOM_MESSAGE, + markdown: bool = True, + allow_html: bool = False, + in_thread: bool | None = None, + extra_content: dict[str, Any] | None = None, + ) -> Awaitable[EventID]: + """ + Reply to the message. The parameters are the same as :meth:`respond`, + but ``reply`` is always ``True`` and ``edits`` is not supported. + + Args: + content: The content to respond with. If this is a string, it will be passed to + :func:`parse_formatted` with the markdown and allow_html flags. + Otherwise, the content is used as-is + event_type: The type of event to send. + markdown: When content is a string, should it be parsed as markdown? + allow_html: When content is a string, should it allow raw HTML? + in_thread: Should the response be sent in a thread with this event? + By default (``None``), the response will be in a thread if this event is in a + thread. If set to ``False``, the response will never be in a thread. If set to + ``True``, the response will always be in a thread, creating one with this event as + the root if necessary. + extra_content: Extra content to add to the event. + + Returns: + The ID of the response event. + """ + return self.respond( + content, + event_type, + markdown=markdown, + reply=True, + in_thread=in_thread, + allow_html=allow_html, + extra_content=extra_content, + ) + + def mark_read(self) -> Awaitable[None]: + """ + Mark this event as read. + """ + return self.client.send_receipt(self.room_id, self.event_id, "m.read") + + def react(self, key: str) -> Awaitable[EventID]: + """ + React to this event with the given key. + + Args: + key: The key to react with. Often an unicode emoji. + + Returns: + The ID of the reaction event. + + Examples: + >>> evt: MaubotMessageEvent + >>> evt.react("🐈️") + """ + return self.client.react(self.room_id, self.event_id, key) + + def redact(self, reason: str | None = None) -> Awaitable[EventID]: + """ + Redact this event. + + Args: + reason: Optionally, the reason for redacting the event. + + Returns: + The ID of the redaction event. + """ + return self.client.redact(self.room_id, self.event_id, reason=reason) + + def edit( + self, + content: str | MessageEventContent, + event_type: EventType = EventType.ROOM_MESSAGE, + markdown: bool = True, + allow_html: bool = False, + ) -> Awaitable[EventID]: + """ + Edit this event. Note that other clients will only render the edit if it was sent by the + same user who's doing the editing. + + Args: + content: The new content for the event. If this is a string, it will be passed to + :func:`parse_formatted` with the markdown and allow_html flags. + Otherwise, the content is used as-is. + event_type: The type of event to edit into. + markdown: When content is a string, should it be parsed as markdown? + allow_html: When content is a string, should it allow raw HTML? + + Returns: + The ID of the edit event. + """ + return self.respond( + content, event_type, markdown=markdown, edits=self, allow_html=allow_html + ) + + +class MaubotMatrixClient(MatrixClient): + disable_replies: bool + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.disable_replies = False + + async def send_markdown( + self, + room_id: RoomID, + markdown: str, + *, + allow_html: bool = False, + render_markdown: bool = True, + msgtype: MessageType = MessageType.TEXT, + edits: EventID | MessageEvent | None = None, + relates_to: RelatesTo | None = None, + extra_content: dict[str, Any] = None, + **kwargs, + ) -> EventID: + content = TextMessageEventContent(msgtype=msgtype, format=Format.HTML) + content.body, content.formatted_body = await parse_formatted( + markdown, + allow_html=allow_html, + render_markdown=render_markdown, + ) + if relates_to: + if edits: + raise ValueError("Can't use edits and relates_to at the same time.") + content.relates_to = relates_to + elif edits: + content.set_edit(edits) + if extra_content: + for k, v in extra_content.items(): + content[k] = v + return await self.send_message(room_id, content, **kwargs) + + def dispatch_event(self, event: Event, source: SyncStream) -> list[asyncio.Task]: + if isinstance(event, MessageEvent) and not isinstance(event, MaubotMessageEvent): + event = MaubotMessageEvent(event, self) + elif source != SyncStream.INTERNAL: + event.client = self + return super().dispatch_event(event, source) + + async def get_event(self, room_id: RoomID, event_id: EventID) -> Event: + evt = await super().get_event(room_id, event_id) + if isinstance(evt, EncryptedEvent) and self.crypto: + try: + self.crypto_log.trace(f"get_event: Decrypting {evt.event_id} in {evt.room_id}...") + decrypted = await self.crypto.decrypt_megolm_event(evt) + except DecryptionError as e: + self.crypto_log.warning(f"get_event: Failed to decrypt {evt.event_id}: {e}") + return + self.crypto_log.trace(f"get_event: Decrypted {evt.event_id}: {decrypted}") + evt = decrypted + if isinstance(evt, MessageEvent): + evt.content.trim_reply_fallback() + return MaubotMessageEvent(evt, self) + else: + evt.client = self + return evt diff --git a/maubot-src/maubot/plugin_base.py b/maubot-src/maubot/plugin_base.py new file mode 100644 index 0000000..1be15e0 --- /dev/null +++ b/maubot-src/maubot/plugin_base.py @@ -0,0 +1,142 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import TYPE_CHECKING, Awaitable +from abc import ABC +from asyncio import AbstractEventLoop + +from aiohttp import ClientSession +from yarl import URL + +from mautrix.util.async_db import Database, UpgradeTable +from mautrix.util.config import BaseProxyConfig +from mautrix.util.logging import TraceLogger + +from .scheduler import BasicScheduler + +if TYPE_CHECKING: + from sqlalchemy.engine.base import Engine + + from .client import MaubotMatrixClient + from .loader import BasePluginLoader + from .plugin_server import PluginWebApp + + +class Plugin(ABC): + client: MaubotMatrixClient + http: ClientSession + id: str + log: TraceLogger + loop: AbstractEventLoop + loader: BasePluginLoader + sched: BasicScheduler + config: BaseProxyConfig | None + database: Engine | Database | None + webapp: PluginWebApp | None + webapp_url: URL | None + + def __init__( + self, + client: MaubotMatrixClient, + loop: AbstractEventLoop, + http: ClientSession, + instance_id: str, + log: TraceLogger, + config: BaseProxyConfig | None, + database: Engine | Database | None, + webapp: PluginWebApp | None, + webapp_url: str | None, + loader: BasePluginLoader, + ) -> None: + self.sched = BasicScheduler(log=log.getChild("scheduler")) + self.client = client + self.loop = loop + self.http = http + self.id = instance_id + self.log = log + self.config = config + self.database = database + self.webapp = webapp + self.webapp_url = URL(webapp_url) if webapp_url else None + self.loader = loader + self._handlers_at_startup = [] + + def register_handler_class(self, obj) -> None: + warned_webapp = False + for key in dir(obj): + val = getattr(obj, key) + try: + if val.__mb_event_handler__: + for event_type in val.__mb_event_types__: + self._handlers_at_startup.append((val, event_type)) + self.client.add_event_handler(event_type, val) + except AttributeError: + pass + try: + web_handlers = val.__mb_web_handler__ + except AttributeError: + pass + else: + if len(web_handlers) > 0 and self.webapp is None: + if not warned_webapp: + self.log.warning( + f"{type(obj).__name__} has web handlers, but the webapp" + " feature isn't enabled in the plugin's maubot.yaml" + ) + warned_webapp = True + continue + for method, path, kwargs in web_handlers: + self.webapp.add_route(method=method, path=path, handler=val, **kwargs) + + async def pre_start(self) -> None: + pass + + async def internal_start(self) -> None: + await self.pre_start() + self.register_handler_class(self) + await self.start() + + async def start(self) -> None: + pass + + async def pre_stop(self) -> None: + pass + + async def internal_stop(self) -> None: + await self.pre_stop() + for func, event_type in self._handlers_at_startup: + self.client.remove_event_handler(event_type, func) + if self.webapp is not None: + self.webapp.clear() + self.sched.stop() + await self.stop() + + async def stop(self) -> None: + pass + + @classmethod + def get_config_class(cls) -> type[BaseProxyConfig] | None: + return None + + @classmethod + def get_db_upgrade_table(cls) -> UpgradeTable | None: + return None + + def on_external_config_update(self) -> Awaitable[None] | None: + if self.config: + self.config.load_and_update() + return None diff --git a/maubot-src/maubot/plugin_server.py b/maubot-src/maubot/plugin_server.py new file mode 100644 index 0000000..e5c246c --- /dev/null +++ b/maubot-src/maubot/plugin_server.py @@ -0,0 +1,90 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import Awaitable, Callable +from functools import partial + +from aiohttp import hdrs, web +from yarl import URL + +Handler = Callable[[web.Request], Awaitable[web.Response]] +Middleware = Callable[[web.Request, Handler], Awaitable[web.Response]] + + +class PluginWebApp(web.UrlDispatcher): + def __init__(self): + super().__init__() + self._middleware: list[Middleware] = [] + + def add_middleware(self, middleware: Middleware) -> None: + self._middleware.append(middleware) + + def remove_middleware(self, middleware: Middleware) -> None: + self._middleware.remove(middleware) + + def clear(self) -> None: + self._resources = [] + self._named_resources = {} + self._middleware = [] + self._resource_index = {} + self._matched_sub_app_resources = [] + + async def handle(self, request: web.Request) -> web.StreamResponse: + match_info = await self.resolve(request) + match_info.freeze() + resp = None + request._match_info = match_info + expect = request.headers.get(hdrs.EXPECT) + if expect: + resp = await match_info.expect_handler(request) + await request.writer.drain() + if resp is None: + handler = match_info.handler + for middleware in self._middleware: + handler = partial(middleware, handler=handler) + resp = await handler(request) + return resp + + +class PrefixResource(web.Resource): + def __init__(self, prefix, *, name=None): + assert not prefix or prefix.startswith("/"), prefix + assert prefix in ("", "/") or not prefix.endswith("/"), prefix + super().__init__(name=name) + self._prefix = URL.build(path=prefix).raw_path + + @property + def canonical(self): + return self._prefix + + def get_info(self): + return {"path": self._prefix} + + def url_for(self): + return URL.build(path=self._prefix, encoded=True) + + def add_prefix(self, prefix): + assert prefix.startswith("/") + assert not prefix.endswith("/") + assert len(prefix) > 1 + self._prefix = prefix + self._prefix + + def _match(self, path: str) -> dict: + return {} if self.raw_match(path) else None + + def raw_match(self, path: str) -> bool: + return path and path.startswith(self._prefix) diff --git a/maubot-src/maubot/py.typed b/maubot-src/maubot/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/maubot-src/maubot/scheduler.py b/maubot-src/maubot/scheduler.py new file mode 100644 index 0000000..0cb39ed --- /dev/null +++ b/maubot-src/maubot/scheduler.py @@ -0,0 +1,159 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2024 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import Awaitable, Callable +import asyncio +import logging + + +class BasicScheduler: + background_loop: asyncio.Task | None + tasks: set[asyncio.Task] + log: logging.Logger + + def __init__(self, log: logging.Logger) -> None: + self.log = log + self.tasks = set() + + def _find_caller(self) -> str: + try: + file_name, line_number, function_name, _ = self.log.findCaller() + return f"{function_name} at {file_name}:{line_number}" + except ValueError: + return "unknown function" + + def run_periodically( + self, + period: float | int, + func: Callable[[], Awaitable], + run_task_in_background: bool = False, + catch_errors: bool = True, + ) -> asyncio.Task: + """ + Run a function periodically in the background. + + Args: + period: The period in seconds between each call to the function. + func: The function to run. No parameters will be provided, + use :meth:`functools.partial` if you need to pass parameters. + run_task_in_background: If ``True``, the function will be run in a background task. + If ``False`` (the default), the loop will wait for the task to return before + sleeping for the next period. + catch_errors: Whether the scheduler should catch and log any errors. + If ``False``, errors will be raised, and the caller must await the returned task + to find errors. This parameter has no effect if ``run_task_in_background`` + is ``True``. + + Returns: + The asyncio task object representing the background loop. + """ + task = asyncio.create_task( + self._call_periodically( + period, + func, + caller=self._find_caller(), + catch_errors=catch_errors, + run_task_in_background=run_task_in_background, + ) + ) + self._register_task(task) + return task + + def run_later( + self, delay: float | int, coro: Awaitable, catch_errors: bool = True + ) -> asyncio.Task: + """ + Run a coroutine after a delay. + + Examples: + >>> self.sched.run_later(5, self.async_task(meow=True)) + + Args: + delay: The delay in seconds to await the coroutine after. + coro: The coroutine to await. + catch_errors: Whether the scheduler should catch and log any errors. + If ``False``, errors will be raised, and the caller must await the returned task + to find errors. + + Returns: + The asyncio task object representing the scheduled task. + """ + task = asyncio.create_task( + self._call_with_delay( + delay, coro, caller=self._find_caller(), catch_errors=catch_errors + ) + ) + self._register_task(task) + return task + + def _register_task(self, task: asyncio.Task) -> None: + self.tasks.add(task) + task.add_done_callback(self.tasks.discard) + + async def _call_periodically( + self, + period: float | int, + func: Callable[[], Awaitable], + caller: str, + catch_errors: bool, + run_task_in_background: bool, + ) -> None: + while True: + try: + await asyncio.sleep(period) + if run_task_in_background: + self._register_task( + asyncio.create_task(self._call_periodically_background(func(), caller)) + ) + else: + await func() + except asyncio.CancelledError: + raise + except Exception: + if catch_errors: + self.log.exception(f"Uncaught error in background loop (created in {caller})") + else: + raise + + async def _call_periodically_background(self, coro: Awaitable, caller: str) -> None: + try: + await coro + except asyncio.CancelledError: + raise + except Exception: + self.log.exception(f"Uncaught error in background loop subtask (created in {caller})") + + async def _call_with_delay( + self, delay: float | int, coro: Awaitable, caller: str, catch_errors: bool + ) -> None: + try: + await asyncio.sleep(delay) + await coro + except asyncio.CancelledError: + raise + except Exception: + if catch_errors: + self.log.exception(f"Uncaught error in scheduled task (created in {caller})") + else: + raise + + def stop(self) -> None: + """ + Stop all scheduled tasks and background loops. + """ + for task in self.tasks: + task.cancel(msg="Scheduler stopped") diff --git a/maubot-src/maubot/server.py b/maubot-src/maubot/server.py new file mode 100644 index 0000000..dd1101e --- /dev/null +++ b/maubot-src/maubot/server.py @@ -0,0 +1,182 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import Callable +import asyncio +import json +import logging + +from aiohttp import hdrs, web +from aiohttp.abc import AbstractAccessLogger +from yarl import URL +import pkg_resources + +from mautrix.api import Method, PathBuilder + +from .__meta__ import __version__ +from .config import Config +from .plugin_server import PluginWebApp, PrefixResource + + +class AccessLogger(AbstractAccessLogger): + def log(self, request: web.Request, response: web.Response, time: int): + self.logger.info( + f'{request.remote} "{request.method} {request.path} ' + f"{response.status} {response.body_length} " + f'in {round(time, 4)}s"' + ) + + +class MaubotServer: + log: logging.Logger = logging.getLogger("maubot.server") + plugin_routes: dict[str, PluginWebApp] + + def __init__( + self, management_api: web.Application, config: Config, loop: asyncio.AbstractEventLoop + ) -> None: + self.loop = loop or asyncio.get_event_loop() + self.app = web.Application(loop=self.loop, client_max_size=100 * 1024 * 1024) + self.config = config + + self.setup_appservice() + self.app.add_subapp("/_matrix/maubot/v1", management_api) + self.setup_instance_subapps() + self.setup_management_ui() + + self.runner = web.AppRunner(self.app, access_log_class=AccessLogger) + + async def handle_plugin_path(self, request: web.Request) -> web.StreamResponse: + for path, app in self.plugin_routes.items(): + if request.path.startswith(path): + request = request.clone( + rel_url=request.rel_url.with_path( + request.rel_url.path[len(path) - 1 :] + ).with_query(request.query_string) + ) + return await app.handle(request) + return web.Response(status=404) + + def get_instance_subapp(self, instance_id: str) -> tuple[PluginWebApp, str]: + subpath = self.config["server.plugin_base_path"] + instance_id + "/" + url = self.config["server.public_url"] + subpath + try: + return self.plugin_routes[subpath], url + except KeyError: + app = PluginWebApp() + self.plugin_routes[subpath] = app + return app, url + + def remove_instance_webapp(self, instance_id: str) -> None: + try: + subpath = self.config["server.plugin_base_path"] + instance_id + "/" + self.plugin_routes.pop(subpath).clear() + except KeyError: + return + + def setup_instance_subapps(self) -> None: + self.plugin_routes = {} + resource = PrefixResource(self.config["server.plugin_base_path"].rstrip("/")) + resource.add_route(hdrs.METH_ANY, self.handle_plugin_path) + self.app.router.register_resource(resource) + + def setup_appservice(self) -> None: + as_path = PathBuilder("/_matrix/appservice/v1") + self.add_route(Method.PUT, as_path.transactions, self.handle_transaction) + + def setup_management_ui(self) -> None: + ui_base = self.config["server.ui_base_path"] + if ui_base == "/": + ui_base = "" + directory = self.config[ + "server.override_resource_path" + ] or pkg_resources.resource_filename("maubot", "management/frontend/build") + self.app.router.add_static(f"{ui_base}/static", f"{directory}/static") + self.setup_static_root_files(directory, ui_base) + + with open(f"{directory}/index.html", "r") as file: + index_html = file.read() + + @web.middleware + async def frontend_404_middleware(request: web.Request, handler) -> web.Response: + if hasattr(handler, "__self__") and isinstance(handler.__self__, web.StaticResource): + try: + return await handler(request) + except web.HTTPNotFound: + return web.Response(body=index_html, content_type="text/html") + return await handler(request) + + async def ui_base_redirect(_: web.Request) -> web.Response: + raise web.HTTPFound(f"{ui_base}/") + + self.app.middlewares.append(frontend_404_middleware) + self.app.router.add_get( + f"{ui_base}/", lambda _: web.Response(body=index_html, content_type="text/html") + ) + self.app.router.add_get(ui_base, ui_base_redirect) + + @staticmethod + def _static_data(data: bytes, mime: str) -> Callable[[web.Request], web.Response]: + def fn(_: web.Request) -> web.Response: + return web.Response(body=data, content_type=mime) + + return fn + + def setup_static_root_files(self, directory: str, ui_base: str) -> None: + files = { + "asset-manifest.json": "application/json", + "manifest.json": "application/json", + "favicon.png": "image/png", + } + for file, mime in files.items(): + with open(f"{directory}/{file}", "rb") as stream: + data = stream.read() + self.app.router.add_get(f"{ui_base}/{file}", self._static_data(data, mime)) + + public_url = self.config["server.public_url"] + public_url_path = "" + if public_url: + public_url_path = URL(public_url).path.rstrip("/") + + api_path = f"{public_url_path}/_matrix/maubot/v1" + + path_prefix_response_body = json.dumps({"api_path": api_path.rstrip("/")}) + self.app.router.add_get( + f"{ui_base}/paths.json", + lambda _: web.Response( + body=path_prefix_response_body, content_type="application/json" + ), + ) + + def add_route(self, method: Method, path: PathBuilder, handler) -> None: + self.app.router.add_route(method.value, str(path), handler) + + async def start(self) -> None: + await self.runner.setup() + site = web.TCPSite(self.runner, self.config["server.hostname"], self.config["server.port"]) + await site.start() + self.log.info(f"Listening on {site.name}") + + async def stop(self) -> None: + await self.runner.shutdown() + await self.runner.cleanup() + + @staticmethod + async def version(_: web.Request) -> web.Response: + return web.json_response({"version": __version__}) + + async def handle_transaction(self, request: web.Request) -> web.Response: + return web.Response(status=501) diff --git a/maubot-src/maubot/standalone/Dockerfile b/maubot-src/maubot/standalone/Dockerfile new file mode 100644 index 0000000..54623f2 --- /dev/null +++ b/maubot-src/maubot/standalone/Dockerfile @@ -0,0 +1,32 @@ +FROM docker.io/alpine:3.21 + +RUN apk add --no-cache \ + python3 py3-pip py3-setuptools py3-wheel \ + py3-aiohttp \ + py3-attrs \ + py3-bcrypt \ + py3-cffi \ + ca-certificates \ + su-exec \ + py3-psycopg2 \ + py3-ruamel.yaml \ + py3-jinja2 \ + py3-packaging \ + py3-markdown \ + py3-cffi \ + py3-olm \ + py3-pycryptodome \ + py3-unpaddedbase64 + +COPY requirements.txt /opt/maubot/requirements.txt +COPY optional-requirements.txt /opt/maubot/optional-requirements.txt +RUN cd /opt/maubot \ + && apk add --no-cache --virtual .build-deps \ + python3-dev \ + libffi-dev \ + build-base \ + && pip3 install --break-system-packages -r requirements.txt -r optional-requirements.txt \ + && apk del .build-deps + +COPY . /opt/maubot +RUN cd /opt/maubot && pip3 install --break-system-packages . diff --git a/maubot-src/maubot/standalone/__init__.py b/maubot-src/maubot/standalone/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/maubot-src/maubot/standalone/__main__.py b/maubot-src/maubot/standalone/__main__.py new file mode 100644 index 0000000..c320af4 --- /dev/null +++ b/maubot-src/maubot/standalone/__main__.py @@ -0,0 +1,424 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import cast +import argparse +import asyncio +import copy +import importlib +import logging.config +import os.path +import signal +import sys + +from aiohttp import ClientSession, hdrs, web +from ruamel.yaml import YAML +from ruamel.yaml.comments import CommentedMap +from yarl import URL + +from mautrix.appservice import AppServiceServerMixin +from mautrix.client import SyncStream +from mautrix.types import ( + BaseMessageEventContentFuncs, + Event, + EventType, + Filter, + Membership, + RoomEventFilter, + RoomFilter, + StrippedStateEvent, +) +from mautrix.util.async_db import Database, Scheme +from mautrix.util.config import BaseMissingError, RecursiveDict +from mautrix.util.logging import TraceLogger + +from ..__meta__ import __version__ +from ..loader import DatabaseType, PluginMeta +from ..matrix import MaubotMatrixClient +from ..plugin_base import Plugin +from ..plugin_server import PluginWebApp, PrefixResource +from ..server import AccessLogger +from .config import Config +from .database import NextBatch, upgrade_table +from .loader import FileSystemLoader + +crypto_import_error = None + +try: + from mautrix.crypto import OlmMachine, PgCryptoStateStore, PgCryptoStore +except ImportError as err: + crypto_import_error = err + OlmMachine = PgCryptoStateStore = PgCryptoStore = None + +parser = argparse.ArgumentParser( + description="A plugin-based Matrix bot system -- standalone mode.", + prog="python -m maubot.standalone", +) +parser.add_argument( + "-c", + "--config", + type=str, + default="config.yaml", + metavar="", + help="the path to your config file", +) +parser.add_argument( + "-b", + "--base-config", + type=str, + default="pkg://maubot.standalone/example-config.yaml", + metavar="", + help="the path to the example config (for automatic config updates)", +) +parser.add_argument( + "-m", + "--meta", + type=str, + default="maubot.yaml", + metavar="", + help="the path to your plugin metadata file", +) +args = parser.parse_args() + +config = Config(args.config, args.base_config) +config.load() +try: + config.update() +except BaseMissingError: + print("No example config found, not updating config") +except Exception as e: + print("Failed to update config:", e) + +logging.config.dictConfig(copy.deepcopy(config["logging"])) + +log = logging.getLogger("maubot.init") + +log.debug(f"Loading plugin metadata from {args.meta}") +yaml = YAML() +with open(args.meta, "r") as meta_file: + meta: PluginMeta = PluginMeta.deserialize(yaml.load(meta_file.read())) + +if "/" in meta.main_class: + module, main_class = meta.main_class.split("/", 1) +else: + module = meta.modules[-1] + main_class = meta.main_class + +if args.meta != "maubot.yaml" and os.path.dirname(args.meta) != "": + sys.path.append(os.path.dirname(args.meta)) +bot_module = importlib.import_module(module) +plugin: type[Plugin] = getattr(bot_module, main_class) +loader = FileSystemLoader(os.path.dirname(args.meta), meta) + +log.info(f"Initializing standalone {meta.id} v{meta.version} on maubot {__version__}") + +db = Database.create( + config["database"], + db_args=config.get("database_opts", {}), + ignore_foreign_tables=True, + log=logging.getLogger("maubot.db.standalone.upgrade"), + upgrade_table=upgrade_table, +) + +user_id = config["user.credentials.id"] +device_id = config["user.credentials.device_id"] +homeserver = config["user.credentials.homeserver"] +access_token = config["user.credentials.access_token"] +appservice_listener = config["user.appservice"] + +crypto_store = state_store = None +if device_id and not OlmMachine: + log.warning( + "device_id set in config, but encryption dependencies not installed", + exc_info=crypto_import_error, + ) +elif device_id: + crypto_store = PgCryptoStore(account_id=user_id, pickle_key="mau.crypto", db=db) + state_store = PgCryptoStateStore(db) + +bot_config = None +if not meta.config and "base-config.yaml" in meta.extra_files: + log.warning( + "base-config.yaml in extra files, but config is not set to true. " + "Assuming legacy plugin and loading config." + ) + meta.config = True +if meta.config: + log.debug("Loading config") + config_class = plugin.get_config_class() + + def load() -> CommentedMap: + return config["plugin_config"] + + def load_base() -> RecursiveDict[CommentedMap]: + return RecursiveDict(config.load_base()["plugin_config"], CommentedMap) + + def save(data: RecursiveDict[CommentedMap]) -> None: + config["plugin_config"] = data + config.save() + + try: + bot_config = config_class(load=load, load_base=load_base, save=save) + bot_config.load_and_update() + except Exception: + log.fatal("Failed to load plugin config", exc_info=True) + sys.exit(1) + +if meta.webapp: + web_app = web.Application() + web_runner = web.AppRunner(web_app, access_log_class=AccessLogger) + web_base_path = config["server.base_path"].rstrip("/") + public_url = str(URL(config["server.public_url"]) / web_base_path.lstrip("/")).rstrip("/") + plugin_webapp = PluginWebApp() + + async def _handle_plugin_request(req: web.Request) -> web.StreamResponse: + if req.path.startswith(web_base_path): + path_override = req.rel_url.path[len(web_base_path) :] + url_override = req.rel_url.with_path(path_override).with_query(req.query_string) + req = req.clone(rel_url=url_override) + return await plugin_webapp.handle(req) + return web.Response(status=404) + + resource = PrefixResource(web_base_path) + resource.add_route(hdrs.METH_ANY, _handle_plugin_request) + web_app.router.register_resource(resource) +elif appservice_listener: + web_app = web.Application() + web_runner = web.AppRunner(web_app, access_log_class=AccessLogger) + public_url = plugin_webapp = None +else: + web_app = web_runner = public_url = plugin_webapp = None + +loop = asyncio.get_event_loop() + +client: MaubotMatrixClient | None = None +bot: Plugin | None = None +appservice: AppServiceServerMixin | None = None + + +if appservice_listener: + assert web_app is not None, "web_app is always set when appservice_listener is set" + appservice = AppServiceServerMixin( + ephemeral_events=True, + encryption_events=True, + log=logging.getLogger("maubot.appservice"), + hs_token=config["user.hs_token"], + ) + appservice.register_routes(web_app) + + @appservice.matrix_event_handler + async def handle_appservice_event(evt: Event) -> None: + if isinstance(evt.content, BaseMessageEventContentFuncs): + evt.content.trim_reply_fallback() + fake_sync_stream = SyncStream.JOINED_ROOM + if evt.type.is_ephemeral: + fake_sync_stream |= SyncStream.EPHEMERAL + else: + fake_sync_stream |= SyncStream.TIMELINE + setattr(evt, "source", fake_sync_stream) + tasks = client.dispatch_manual_event(evt.type, evt, include_global_handlers=True) + await asyncio.gather(*tasks) + + +async def main(): + http_client = ClientSession(loop=loop) + + global client, bot + + await db.start() + nb = await NextBatch(db, user_id).load() + + client_log = logging.getLogger("maubot.client").getChild(user_id) + client = MaubotMatrixClient( + mxid=user_id, + base_url=homeserver, + token=access_token, + client_session=http_client, + loop=loop, + log=client_log, + sync_store=nb, + state_store=state_store, + device_id=device_id, + ) + if appservice: + client.api.as_user_id = user_id + client.ignore_first_sync = config["user.ignore_first_sync"] + client.ignore_initial_sync = config["user.ignore_initial_sync"] + if crypto_store: + await crypto_store.upgrade_table.upgrade(db) + await state_store.upgrade_table.upgrade(db) + await crypto_store.open() + + client.crypto = OlmMachine(client, crypto_store, state_store) + if appservice: + appservice.otk_handler = client.crypto.handle_as_otk_counts + appservice.device_list_handler = client.crypto.handle_as_device_lists + appservice.to_device_handler = client.crypto.handle_as_to_device_event + client.api.as_device_id = device_id + crypto_device_id = await crypto_store.get_device_id() + if crypto_device_id and crypto_device_id != device_id: + log.fatal( + "Mismatching device ID in crypto store and config " + f"(store: {crypto_device_id}, config: {device_id})" + ) + sys.exit(10) + await client.crypto.load() + if not crypto_device_id: + await crypto_store.put_device_id(device_id) + log.debug("Enabled encryption support") + + if web_runner: + await web_runner.setup() + site = web.TCPSite(web_runner, config["server.hostname"], config["server.port"]) + await site.start() + log.info(f"Web server listening on {site.name}") + + while True: + try: + whoami = await client.whoami() + except Exception as e: + log.error( + f"Failed to connect to homeserver: {type(e).__name__}: {e}" + " - retrying in 10 seconds..." + ) + await asyncio.sleep(10) + continue + if whoami.user_id != user_id: + log.fatal(f"User ID mismatch: configured {user_id}, but server said {whoami.user_id}") + sys.exit(11) + elif whoami.device_id and device_id and whoami.device_id != device_id: + log.fatal( + f"Device ID mismatch: configured {device_id}, " + f"but server said {whoami.device_id}" + ) + sys.exit(12) + log.debug(f"Confirmed connection as {whoami.user_id} / {whoami.device_id}") + break + + if config["user.sync"]: + if not nb.filter_id: + filter_id = await client.create_filter( + Filter(room=RoomFilter(timeline=RoomEventFilter(limit=50))) + ) + await nb.put_filter_id(filter_id) + _ = client.start(nb.filter_id) + elif appservice_listener and crypto_store and not client.crypto.account.shared: + await client.crypto.share_keys() + + if config["user.autojoin"]: + log.debug("Autojoin is enabled") + + @client.on(EventType.ROOM_MEMBER) + async def _handle_invite(evt: StrippedStateEvent) -> None: + if evt.state_key == client.mxid and evt.content.membership == Membership.INVITE: + await client.join_room(evt.room_id) + + displayname, avatar_url = config["user.displayname"], config["user.avatar_url"] + if avatar_url != "disable": + await client.set_avatar_url(avatar_url) + if displayname != "disable": + await client.set_displayname(displayname) + + plugin_log = cast(TraceLogger, logging.getLogger("maubot.instance.__main__")) + if meta.database: + if meta.database_type == DatabaseType.SQLALCHEMY: + import sqlalchemy as sql + + plugin_db = sql.create_engine(config["database"]) + if db.scheme == Scheme.SQLITE: + log.warning( + "Using SQLite with legacy plugins in standalone mode can cause database " + "locking issues. Switching to Postgres or updating the plugin to use the " + "new asyncpg/aiosqlite database interface is recommended." + ) + elif meta.database_type == DatabaseType.ASYNCPG: + plugin_db = db + upgrade_table = plugin.get_db_upgrade_table() + if upgrade_table: + await upgrade_table.upgrade(plugin_db) + else: + log.fatal(f"Unsupported database type {meta.database_type}") + sys.exit(13) + else: + plugin_db = None + bot = plugin( + client=client, + loop=loop, + http=http_client, + instance_id="__main__", + log=plugin_log, + config=bot_config, + database=plugin_db, + webapp=plugin_webapp, + webapp_url=public_url, + loader=loader, + ) + + await bot.internal_start() + + +async def stop(suppress_stop_error: bool = False) -> None: + if client: + client.stop() + if bot: + try: + await bot.internal_stop() + except Exception: + if not suppress_stop_error: + log.exception("Error stopping bot") + if web_runner and web_runner.server: + try: + await web_runner.shutdown() + await web_runner.cleanup() + except RuntimeError: + if not suppress_stop_error: + await db.stop() + raise + await db.stop() + + +signal.signal(signal.SIGINT, signal.default_int_handler) +signal.signal(signal.SIGTERM, signal.default_int_handler) + + +try: + log.info("Starting plugin") + loop.run_until_complete(main()) +except SystemExit: + loop.run_until_complete(stop(suppress_stop_error=True)) + loop.close() + raise +except (Exception, KeyboardInterrupt) as e: + if isinstance(e, KeyboardInterrupt): + log.info("Startup interrupted, stopping") + else: + log.fatal("Failed to start plugin", exc_info=True) + loop.run_until_complete(stop(suppress_stop_error=True)) + loop.close() + sys.exit(1) + +try: + log.info("Startup completed, running forever") + loop.run_forever() +except KeyboardInterrupt: + log.info("Interrupt received, stopping") + loop.run_until_complete(stop()) + loop.close() + sys.exit(0) +except Exception: + log.fatal("Fatal error in bot", exc_info=True) + sys.exit(1) diff --git a/maubot-src/maubot/standalone/config.py b/maubot-src/maubot/standalone/config.py new file mode 100644 index 0000000..f2c90a0 --- /dev/null +++ b/maubot-src/maubot/standalone/config.py @@ -0,0 +1,52 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from typing import Any +import os + +from mautrix.util.config import BaseFileConfig, ConfigUpdateHelper + + +class Config(BaseFileConfig): + def __getitem__(self, key: str) -> Any: + try: + return os.environ[f"MAUBOT_{key.replace('.', '_').upper()}"] + except KeyError: + return super().__getitem__(key) + + def do_update(self, helper: ConfigUpdateHelper) -> None: + copy, _, base = helper + copy("user.credentials.id") + copy("user.credentials.homeserver") + copy("user.credentials.access_token") + copy("user.credentials.device_id") + copy("user.sync") + copy("user.appservice") + copy("user.hs_token") + copy("user.autojoin") + copy("user.displayname") + copy("user.avatar_url") + copy("user.ignore_initial_sync") + copy("user.ignore_first_sync") + if "server" in base: + copy("server.hostname") + copy("server.port") + copy("server.base_path") + copy("server.public_url") + copy("database") + copy("database_opts") + if "plugin_config" in base: + copy("plugin_config") + copy("logging") diff --git a/maubot-src/maubot/standalone/database.py b/maubot-src/maubot/standalone/database.py new file mode 100644 index 0000000..f09906d --- /dev/null +++ b/maubot-src/maubot/standalone/database.py @@ -0,0 +1,73 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +import logging + +from attr import dataclass + +from mautrix.client import SyncStore +from mautrix.types import FilterID, SyncToken, UserID +from mautrix.util.async_db import Connection, Database, UpgradeTable + +upgrade_table = UpgradeTable( + version_table_name="standalone_version", log=logging.getLogger("maubot.db") +) + + +@upgrade_table.register(description="Initial revision") +async def upgrade_v1(conn: Connection) -> None: + await conn.execute( + """CREATE TABLE IF NOT EXISTS standalone_next_batch ( + user_id TEXT PRIMARY KEY, + next_batch TEXT, + filter_id TEXT + )""" + ) + + +find_q = "SELECT next_batch, filter_id FROM standalone_next_batch WHERE user_id=$1" +insert_q = "INSERT INTO standalone_next_batch (user_id, next_batch, filter_id) VALUES ($1, $2, $3)" +update_nb_q = "UPDATE standalone_next_batch SET next_batch=$1 WHERE user_id=$2" +update_filter_q = "UPDATE standalone_next_batch SET filter_id=$1 WHERE user_id=$2" + + +@dataclass +class NextBatch(SyncStore): + db: Database + user_id: UserID + next_batch: SyncToken = "" + filter_id: FilterID = "" + + async def load(self) -> NextBatch: + row = await self.db.fetchrow(find_q, self.user_id) + if row is not None: + self.next_batch = row["next_batch"] + self.filter_id = row["filter_id"] + else: + await self.db.execute(insert_q, self.user_id, self.next_batch, self.filter_id) + return self + + async def put_filter_id(self, filter_id: FilterID) -> None: + self.filter_id = filter_id + await self.db.execute(update_filter_q, self.filter_id, self.user_id) + + async def put_next_batch(self, next_batch: SyncToken) -> None: + self.next_batch = next_batch + await self.db.execute(update_nb_q, self.next_batch, self.user_id) + + async def get_next_batch(self) -> SyncToken: + return self.next_batch diff --git a/maubot-src/maubot/standalone/example-config.yaml b/maubot-src/maubot/standalone/example-config.yaml new file mode 100644 index 0000000..8ee4e43 --- /dev/null +++ b/maubot-src/maubot/standalone/example-config.yaml @@ -0,0 +1,78 @@ +# Bot account details +user: + credentials: + id: "@bot:example.com" + homeserver: https://example.com + access_token: foo + # If you want to enable encryption, set the device ID corresponding to the access token here. + # When using an appservice, you should use appservice login manually to generate a device ID and access token. + device_id: null + # Enable /sync? This is not needed for purely unencrypted webhook-based bots, but is necessary in most other cases. + sync: true + # Receive appservice transactions? This will add a /_matrix/app/v1/transactions endpoint on + # the HTTP server configured below. The base_path will not be applied for the /transactions path. + appservice: false + # When appservice mode is enabled, the hs_token for the appservice. + hs_token: null + # Automatically accept invites? + autojoin: false + # The displayname and avatar URL to set for the bot on startup. + # Set to "disable" to not change the the current displayname/avatar. + displayname: Standalone Bot + avatar_url: mxc://maunium.net/AKwRzQkTbggfVZGEqexbYLIO + + # Should events from the initial sync be ignored? This should usually always be true. + ignore_initial_sync: true + # Should events from the first sync after starting be ignored? This can be set to false + # if you want the bot to handle messages that were sent while the bot was down. + ignore_first_sync: true + +# Web server settings. These will only take effect if the plugin requests it using `webapp: true` in the meta file, +# or if user -> appservice is set to true. +server: + # The IP and port to listen to. + hostname: 0.0.0.0 + port: 8080 + # The base path where the plugin's web resources will be served. Unlike the normal mode, + # the webserver is dedicated for a single bot in standalone mode, so the default path + # is just /. If you want to emulate normal mode, set this to /_matrix/maubot/plugin/something + base_path: / + # The public URL where the resources are available. The base path is automatically appended to this. + public_url: https://example.com + +# The database for the plugin. Used for plugin data, the sync token and e2ee data (if enabled). +# SQLite and Postgres are supported. +database: sqlite:bot.db + +# Additional arguments for asyncpg.create_pool() or sqlite3.connect() +# https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.pool.create_pool +# https://docs.python.org/3/library/sqlite3.html#sqlite3.connect +# For sqlite, min_size is used as the connection thread pool size and max_size is ignored. +database_opts: + min_size: 1 + max_size: 10 + +# Config for the plugin. Refer to the plugin's base-config.yaml to find what (if anything) to put here. +plugin_config: {} + +# Standard Python logging configuration +logging: + version: 1 + formatters: + colored: + (): maubot.lib.color_log.ColorFormatter + format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + handlers: + console: + class: logging.StreamHandler + formatter: colored + loggers: + maubot: + level: DEBUG + mau: + level: DEBUG + aiohttp: + level: INFO + root: + level: DEBUG + handlers: [console] diff --git a/maubot-src/maubot/standalone/loader.py b/maubot-src/maubot/standalone/loader.py new file mode 100644 index 0000000..3d5a907 --- /dev/null +++ b/maubot-src/maubot/standalone/loader.py @@ -0,0 +1,44 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +import os +import os.path + +from ..loader import BasePluginLoader, PluginMeta + + +class FileSystemLoader(BasePluginLoader): + def __init__(self, path: str, meta: PluginMeta) -> None: + self.path = path + self.meta = meta + + @property + def source(self) -> str: + return self.path + + def sync_read_file(self, path: str) -> bytes: + with open(os.path.join(self.path, path), "rb") as file: + return file.read() + + async def read_file(self, path: str) -> bytes: + return self.sync_read_file(path) + + def sync_list_files(self, directory: str) -> list[str]: + return os.listdir(os.path.join(self.path, directory)) + + async def list_files(self, directory: str) -> list[str]: + return self.sync_list_files(directory) diff --git a/maubot-src/maubot/testing/__init__.py b/maubot-src/maubot/testing/__init__.py new file mode 100644 index 0000000..1fcdfc0 --- /dev/null +++ b/maubot-src/maubot/testing/__init__.py @@ -0,0 +1,17 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2023 Aurélien Bompard +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from .bot import TestBot, make_message # noqa: F401 +from .fixtures import * # noqa: F401,F403 diff --git a/maubot-src/maubot/testing/bot.py b/maubot-src/maubot/testing/bot.py new file mode 100644 index 0000000..0519016 --- /dev/null +++ b/maubot-src/maubot/testing/bot.py @@ -0,0 +1,100 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2023 Aurélien Bompard +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import asyncio +import time + +from attr import dataclass + +from maubot.matrix import MaubotMatrixClient, MaubotMessageEvent +from mautrix.api import HTTPAPI +from mautrix.types import ( + EventContent, + EventType, + MessageEvent, + MessageType, + RoomID, + TextMessageEventContent, +) + + +@dataclass +class MatrixEvent: + room_id: RoomID + event_type: EventType + content: EventContent + kwargs: dict + + +class TestBot: + """A mocked bot used for testing purposes. + + Send messages to the mock Matrix server with the ``send()`` method. + Look into the ``responded`` list to get what server has replied. + """ + + def __init__(self, mxid="@botname:example.com", mxurl="http://matrix.example.com"): + api = HTTPAPI(base_url=mxurl) + self.client = MaubotMatrixClient(api=api) + self.responded = [] + self.client.mxid = mxid + self.client.send_message_event = self._mock_send_message_event + + async def _mock_send_message_event(self, room_id, event_type, content, txn_id=None, **kwargs): + self.responded.append( + MatrixEvent(room_id=room_id, event_type=event_type, content=content, kwargs=kwargs) + ) + + async def dispatch(self, event_type: EventType, event): + tasks = self.client.dispatch_manual_event(event_type, event, force_synchronous=True) + return await asyncio.gather(*tasks) + + async def send( + self, + content, + html=None, + room_id="testroom", + msg_type=MessageType.TEXT, + sender="@dummy:example.com", + timestamp=None, + ): + event = make_message( + content, + html=html, + room_id=room_id, + msg_type=msg_type, + sender=sender, + timestamp=timestamp, + ) + await self.dispatch(EventType.ROOM_MESSAGE, MaubotMessageEvent(event, self.client)) + + +def make_message( + content, + html=None, + room_id="testroom", + msg_type=MessageType.TEXT, + sender="@dummy:example.com", + timestamp=None, +): + """Make a Matrix message event.""" + return MessageEvent( + type=EventType.ROOM_MESSAGE, + room_id=room_id, + event_id="test", + sender=sender, + timestamp=timestamp or int(time.time() * 1000), + content=TextMessageEventContent(msgtype=msg_type, body=content, formatted_body=html), + ) diff --git a/maubot-src/maubot/testing/fixtures.py b/maubot-src/maubot/testing/fixtures.py new file mode 100644 index 0000000..e975782 --- /dev/null +++ b/maubot-src/maubot/testing/fixtures.py @@ -0,0 +1,135 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2023 Aurélien Bompard +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from pathlib import Path +import asyncio +import logging + +from ruamel.yaml import YAML +import aiohttp +import pytest +import pytest_asyncio + +from maubot import Plugin +from maubot.loader import PluginMeta +from maubot.standalone.loader import FileSystemLoader +from mautrix.util.async_db import Database +from mautrix.util.config import BaseProxyConfig, RecursiveDict +from mautrix.util.logging import TraceLogger + +from .bot import TestBot + + +@pytest_asyncio.fixture +async def maubot_test_bot(): + return TestBot() + + +@pytest.fixture +def maubot_upgrade_table(): + return None + + +@pytest.fixture +def maubot_plugin_path(): + return Path(".") + + +@pytest.fixture +def maubot_plugin_meta(maubot_plugin_path): + yaml = YAML() + with open(maubot_plugin_path.joinpath("maubot.yaml")) as fh: + plugin_meta = PluginMeta.deserialize(yaml.load(fh.read())) + return plugin_meta + + +@pytest_asyncio.fixture +async def maubot_plugin_db(tmp_path, maubot_plugin_meta, maubot_upgrade_table): + if not maubot_plugin_meta.get("database", False): + return + db_path = tmp_path.joinpath("maubot-tests.db").as_posix() + db = Database.create( + f"sqlite:{db_path}", + upgrade_table=maubot_upgrade_table, + log=logging.getLogger("db"), + ) + await db.start() + yield db + await db.stop() + + +@pytest.fixture +def maubot_plugin_class(): + return Plugin + + +@pytest.fixture +def maubot_plugin_config_class(): + return BaseProxyConfig + + +@pytest.fixture +def maubot_plugin_config_dict(): + return {} + + +@pytest.fixture +def maubot_plugin_config_overrides(): + return {} + + +@pytest.fixture +def maubot_plugin_config( + maubot_plugin_path, + maubot_plugin_config_class, + maubot_plugin_config_dict, + maubot_plugin_config_overrides, +): + yaml = YAML() + with open(maubot_plugin_path.joinpath("base-config.yaml")) as fh: + base_config = RecursiveDict(yaml.load(fh)) + maubot_plugin_config_dict.update(maubot_plugin_config_overrides) + return maubot_plugin_config_class( + load=lambda: maubot_plugin_config_dict, + load_base=lambda: base_config, + save=lambda c: None, + ) + + +@pytest_asyncio.fixture +async def maubot_plugin( + maubot_test_bot, + maubot_plugin_db, + maubot_plugin_class, + maubot_plugin_path, + maubot_plugin_config, + maubot_plugin_meta, +): + loader = FileSystemLoader(maubot_plugin_path, maubot_plugin_meta) + async with aiohttp.ClientSession() as http: + instance = maubot_plugin_class( + client=maubot_test_bot.client, + loop=asyncio.get_running_loop(), + http=http, + instance_id="tests", + log=TraceLogger("test"), + config=maubot_plugin_config, + database=maubot_plugin_db, + webapp=None, + webapp_url=None, + loader=loader, + ) + await instance.internal_start() + yield instance diff --git a/maubot-src/nginx.conf b/maubot-src/nginx.conf new file mode 100644 index 0000000..7765d7a --- /dev/null +++ b/maubot-src/nginx.conf @@ -0,0 +1,58 @@ +worker_processes auto; +pid /run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$request_time"'; + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + access_log /dev/stdout main; + error_log /dev/stderr info; + + upstream maubot_upstream { + server 127.0.0.1:3001; + } + + server { + listen 3000 default_server; + listen [::]:3000 default_server; + + client_max_body_size 64m; + + location = /healthz { + add_header Content-Type text/plain; + return 200 "OK"; + } + + location / { + proxy_pass http://maubot_upstream; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_buffering off; + } + } +} diff --git a/maubot-src/optional-requirements.txt b/maubot-src/optional-requirements.txt new file mode 100644 index 0000000..3676b0e --- /dev/null +++ b/maubot-src/optional-requirements.txt @@ -0,0 +1,15 @@ +# Format: #/name defines a new extras_require group called name +# Uncommented lines after the group definition insert things into that group. + +#/encryption +python-olm>=3,<4 +pycryptodome>=3,<4 +unpaddedbase64>=1,<3 +base58>=2,<3 + +#/testing +pytest +pytest-asyncio + +#/legacydb +SQLAlchemy>1,<1.4 diff --git a/maubot-src/pyproject.toml b/maubot-src/pyproject.toml new file mode 100644 index 0000000..6c2ca27 --- /dev/null +++ b/maubot-src/pyproject.toml @@ -0,0 +1,13 @@ +[tool.isort] +profile = "black" +force_to_top = "typing" +from_first = true +combine_as_imports = true +known_first_party = "mautrix" +line_length = 99 +skip = ["maubot/management/frontend"] + +[tool.black] +line-length = 99 +target-version = ["py310"] +force-exclude = "maubot/management/frontend" diff --git a/maubot-src/requirements.txt b/maubot-src/requirements.txt new file mode 100644 index 0000000..fd96666 --- /dev/null +++ b/maubot-src/requirements.txt @@ -0,0 +1,16 @@ +mautrix>=0.21.0b5,<0.22 +aiohttp>=3,<4 +yarl>=1,<2 +asyncpg>=0.20,<1 +aiosqlite>=0.16,<1 +commonmark>=0.9,<1 +ruamel.yaml>=0.15.35,<0.19 +attrs>=18.1.0 +bcrypt>=3,<5 +packaging>=10 + +click>=7,<9 +colorama>=0.4,<0.5 +questionary>=1,<3 +jinja2>=2,<4 +setuptools diff --git a/maubot-src/setup.py b/maubot-src/setup.py new file mode 100644 index 0000000..838196f --- /dev/null +++ b/maubot-src/setup.py @@ -0,0 +1,79 @@ +import setuptools +import os + +with open("requirements.txt") as reqs: + install_requires = reqs.read().splitlines() + +with open("optional-requirements.txt") as reqs: + extras_require = {} + current = [] + for line in reqs.read().splitlines(): + if line.startswith("#/"): + extras_require[line[2:]] = current = [] + elif not line or line.startswith("#"): + continue + else: + current.append(line) + +extras_require["all"] = list({dep for deps in extras_require.values() for dep in deps}) + +path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "maubot", "__meta__.py") +__version__ = "UNKNOWN" +with open(path) as f: + exec(f.read()) + +setuptools.setup( + name="maubot", + version=__version__, + url="https://github.com/maubot/maubot", + project_urls={ + "Changelog": "https://github.com/maubot/maubot/blob/master/CHANGELOG.md", + }, + + author="Tulir Asokan", + author_email="tulir@maunium.net", + + description="A plugin-based Matrix bot system.", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", + + packages=setuptools.find_packages(), + + install_requires=install_requires, + extras_require=extras_require, + python_requires="~=3.10", + + classifiers=[ + "Development Status :: 4 - Beta", + "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", + "Topic :: Communications :: Chat", + "Framework :: AsyncIO", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + ], + entry_points=""" + [console_scripts] + mbc=maubot.cli:app + [pytest11] + maubot=maubot.testing + """, + data_files=[ + (".", ["maubot/example-config.yaml"]), + ], + package_data={ + "maubot": [ + "example-config.yaml", + "management/frontend/build/*", + "management/frontend/build/static/css/*", + "management/frontend/build/static/js/*", + "management/frontend/build/static/media/*", + "py.typed", + ], + "maubot.cli": ["res/*"], + "maubot.standalone": ["example-config.yaml"], + }, +) diff --git a/maubot-src/start.sh b/maubot-src/start.sh new file mode 100755 index 0000000..9636c57 --- /dev/null +++ b/maubot-src/start.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_DIR="/app/code" +DATA_DIR="/app/data" +CONFIG_PATH="${DATA_DIR}/config.yaml" +DEFAULT_CONFIG="/tmp/data/config.yaml" +FRONTEND_DIR="${APP_DIR}/frontend" +ADMIN_FILE="${DATA_DIR}/.admin_password" +MAUBOT_INTERNAL_PORT="${MAUBOT_INTERNAL_PORT:-3001}" + +umask 0027 + +mkdir -p /run/nginx \ + "${DATA_DIR}" \ + "${DATA_DIR}/plugins" \ + "${DATA_DIR}/trash" \ + "${DATA_DIR}/dbs" \ + "${DATA_DIR}/logs" + +if [ ! -f "${CONFIG_PATH}" ]; then + cp "${DEFAULT_CONFIG}" "${CONFIG_PATH}" + echo "Generated initial Maubot configuration at ${CONFIG_PATH}" +fi + +if compgen -G "${DATA_DIR}/plugins/*.db" > /dev/null; then + mv "${DATA_DIR}"/plugins/*.db "${DATA_DIR}/dbs/" || true +fi + +chown -R cloudron:cloudron "${DATA_DIR}" + +export CONFIG_PATH DATA_DIR FRONTEND_DIR ADMIN_FILE +export MAUBOT_PORT="${MAUBOT_INTERNAL_PORT}" +export CLOUDRON_APP_ORIGIN="${CLOUDRON_APP_ORIGIN:-https://example.com}" +export CLOUDRON_POSTGRESQL_URL="${CLOUDRON_POSTGRESQL_URL:-}" +export MAUBOT_CRYPTO_DATABASE="${MAUBOT_CRYPTO_DATABASE:-default}" + +"${APP_DIR}/venv/bin/python3" <<'PY' +import os +import pathlib +import secrets +import string +from ruamel.yaml import YAML + +yaml = YAML() +yaml.preserve_quotes = True + +config_path = pathlib.Path(os.environ["CONFIG_PATH"]) +data_dir = pathlib.Path(os.environ["DATA_DIR"]) +frontend_dir = pathlib.Path(os.environ["FRONTEND_DIR"]) +admin_file = pathlib.Path(os.environ["ADMIN_FILE"]) +public_url = os.environ.get("CLOUDRON_APP_ORIGIN") or "https://example.com" +db_url = os.environ.get("CLOUDRON_POSTGRESQL_URL") +crypto_url = os.environ.get("MAUBOT_CRYPTO_DATABASE", "default") +maubot_port = int(os.environ["MAUBOT_PORT"]) + +with config_path.open() as handle: + config = yaml.load(handle) or {} + +config["database"] = db_url or f"sqlite:{data_dir / 'maubot.db'}" +config["crypto_database"] = "default" if crypto_url in ("", "default") else crypto_url + +plugin_dirs = config.setdefault("plugin_directories", {}) +plugin_dirs["upload"] = str(data_dir / "plugins") +plugin_dirs["load"] = [str(data_dir / "plugins")] +plugin_dirs["trash"] = str(data_dir / "trash") + +plugin_dbs = config.setdefault("plugin_databases", {}) +plugin_dbs["sqlite"] = str(data_dir / "dbs") +plugin_dbs["postgres"] = "default" if db_url else None +plugin_dbs.setdefault("postgres_max_conns_per_plugin", 3) +plugin_dbs.setdefault("postgres_opts", {}) + +server = config.setdefault("server", {}) +server["hostname"] = "127.0.0.1" +server["port"] = maubot_port +server["public_url"] = public_url.rstrip("/") +server.setdefault("ui_base_path", "/") +server.setdefault("plugin_base_path", "/_matrix/maubot/plugin/") +server["override_resource_path"] = str(frontend_dir) + +logging = config.setdefault("logging", {}) +handlers = logging.setdefault("handlers", {}) +file_handler = handlers.setdefault("file", {}) +file_handler["filename"] = str(data_dir / "logs" / "maubot.log") +file_handler.setdefault("class", "logging.handlers.RotatingFileHandler") +file_handler.setdefault("formatter", "normal") +file_handler.setdefault("maxBytes", 10485760) +file_handler.setdefault("backupCount", 10) + +admins = config.setdefault("admins", {}) +if admin_file.exists(): + admin_password = admin_file.read_text().strip() +else: + alphabet = string.ascii_letters + string.digits + admin_password = "".join(secrets.choice(alphabet) for _ in range(40)) + admin_file.write_text(admin_password) + admin_file.chmod(0o640) +admins["root"] = admin_password + +with config_path.open("w") as handle: + yaml.dump(config, handle) +PY + +chown cloudron:cloudron "${CONFIG_PATH}" "${ADMIN_FILE}" + +exec /usr/bin/supervisord -c /app/code/supervisord.conf diff --git a/maubot-src/supervisord.conf b/maubot-src/supervisord.conf new file mode 100644 index 0000000..58d7ccf --- /dev/null +++ b/maubot-src/supervisord.conf @@ -0,0 +1,22 @@ +[supervisord] +nodaemon=true +logfile=/dev/null + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" -c /app/code/nginx.conf +autorestart=true +priority=10 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:maubot] +command=/usr/sbin/gosu cloudron:cloudron /app/code/venv/bin/python3 -m maubot -c /app/data/config.yaml +directory=/app/code +autorestart=true +priority=20 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0

3LXWJV8K6|>Qa3(_9Z7Cq9o-HgWr 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 z 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 U000010096`0002@rV0Q606*uy=>Px# literal 0 HcmV?d00001 diff --git a/maubot-src/maubot/cli/util/__init__.py b/maubot-src/maubot/cli/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/maubot-src/maubot/cli/util/spdx.py b/maubot-src/maubot/cli/util/spdx.py new file mode 100644 index 0000000..69f58b7 --- /dev/null +++ b/maubot-src/maubot/cli/util/spdx.py @@ -0,0 +1,45 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +import json +import zipfile + +import pkg_resources + +spdx_list: dict[str, dict[str, str]] | None = None + + +def load() -> None: + global spdx_list + if spdx_list is not None: + return + with pkg_resources.resource_stream("maubot.cli", "res/spdx.json.zip") as disk_file: + with zipfile.ZipFile(disk_file) as zip_file: + with zip_file.open("spdx.json") as file: + spdx_list = json.load(file) + + +def get(id: str) -> dict[str, str]: + if not spdx_list: + load() + return spdx_list[id] + + +def valid(id: str) -> bool: + if not spdx_list: + load() + return id in spdx_list diff --git a/maubot-src/maubot/client.py b/maubot-src/maubot/client.py new file mode 100644 index 0000000..915b170 --- /dev/null +++ b/maubot-src/maubot/client.py @@ -0,0 +1,581 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, AsyncGenerator, Awaitable, Callable, cast +from collections import defaultdict +import asyncio +import logging + +from aiohttp import ClientSession + +from mautrix.api import HTTPAPI +from mautrix.client import InternalEventType +from mautrix.errors import MatrixInvalidToken +from mautrix.types import ( + ContentURI, + DeviceID, + EventFilter, + EventType, + Filter, + FilterID, + Membership, + PresenceState, + RoomEventFilter, + RoomFilter, + StateEvent, + StateFilter, + StrippedStateEvent, + SyncToken, + TrustState, + UserID, +) +from mautrix.util import background_task +from mautrix.util.async_getter_lock import async_getter_lock +from mautrix.util.logging import TraceLogger + +from .db import Client as DBClient +from .matrix import MaubotMatrixClient + +try: + from mautrix.crypto import OlmMachine, PgCryptoStore + + crypto_import_error = None +except ImportError as e: + OlmMachine = PgCryptoStore = None + crypto_import_error = e + +if TYPE_CHECKING: + from .__main__ import Maubot + from .instance import PluginInstance + + +class Client(DBClient): + maubot: "Maubot" = None + cache: dict[UserID, Client] = {} + _async_get_locks: dict[Any, asyncio.Lock] = defaultdict(lambda: asyncio.Lock()) + log: TraceLogger = logging.getLogger("maubot.client") + + http_client: ClientSession = None + + references: set[PluginInstance] + client: MaubotMatrixClient + crypto: OlmMachine | None + crypto_store: PgCryptoStore | None + started: bool + sync_ok: bool + + remote_displayname: str | None + remote_avatar_url: ContentURI | None + trust_state: TrustState | None + + def __init__( + self, + id: UserID, + homeserver: str, + access_token: str, + device_id: DeviceID, + enabled: bool = False, + next_batch: SyncToken = "", + filter_id: FilterID = "", + sync: bool = True, + autojoin: bool = True, + online: bool = True, + displayname: str = "disable", + avatar_url: str = "disable", + ) -> None: + super().__init__( + id=id, + homeserver=homeserver, + access_token=access_token, + device_id=device_id, + enabled=bool(enabled), + next_batch=next_batch, + filter_id=filter_id, + sync=bool(sync), + autojoin=bool(autojoin), + online=bool(online), + displayname=displayname, + avatar_url=avatar_url, + ) + self._postinited = False + + def __hash__(self) -> int: + return hash(self.id) + + @classmethod + def init_cls(cls, maubot: "Maubot") -> None: + cls.maubot = maubot + + def _make_client( + self, homeserver: str | None = None, token: str | None = None, device_id: str | None = None + ) -> MaubotMatrixClient: + return MaubotMatrixClient( + mxid=self.id, + base_url=homeserver or self.homeserver, + token=token or self.access_token, + client_session=self.http_client, + log=self.log, + crypto_log=self.log.getChild("crypto"), + loop=self.maubot.loop, + device_id=device_id or self.device_id, + sync_store=self, + state_store=self.maubot.state_store, + ) + + def postinit(self) -> None: + if self._postinited: + raise RuntimeError("postinit() called twice") + self._postinited = True + self.cache[self.id] = self + self.log = self.log.getChild(self.id) + self.http_client = ClientSession( + loop=self.maubot.loop, + headers={ + "User-Agent": HTTPAPI.default_ua, + }, + ) + self.references = set() + self.started = False + self.sync_ok = True + self.trust_state = None + self.remote_displayname = None + self.remote_avatar_url = None + self.client = self._make_client() + if self.enable_crypto: + self._prepare_crypto() + else: + self.crypto_store = None + self.crypto = None + self.client.ignore_initial_sync = True + self.client.ignore_first_sync = True + self.client.presence = PresenceState.ONLINE if self.online else PresenceState.OFFLINE + if self.autojoin: + self.client.add_event_handler(EventType.ROOM_MEMBER, self._handle_invite) + self.client.add_event_handler(EventType.ROOM_TOMBSTONE, self._handle_tombstone) + self.client.add_event_handler(InternalEventType.SYNC_ERRORED, self._set_sync_ok(False)) + self.client.add_event_handler(InternalEventType.SYNC_SUCCESSFUL, self._set_sync_ok(True)) + + def _set_sync_ok(self, ok: bool) -> Callable[[dict[str, Any]], Awaitable[None]]: + async def handler(data: dict[str, Any]) -> None: + self.sync_ok = ok + + return handler + + @property + def enable_crypto(self) -> bool: + if not self.device_id: + return False + elif not OlmMachine: + global crypto_import_error + self.log.warning( + "Client has device ID, but encryption dependencies not installed", + exc_info=crypto_import_error, + ) + # Clear the stack trace after it's logged once to avoid spamming logs + crypto_import_error = None + return False + elif not self.maubot.crypto_db: + self.log.warning("Client has device ID, but crypto database is not prepared") + return False + return True + + def _prepare_crypto(self) -> None: + self.crypto_store = PgCryptoStore( + account_id=self.id, pickle_key="mau.crypto", db=self.maubot.crypto_db + ) + self.crypto = OlmMachine( + self.client, + self.crypto_store, + self.maubot.state_store, + log=self.client.crypto_log, + ) + self.client.crypto = self.crypto + + def _remove_crypto_event_handlers(self) -> None: + if not self.crypto: + return + handlers = [ + (InternalEventType.DEVICE_OTK_COUNT, self.crypto.handle_otk_count), + (InternalEventType.DEVICE_LISTS, self.crypto.handle_device_lists), + (EventType.TO_DEVICE_ENCRYPTED, self.crypto.handle_to_device_event), + (EventType.ROOM_KEY_REQUEST, self.crypto.handle_room_key_request), + (EventType.ROOM_MEMBER, self.crypto.handle_member_event), + ] + for event_type, func in handlers: + self.client.remove_event_handler(event_type, func) + + async def start(self, try_n: int | None = 0) -> None: + try: + if try_n > 0: + await asyncio.sleep(try_n * 10) + await self._start(try_n) + except Exception: + self.log.exception("Failed to start") + + async def _start_crypto(self) -> None: + self.log.debug("Enabling end-to-end encryption support") + await self.crypto_store.open() + crypto_device_id = await self.crypto_store.get_device_id() + if crypto_device_id and crypto_device_id != self.device_id: + self.log.warning( + "Mismatching device ID in crypto store and main database, resetting encryption" + ) + await self.crypto_store.delete() + crypto_device_id = None + await self.crypto.load() + if not crypto_device_id: + await self.crypto_store.put_device_id(self.device_id) + if not self.crypto.account.shared: + await self.crypto.share_keys() + self.trust_state = await self.crypto.resolve_trust( + self.crypto.own_identity, + allow_fetch=False, + ) + + async def _start(self, try_n: int | None = 0) -> None: + if not self.enabled: + self.log.debug("Not starting disabled client") + return + elif self.started: + self.log.warning("Ignoring start() call to started client") + return + try: + await self.client.versions() + whoami = await self.client.whoami() + except MatrixInvalidToken as e: + self.log.error(f"Invalid token: {e}. Disabling client") + self.enabled = False + await self.update() + return + except Exception as e: + if try_n >= 8: + self.log.exception("Failed to get /account/whoami, disabling client") + self.enabled = False + await self.update() + else: + self.log.warning( + f"Failed to get /account/whoami, retrying in {(try_n + 1) * 10}s: {e}" + ) + background_task.create(self.start(try_n + 1)) + return + if whoami.user_id != self.id: + self.log.error(f"User ID mismatch: expected {self.id}, but got {whoami.user_id}") + self.enabled = False + await self.update() + return + elif whoami.device_id and self.device_id and whoami.device_id != self.device_id: + self.log.error( + f"Device ID mismatch: expected {self.device_id}, but got {whoami.device_id}" + ) + self.enabled = False + await self.update() + return + if not self.filter_id: + self.filter_id = await self.client.create_filter( + Filter( + room=RoomFilter( + timeline=RoomEventFilter( + limit=50, + lazy_load_members=True, + ), + state=StateFilter( + lazy_load_members=True, + ), + ), + presence=EventFilter( + not_types=[EventType.PRESENCE], + ), + ) + ) + await self.update() + if self.displayname != "disable": + await self.client.set_displayname(self.displayname) + if self.avatar_url != "disable": + await self.client.set_avatar_url(self.avatar_url) + if self.crypto: + await self._start_crypto() + self.start_sync() + await self._update_remote_profile() + self.started = True + self.log.info("Client started, starting plugin instances...") + await self.start_plugins() + + async def start_plugins(self) -> None: + await asyncio.gather(*[plugin.start() for plugin in self.references]) + + async def stop_plugins(self) -> None: + await asyncio.gather(*[plugin.stop() for plugin in self.references if plugin.started]) + + def start_sync(self) -> None: + if self.sync: + self.client.start(self.filter_id) + + def stop_sync(self) -> None: + self.client.stop() + + async def stop(self) -> None: + if self.started: + self.started = False + await self.stop_plugins() + self.stop_sync() + if self.crypto: + await self.crypto_store.close() + + async def clear_cache(self) -> None: + self.stop_sync() + self.filter_id = FilterID("") + self.next_batch = SyncToken("") + await self.update() + self.start_sync() + + def to_dict(self) -> dict: + return { + "id": self.id, + "homeserver": self.homeserver, + "access_token": self.access_token, + "device_id": self.device_id, + "fingerprint": ( + self.crypto.account.fingerprint if self.crypto and self.crypto.account else None + ), + "enabled": self.enabled, + "started": self.started, + "sync": self.sync, + "sync_ok": self.sync_ok, + "autojoin": self.autojoin, + "online": self.online, + "displayname": self.displayname, + "avatar_url": self.avatar_url, + "remote_displayname": self.remote_displayname, + "remote_avatar_url": self.remote_avatar_url, + "instances": [instance.to_dict() for instance in self.references], + "trust_state": str(self.trust_state) if self.trust_state else None, + } + + async def _handle_tombstone(self, evt: StateEvent) -> None: + if evt.state_key != "": + return + if not evt.content.replacement_room: + self.log.info(f"{evt.room_id} tombstoned with no replacement, ignoring") + return + is_joined = await self.client.state_store.is_joined( + evt.content.replacement_room, + self.client.mxid, + ) + if is_joined: + self.log.debug( + f"Ignoring tombstone from {evt.room_id} to {evt.content.replacement_room} " + f"sent by {evt.sender}: already joined to replacement room" + ) + return + self.log.debug( + f"Following tombstone from {evt.room_id} to {evt.content.replacement_room} " + f"sent by {evt.sender}" + ) + _, server = self.client.parse_user_id(evt.sender) + room_id = await self.client.join_room(evt.content.replacement_room, servers=[server]) + power_levels = await self.client.get_state_event(room_id, EventType.ROOM_POWER_LEVELS) + create_event = await self.client.get_state_event( + room_id, EventType.ROOM_CREATE, format="event" + ) + if power_levels.get_user_level(evt.sender, create_event) < power_levels.invite: + self.log.warning( + f"{evt.room_id} was tombstoned into {room_id} by {evt.sender}," + " but the sender doesn't have invite power levels, leaving..." + ) + await self.client.leave_room( + room_id, + f"Followed tombstone from {evt.room_id} by {evt.sender}," + " but sender doesn't have sufficient power level for invites", + ) + + async def _handle_invite(self, evt: StrippedStateEvent) -> None: + if evt.state_key == self.id and evt.content.membership == Membership.INVITE: + await self.client.join_room(evt.room_id) + + async def update_started(self, started: bool | None) -> None: + if started is None or started == self.started: + return + if started: + await self.start() + else: + await self.stop() + + async def update_enabled(self, enabled: bool | None, save: bool = True) -> None: + if enabled is None or enabled == self.enabled: + return + self.enabled = enabled + if save: + await self.update() + + async def update_displayname(self, displayname: str | None, save: bool = True) -> None: + if displayname is None or displayname == self.displayname: + return + self.displayname = displayname + if self.displayname != "disable": + await self.client.set_displayname(self.displayname) + else: + await self._update_remote_profile() + if save: + await self.update() + + async def update_avatar_url(self, avatar_url: ContentURI, save: bool = True) -> None: + if avatar_url is None or avatar_url == self.avatar_url: + return + self.avatar_url = avatar_url + if self.avatar_url != "disable": + await self.client.set_avatar_url(self.avatar_url) + else: + await self._update_remote_profile() + if save: + await self.update() + + async def update_sync(self, sync: bool | None, save: bool = True) -> None: + if sync is None or self.sync == sync: + return + self.sync = sync + if self.started: + if sync: + self.start_sync() + else: + self.stop_sync() + if save: + await self.update() + + async def update_autojoin(self, autojoin: bool | None, save: bool = True) -> None: + if autojoin is None or autojoin == self.autojoin: + return + if autojoin: + self.client.add_event_handler(EventType.ROOM_MEMBER, self._handle_invite) + else: + self.client.remove_event_handler(EventType.ROOM_MEMBER, self._handle_invite) + self.autojoin = autojoin + if save: + await self.update() + + async def update_online(self, online: bool | None, save: bool = True) -> None: + if online is None or online == self.online: + return + self.client.presence = PresenceState.ONLINE if online else PresenceState.OFFLINE + self.online = online + if save: + await self.update() + + async def update_access_details( + self, + access_token: str | None, + homeserver: str | None, + device_id: str | None = None, + ) -> None: + if not access_token and not homeserver: + return + if device_id is None: + device_id = self.device_id + elif not device_id: + device_id = None + if ( + access_token == self.access_token + and homeserver == self.homeserver + and device_id == self.device_id + ): + return + new_client = self._make_client(homeserver, access_token, device_id) + whoami = await new_client.whoami() + if whoami.user_id != self.id: + raise ValueError(f"MXID mismatch: {whoami.user_id}") + elif whoami.device_id and device_id and whoami.device_id != device_id: + raise ValueError(f"Device ID mismatch: {whoami.device_id}") + new_client.sync_store = self + self.stop_sync() + + # TODO this event handler transfer is pretty hacky + self._remove_crypto_event_handlers() + self.client.crypto = None + new_client.event_handlers = self.client.event_handlers + new_client.global_event_handlers = self.client.global_event_handlers + + self.client = new_client + self.homeserver = homeserver + self.access_token = access_token + self.device_id = device_id + if self.enable_crypto: + self._prepare_crypto() + await self._start_crypto() + else: + self.crypto_store = None + self.crypto = None + self.start_sync() + + async def _update_remote_profile(self) -> None: + try: + profile = await self.client.get_profile(self.id) + self.remote_displayname, self.remote_avatar_url = ( + profile.displayname, + profile.avatar_url, + ) + except Exception: + self.log.warning("Failed to update own profile from server", exc_info=True) + + async def delete(self) -> None: + try: + del self.cache[self.id] + except KeyError: + pass + await super().delete() + + @classmethod + @async_getter_lock + async def get( + cls, + user_id: UserID, + *, + homeserver: str | None = None, + access_token: str | None = None, + device_id: DeviceID | None = None, + ) -> Client | None: + try: + return cls.cache[user_id] + except KeyError: + pass + + user = cast(cls, await super().get(user_id)) + if user is not None: + user.postinit() + return user + + if homeserver and access_token: + user = cls( + user_id, + homeserver=homeserver, + access_token=access_token, + device_id=device_id or "", + ) + await user.insert() + user.postinit() + return user + + return None + + @classmethod + async def all(cls) -> AsyncGenerator[Client, None]: + users = await super().all() + user: cls + for user in users: + try: + yield cls.cache[user.id] + except KeyError: + user.postinit() + yield user diff --git a/maubot-src/maubot/config.py b/maubot-src/maubot/config.py new file mode 100644 index 0000000..b8e42de --- /dev/null +++ b/maubot-src/maubot/config.py @@ -0,0 +1,100 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import random +import re +import string + +import bcrypt + +from mautrix.util.config import BaseFileConfig, ConfigUpdateHelper + +bcrypt_regex = re.compile(r"^\$2[ayb]\$.{56}$") + + +class Config(BaseFileConfig): + @staticmethod + def _new_token() -> str: + return "".join(random.choices(string.ascii_lowercase + string.digits, k=64)) + + def do_update(self, helper: ConfigUpdateHelper) -> None: + base = helper.base + copy = helper.copy + + if "database" in self and self["database"].startswith("sqlite:///"): + helper.base["database"] = self["database"].replace("sqlite:///", "sqlite:") + else: + copy("database") + copy("database_opts") + if isinstance(self["crypto_database"], dict): + if self["crypto_database.type"] == "postgres": + base["crypto_database"] = self["crypto_database.postgres_uri"] + else: + copy("crypto_database") + copy("plugin_directories.upload") + copy("plugin_directories.load") + copy("plugin_directories.trash") + if "plugin_directories.db" in self: + base["plugin_databases.sqlite"] = self["plugin_directories.db"] + else: + copy("plugin_databases.sqlite") + copy("plugin_databases.postgres") + copy("plugin_databases.postgres_opts") + copy("server.hostname") + copy("server.port") + copy("server.public_url") + copy("server.listen") + copy("server.ui_base_path") + copy("server.plugin_base_path") + copy("server.override_resource_path") + shared_secret = self["server.unshared_secret"] + if shared_secret is None or shared_secret == "generate": + base["server.unshared_secret"] = self._new_token() + else: + base["server.unshared_secret"] = shared_secret + if "registration_secrets" in self: + base["homeservers"] = self["registration_secrets"] + else: + copy("homeservers") + copy("admins") + for username, password in base["admins"].items(): + if password and not bcrypt_regex.match(password): + if password == "password": + password = self._new_token() + base["admins"][username] = bcrypt.hashpw( + password.encode("utf-8"), bcrypt.gensalt() + ).decode("utf-8") + copy("api_features.login") + copy("api_features.plugin") + copy("api_features.plugin_upload") + copy("api_features.instance") + copy("api_features.instance_database") + copy("api_features.client") + copy("api_features.client_proxy") + copy("api_features.client_auth") + copy("api_features.dev_open") + copy("api_features.log") + copy("logging") + + def is_admin(self, user: str) -> bool: + return user == "root" or user in self["admins"] + + def check_password(self, user: str, passwd: str) -> bool: + if user == "root": + return False + passwd_hash = self["admins"].get(user, None) + if not passwd_hash: + return False + return bcrypt.checkpw(passwd.encode("utf-8"), passwd_hash.encode("utf-8")) diff --git a/maubot-src/maubot/db/__init__.py b/maubot-src/maubot/db/__init__.py new file mode 100644 index 0000000..68833ce --- /dev/null +++ b/maubot-src/maubot/db/__init__.py @@ -0,0 +1,13 @@ +from mautrix.util.async_db import Database + +from .client import Client +from .instance import DatabaseEngine, Instance +from .upgrade import upgrade_table + + +def init(db: Database) -> None: + for table in (Client, Instance): + table.db = db + + +__all__ = ["upgrade_table", "init", "Client", "Instance", "DatabaseEngine"] diff --git a/maubot-src/maubot/db/client.py b/maubot-src/maubot/db/client.py new file mode 100644 index 0000000..52f3a20 --- /dev/null +++ b/maubot-src/maubot/db/client.py @@ -0,0 +1,114 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import TYPE_CHECKING, ClassVar + +from asyncpg import Record +from attr import dataclass + +from mautrix.client import SyncStore +from mautrix.types import ContentURI, DeviceID, FilterID, SyncToken, UserID +from mautrix.util.async_db import Database + +fake_db = Database.create("") if TYPE_CHECKING else None + + +@dataclass +class Client(SyncStore): + db: ClassVar[Database] = fake_db + + id: UserID + homeserver: str + access_token: str + device_id: DeviceID + enabled: bool + + next_batch: SyncToken + filter_id: FilterID + + sync: bool + autojoin: bool + online: bool + + displayname: str + avatar_url: ContentURI + + @classmethod + def _from_row(cls, row: Record | None) -> Client | None: + if row is None: + return None + return cls(**row) + + _columns = ( + "id, homeserver, access_token, device_id, enabled, next_batch, filter_id, " + "sync, autojoin, online, displayname, avatar_url" + ) + + @property + def _values(self): + return ( + self.id, + self.homeserver, + self.access_token, + self.device_id, + self.enabled, + self.next_batch, + self.filter_id, + self.sync, + self.autojoin, + self.online, + self.displayname, + self.avatar_url, + ) + + @classmethod + async def all(cls) -> list[Client]: + rows = await cls.db.fetch(f"SELECT {cls._columns} FROM client") + return [cls._from_row(row) for row in rows] + + @classmethod + async def get(cls, id: str) -> Client | None: + q = f"SELECT {cls._columns} FROM client WHERE id=$1" + return cls._from_row(await cls.db.fetchrow(q, id)) + + async def insert(self) -> None: + q = """ + INSERT INTO client ( + id, homeserver, access_token, device_id, enabled, next_batch, filter_id, + sync, autojoin, online, displayname, avatar_url + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) + """ + await self.db.execute(q, *self._values) + + async def put_next_batch(self, next_batch: SyncToken) -> None: + await self.db.execute("UPDATE client SET next_batch=$1 WHERE id=$2", next_batch, self.id) + self.next_batch = next_batch + + async def get_next_batch(self) -> SyncToken: + return self.next_batch + + async def update(self) -> None: + q = """ + UPDATE client SET homeserver=$2, access_token=$3, device_id=$4, enabled=$5, + next_batch=$6, filter_id=$7, sync=$8, autojoin=$9, online=$10, + displayname=$11, avatar_url=$12 + WHERE id=$1 + """ + await self.db.execute(q, *self._values) + + async def delete(self) -> None: + await self.db.execute("DELETE FROM client WHERE id=$1", self.id) diff --git a/maubot-src/maubot/db/instance.py b/maubot-src/maubot/db/instance.py new file mode 100644 index 0000000..5bb3f6a --- /dev/null +++ b/maubot-src/maubot/db/instance.py @@ -0,0 +1,101 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import TYPE_CHECKING, ClassVar +from enum import Enum + +from asyncpg import Record +from attr import dataclass + +from mautrix.types import UserID +from mautrix.util.async_db import Database + +fake_db = Database.create("") if TYPE_CHECKING else None + + +class DatabaseEngine(Enum): + SQLITE = "sqlite" + POSTGRES = "postgres" + + +@dataclass +class Instance: + db: ClassVar[Database] = fake_db + + id: str + type: str + enabled: bool + primary_user: UserID + config_str: str + database_engine: DatabaseEngine | None + + @property + def database_engine_str(self) -> str | None: + return self.database_engine.value if self.database_engine else None + + @classmethod + def _from_row(cls, row: Record | None) -> Instance | None: + if row is None: + return None + data = {**row} + db_engine = data.pop("database_engine", None) + return cls(**data, database_engine=DatabaseEngine(db_engine) if db_engine else None) + + _columns = "id, type, enabled, primary_user, config, database_engine" + + @classmethod + async def all(cls) -> list[Instance]: + q = f"SELECT {cls._columns} FROM instance" + rows = await cls.db.fetch(q) + return [cls._from_row(row) for row in rows] + + @classmethod + async def get(cls, id: str) -> Instance | None: + q = f"SELECT {cls._columns} FROM instance WHERE id=$1" + return cls._from_row(await cls.db.fetchrow(q, id)) + + async def update_id(self, new_id: str) -> None: + await self.db.execute("UPDATE instance SET id=$1 WHERE id=$2", new_id, self.id) + self.id = new_id + + @property + def _values(self): + return ( + self.id, + self.type, + self.enabled, + self.primary_user, + self.config_str, + self.database_engine_str, + ) + + async def insert(self) -> None: + q = ( + "INSERT INTO instance (id, type, enabled, primary_user, config, database_engine) " + "VALUES ($1, $2, $3, $4, $5, $6)" + ) + await self.db.execute(q, *self._values) + + async def update(self) -> None: + q = """ + UPDATE instance SET type=$2, enabled=$3, primary_user=$4, config=$5, database_engine=$6 + WHERE id=$1 + """ + await self.db.execute(q, *self._values) + + async def delete(self) -> None: + await self.db.execute("DELETE FROM instance WHERE id=$1", self.id) diff --git a/maubot-src/maubot/db/upgrade/__init__.py b/maubot-src/maubot/db/upgrade/__init__.py new file mode 100644 index 0000000..ed96422 --- /dev/null +++ b/maubot-src/maubot/db/upgrade/__init__.py @@ -0,0 +1,5 @@ +from mautrix.util.async_db import UpgradeTable + +upgrade_table = UpgradeTable() + +from . import v01_initial_revision, v02_instance_database_engine diff --git a/maubot-src/maubot/db/upgrade/v01_initial_revision.py b/maubot-src/maubot/db/upgrade/v01_initial_revision.py new file mode 100644 index 0000000..2da8aff --- /dev/null +++ b/maubot-src/maubot/db/upgrade/v01_initial_revision.py @@ -0,0 +1,136 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from mautrix.util.async_db import Connection, Scheme + +from . import upgrade_table + +legacy_version_query = "SELECT version_num FROM alembic_version" +last_legacy_version = "90aa88820eab" + + +@upgrade_table.register(description="Initial asyncpg revision") +async def upgrade_v1(conn: Connection, scheme: Scheme) -> None: + if await conn.table_exists("alembic_version"): + await migrate_legacy_to_v1(conn, scheme) + else: + return await create_v1_tables(conn) + + +async def create_v1_tables(conn: Connection) -> None: + await conn.execute( + """CREATE TABLE client ( + id TEXT PRIMARY KEY, + homeserver TEXT NOT NULL, + access_token TEXT NOT NULL, + device_id TEXT NOT NULL, + enabled BOOLEAN NOT NULL, + + next_batch TEXT NOT NULL, + filter_id TEXT NOT NULL, + + sync BOOLEAN NOT NULL, + autojoin BOOLEAN NOT NULL, + online BOOLEAN NOT NULL, + + displayname TEXT NOT NULL, + avatar_url TEXT NOT NULL + )""" + ) + await conn.execute( + """CREATE TABLE instance ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL, + enabled BOOLEAN NOT NULL, + primary_user TEXT NOT NULL, + config TEXT NOT NULL, + FOREIGN KEY (primary_user) REFERENCES client(id) ON DELETE RESTRICT ON UPDATE CASCADE + )""" + ) + + +async def migrate_legacy_to_v1(conn: Connection, scheme: Scheme) -> None: + legacy_version = await conn.fetchval(legacy_version_query) + if legacy_version != last_legacy_version: + raise RuntimeError( + "Legacy database is not on last version. " + "Please upgrade the old database with alembic or drop it completely first." + ) + await conn.execute("ALTER TABLE plugin RENAME TO instance") + await update_state_store(conn, scheme) + if scheme != Scheme.SQLITE: + await varchar_to_text(conn) + await conn.execute("DROP TABLE alembic_version") + + +async def update_state_store(conn: Connection, scheme: Scheme) -> None: + # The Matrix state store already has more or less the correct schema, so set the version + await conn.execute("CREATE TABLE mx_version (version INTEGER PRIMARY KEY)") + await conn.execute("INSERT INTO mx_version (version) VALUES (2)") + if scheme != Scheme.SQLITE: + # Remove old uppercase membership type and recreate it as lowercase + await conn.execute("ALTER TABLE mx_user_profile ALTER COLUMN membership TYPE TEXT") + await conn.execute("DROP TYPE IF EXISTS membership") + await conn.execute( + "CREATE TYPE membership AS ENUM ('join', 'leave', 'invite', 'ban', 'knock')" + ) + await conn.execute( + "ALTER TABLE mx_user_profile ALTER COLUMN membership TYPE membership " + "USING LOWER(membership)::membership" + ) + else: + # Recreate table to remove CHECK constraint and lowercase everything + await conn.execute( + """CREATE TABLE new_mx_user_profile ( + room_id TEXT, + user_id TEXT, + membership TEXT NOT NULL + CHECK (membership IN ('join', 'leave', 'invite', 'ban', 'knock')), + displayname TEXT, + avatar_url TEXT, + PRIMARY KEY (room_id, user_id) + )""" + ) + await conn.execute( + """ + INSERT INTO new_mx_user_profile (room_id, user_id, membership, displayname, avatar_url) + SELECT room_id, user_id, LOWER(membership), displayname, avatar_url + FROM mx_user_profile + """ + ) + await conn.execute("DROP TABLE mx_user_profile") + await conn.execute("ALTER TABLE new_mx_user_profile RENAME TO mx_user_profile") + + +async def varchar_to_text(conn: Connection) -> None: + columns_to_adjust = { + "client": ( + "id", + "homeserver", + "device_id", + "next_batch", + "filter_id", + "displayname", + "avatar_url", + ), + "instance": ("id", "type", "primary_user"), + "mx_room_state": ("room_id",), + "mx_user_profile": ("room_id", "user_id", "displayname", "avatar_url"), + } + for table, columns in columns_to_adjust.items(): + for column in columns: + await conn.execute(f'ALTER TABLE "{table}" ALTER COLUMN {column} TYPE TEXT') diff --git a/maubot-src/maubot/db/upgrade/v02_instance_database_engine.py b/maubot-src/maubot/db/upgrade/v02_instance_database_engine.py new file mode 100644 index 0000000..7d2d7e7 --- /dev/null +++ b/maubot-src/maubot/db/upgrade/v02_instance_database_engine.py @@ -0,0 +1,25 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from mautrix.util.async_db import Connection + +from . import upgrade_table + + +@upgrade_table.register(description="Store instance database engine") +async def upgrade_v2(conn: Connection) -> None: + await conn.execute("ALTER TABLE instance ADD COLUMN database_engine TEXT") diff --git a/maubot-src/maubot/example-config.yaml b/maubot-src/maubot/example-config.yaml new file mode 100644 index 0000000..7991461 --- /dev/null +++ b/maubot-src/maubot/example-config.yaml @@ -0,0 +1,132 @@ +# The full URI to the database. SQLite and Postgres are fully supported. +# Format examples: +# SQLite: sqlite:filename.db +# Postgres: postgresql://username:password@hostname/dbname +database: sqlite:maubot.db + +# Separate database URL for the crypto database. "default" means use the same database as above. +crypto_database: default + +# Additional arguments for asyncpg.create_pool() or sqlite3.connect() +# https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.pool.create_pool +# https://docs.python.org/3/library/sqlite3.html#sqlite3.connect +# For sqlite, min_size is used as the connection thread pool size and max_size is ignored. +database_opts: + min_size: 1 + max_size: 10 + +# Configuration for storing plugin .mbp files +plugin_directories: + # The directory where uploaded new plugins should be stored. + upload: ./plugins + # The directories from which plugins should be loaded. + # Duplicate plugin IDs will be moved to the trash. + load: + - ./plugins + # The directory where old plugin versions and conflicting plugins should be moved. + # Set to "delete" to delete files immediately. + trash: ./trash + +# Configuration for storing plugin databases +plugin_databases: + # The directory where SQLite plugin databases should be stored. + sqlite: ./plugins + # The connection URL for plugin databases. If null, all plugins will get SQLite databases. + # If set, plugins using the new asyncpg interface will get a Postgres connection instead. + # Plugins using the legacy SQLAlchemy interface will always get a SQLite connection. + # + # To use the same connection pool as the default database, set to "default" + # (the default database above must be postgres to do this). + # + # When enabled, maubot will create separate Postgres schemas in the database for each plugin. + # To view schemas in psql, use `\dn`. To view enter and interact with a specific schema, + # use `SET search_path = name` (where `name` is the name found with `\dn`) and then use normal + # SQL queries/psql commands. + postgres: null + # Maximum number of connections per plugin instance. + postgres_max_conns_per_plugin: 3 + # Overrides for the default database_opts when using a non-"default" postgres connection string. + postgres_opts: {} + +server: + # The IP and port to listen to. + hostname: 0.0.0.0 + port: 29316 + # Public base URL where the server is visible. + public_url: https://example.com + # The base path for the UI. Note that this does not change the API path. + # Add a path prefix to public_url if you want everything on a subpath. + ui_base_path: /_matrix/maubot + # The base path for plugin endpoints. The instance ID will be appended directly. + plugin_base_path: /_matrix/maubot/plugin/ + # Override path from where to load UI resources. + # Set to false to using pkg_resources to find the path. + override_resource_path: false + # The shared secret to sign API access tokens. + # Set to "generate" to generate and save a new token at startup. + unshared_secret: generate + +# Known homeservers. This is required for the `mbc auth` command and also allows +# more convenient access from the management UI. This is not required to create +# clients in the management UI, since you can also just type the homeserver URL +# into the box there. +homeservers: + matrix.org: + # Client-server API URL + url: https://matrix-client.matrix.org + # registration_shared_secret from synapse config + # You can leave this empty if you don't have access to the homeserver. + # When this is empty, `mbc auth --register` won't work, but `mbc auth` (login) will. + secret: null + +# List of administrator users. Each key is a username and the value is the password. +# Plaintext passwords will be bcrypted on startup. Set empty password to prevent normal login. +# Root is a special user that can't have a password and will always exist. +admins: + root: "" + +# API feature switches. +api_features: + login: true + plugin: true + plugin_upload: true + instance: true + instance_database: true + client: true + client_proxy: true + client_auth: true + dev_open: true + log: true + +# Python logging configuration. +# +# See section 16.7.2 of the Python documentation for more info: +# https://docs.python.org/3.6/library/logging.config.html#configuration-dictionary-schema +logging: + version: 1 + formatters: + colored: + (): maubot.lib.color_log.ColorFormatter + format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + normal: + format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + handlers: + file: + class: logging.handlers.RotatingFileHandler + formatter: normal + filename: ./maubot.log + maxBytes: 10485760 + backupCount: 10 + console: + class: logging.StreamHandler + formatter: colored + loggers: + maubot: + level: DEBUG + mau: + level: DEBUG + aiohttp: + level: INFO + root: + level: DEBUG + handlers: [file, console] diff --git a/maubot-src/maubot/handlers/__init__.py b/maubot-src/maubot/handlers/__init__.py new file mode 100644 index 0000000..e8567a2 --- /dev/null +++ b/maubot-src/maubot/handlers/__init__.py @@ -0,0 +1 @@ +from . import command, event, web diff --git a/maubot-src/maubot/handlers/command.py b/maubot-src/maubot/handlers/command.py new file mode 100644 index 0000000..27e6547 --- /dev/null +++ b/maubot-src/maubot/handlers/command.py @@ -0,0 +1,496 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from typing import ( + Any, + Awaitable, + Callable, + Dict, + Iterable, + List, + NewType, + Optional, + Pattern, + Sequence, + Set, + Tuple, + Union, +) +from abc import ABC, abstractmethod +import asyncio +import functools +import inspect +import re + +from mautrix.types import EventType, MessageType + +from ..matrix import MaubotMessageEvent +from . import event + +PrefixType = Optional[Union[str, Callable[[], str], Callable[[Any], str]]] +AliasesType = Union[ + List[str], Tuple[str, ...], Set[str], Callable[[str], bool], Callable[[Any, str], bool] +] +CommandHandlerFunc = NewType( + "CommandHandlerFunc", Callable[[MaubotMessageEvent, Any], Awaitable[Any]] +) +CommandHandlerDecorator = NewType( + "CommandHandlerDecorator", + Callable[[Union["CommandHandler", CommandHandlerFunc]], "CommandHandler"], +) +PassiveCommandHandlerDecorator = NewType( + "PassiveCommandHandlerDecorator", Callable[[CommandHandlerFunc], CommandHandlerFunc] +) + + +def _split_in_two(val: str, split_by: str) -> List[str]: + return val.split(split_by, 1) if split_by in val else [val, ""] + + +class CommandHandler: + def __init__(self, func: CommandHandlerFunc) -> None: + self.__mb_func__: CommandHandlerFunc = func + self.__mb_parent__: Optional[CommandHandler] = None + self.__mb_subcommands__: List[CommandHandler] = [] + self.__mb_arguments__: List[Argument] = [] + self.__mb_help__: Optional[str] = None + self.__mb_get_name__: Callable[[Any], str] = lambda s: "noname" + self.__mb_is_command_match__: Callable[[Any, str], bool] = self.__command_match_unset + self.__mb_require_subcommand__: bool = True + self.__mb_must_consume_args__: bool = True + self.__mb_arg_fallthrough__: bool = True + self.__mb_event_handler__: bool = True + self.__mb_event_types__: set[EventType] = {EventType.ROOM_MESSAGE} + self.__mb_msgtypes__: Iterable[MessageType] = (MessageType.TEXT,) + self.__bound_copies__: Dict[Any, CommandHandler] = {} + self.__bound_instance__: Any = None + + def __get__(self, instance, instancetype): + if not instance or self.__bound_instance__: + return self + try: + return self.__bound_copies__[instance] + except KeyError: + new_ch = type(self)(self.__mb_func__) + keys = [ + "parent", + "subcommands", + "arguments", + "help", + "get_name", + "is_command_match", + "require_subcommand", + "must_consume_args", + "arg_fallthrough", + "event_handler", + "event_types", + "msgtypes", + ] + for key in keys: + key = f"__mb_{key}__" + setattr(new_ch, key, getattr(self, key)) + new_ch.__bound_instance__ = instance + new_ch.__mb_subcommands__ = [ + subcmd.__get__(instance, instancetype) for subcmd in self.__mb_subcommands__ + ] + self.__bound_copies__[instance] = new_ch + return new_ch + + @staticmethod + def __command_match_unset(self, val: str) -> bool: + raise NotImplementedError("Hmm") + + async def __call__( + self, + evt: MaubotMessageEvent, + *, + _existing_args: Dict[str, Any] = None, + remaining_val: str = None, + ) -> Any: + if evt.sender == evt.client.mxid or evt.content.msgtype not in self.__mb_msgtypes__: + return + if remaining_val is None: + if not evt.content.body or evt.content.body[0] != "!": + return + command, remaining_val = _split_in_two(evt.content.body[1:], " ") + command = command.lower() + if not self.__mb_is_command_match__(self.__bound_instance__, command): + return + call_args: Dict[str, Any] = {**_existing_args} if _existing_args else {} + + if not self.__mb_arg_fallthrough__ and len(self.__mb_subcommands__) > 0: + ok, res = await self.__call_subcommand__(evt, call_args, remaining_val) + if ok: + return res + + ok, remaining_val = await self.__parse_args__(evt, call_args, remaining_val) + if not ok: + return + elif self.__mb_arg_fallthrough__ and len(self.__mb_subcommands__) > 0: + ok, res = await self.__call_subcommand__(evt, call_args, remaining_val) + if ok: + return res + elif self.__mb_require_subcommand__: + await evt.reply(self.__mb_full_help__) + return + + if self.__mb_must_consume_args__ and remaining_val.strip(): + await evt.reply(self.__mb_full_help__) + return + + if self.__bound_instance__: + return await self.__mb_func__(self.__bound_instance__, evt, **call_args) + return await self.__mb_func__(evt, **call_args) + + async def __call_subcommand__( + self, evt: MaubotMessageEvent, call_args: Dict[str, Any], remaining_val: str + ) -> Tuple[bool, Any]: + command, remaining_val = _split_in_two(remaining_val.strip(), " ") + for subcommand in self.__mb_subcommands__: + if subcommand.__mb_is_command_match__(subcommand.__bound_instance__, command): + return True, await subcommand( + evt, _existing_args=call_args, remaining_val=remaining_val + ) + return False, None + + async def __parse_args__( + self, evt: MaubotMessageEvent, call_args: Dict[str, Any], remaining_val: str + ) -> Tuple[bool, str]: + for arg in self.__mb_arguments__: + try: + remaining_val, call_args[arg.name] = arg.match( + remaining_val.strip(), evt=evt, instance=self.__bound_instance__ + ) + if arg.required and call_args[arg.name] is None: + raise ValueError("Argument required") + except ArgumentSyntaxError as e: + await evt.reply(e.message + (f"\n{self.__mb_usage__}" if e.show_usage else "")) + return False, remaining_val + except ValueError: + await evt.reply(self.__mb_usage__) + return False, remaining_val + return True, remaining_val + + @property + def __mb_full_help__(self) -> str: + usage = self.__mb_usage_without_subcommands__ + "\n\n" + if not self.__mb_require_subcommand__: + usage += f"* {self.__mb_prefix__} {self.__mb_usage_args__} - {self.__mb_help__}\n" + usage += "\n".join(cmd.__mb_usage_inline__ for cmd in self.__mb_subcommands__) + return usage + + @property + def __mb_usage_args__(self) -> str: + arg_usage = " ".join( + f"<{arg.label}>" if arg.required else f"[{arg.label}]" for arg in self.__mb_arguments__ + ) + if self.__mb_subcommands__ and self.__mb_arg_fallthrough__: + arg_usage += " " + self.__mb_usage_subcommand__ + return arg_usage + + @property + def __mb_usage_subcommand__(self) -> str: + return f" [...]" + + @property + def __mb_name__(self) -> str: + return self.__mb_get_name__(self.__bound_instance__) + + @property + def __mb_prefix__(self) -> str: + if self.__mb_parent__: + return ( + f"!{self.__mb_parent__.__mb_get_name__(self.__bound_instance__)} " + f"{self.__mb_name__}" + ) + return f"!{self.__mb_name__}" + + @property + def __mb_usage_inline__(self) -> str: + if not self.__mb_arg_fallthrough__: + return ( + f"* {self.__mb_name__} {self.__mb_usage_args__} - {self.__mb_help__}\n" + f"* {self.__mb_name__} {self.__mb_usage_subcommand__}" + ) + return f"* {self.__mb_name__} {self.__mb_usage_args__} - {self.__mb_help__}" + + @property + def __mb_subcommands_list__(self) -> str: + return f"**Subcommands:** {', '.join(sc.__mb_name__ for sc in self.__mb_subcommands__)}" + + @property + def __mb_usage_without_subcommands__(self) -> str: + if not self.__mb_arg_fallthrough__: + if not self.__mb_arguments__: + return f"**Usage:** {self.__mb_prefix__} [subcommand] [...]" + return ( + f"**Usage:** {self.__mb_prefix__} {self.__mb_usage_args__}" + f" _OR_ {self.__mb_prefix__} {self.__mb_usage_subcommand__}" + ) + return f"**Usage:** {self.__mb_prefix__} {self.__mb_usage_args__}" + + @property + def __mb_usage__(self) -> str: + if len(self.__mb_subcommands__) > 0: + return f"{self.__mb_usage_without_subcommands__} \n{self.__mb_subcommands_list__}" + return self.__mb_usage_without_subcommands__ + + def subcommand( + self, + name: PrefixType = None, + *, + help: str = None, + aliases: AliasesType = None, + required_subcommand: bool = True, + arg_fallthrough: bool = True, + ) -> CommandHandlerDecorator: + def decorator(func: Union[CommandHandler, CommandHandlerFunc]) -> CommandHandler: + if not isinstance(func, CommandHandler): + func = CommandHandler(func) + new( + name, + help=help, + aliases=aliases, + require_subcommand=required_subcommand, + arg_fallthrough=arg_fallthrough, + )(func) + func.__mb_parent__ = self + func.__mb_event_handler__ = False + self.__mb_subcommands__.append(func) + return func + + return decorator + + +def new( + name: PrefixType = None, + *, + help: str = None, + aliases: AliasesType = None, + event_type: EventType = EventType.ROOM_MESSAGE, + msgtypes: Iterable[MessageType] = None, + require_subcommand: bool = True, + arg_fallthrough: bool = True, + must_consume_args: bool = True, +) -> CommandHandlerDecorator: + def decorator(func: Union[CommandHandler, CommandHandlerFunc]) -> CommandHandler: + if not isinstance(func, CommandHandler): + func = CommandHandler(func) + func.__mb_help__ = help + if name: + if callable(name): + if len(inspect.getfullargspec(name).args) == 0: + func.__mb_get_name__ = lambda self: name() + else: + func.__mb_get_name__ = name + else: + func.__mb_get_name__ = lambda self: name + else: + func.__mb_get_name__ = lambda self: func.__mb_func__.__name__.replace("_", "-") + if callable(aliases): + if len(inspect.getfullargspec(aliases).args) == 1: + func.__mb_is_command_match__ = lambda self, val: aliases(val) + else: + func.__mb_is_command_match__ = aliases + elif isinstance(aliases, (list, set, tuple)): + func.__mb_is_command_match__ = lambda self, val: ( + val == func.__mb_get_name__(self) or val in aliases + ) + else: + func.__mb_is_command_match__ = lambda self, val: val == func.__mb_get_name__(self) + # Decorators are executed last to first, so we reverse the argument list. + func.__mb_arguments__.reverse() + func.__mb_require_subcommand__ = require_subcommand + func.__mb_arg_fallthrough__ = arg_fallthrough + func.__mb_must_consume_args__ = must_consume_args + func.__mb_event_types__ = {event_type} + if msgtypes: + func.__mb_msgtypes__ = msgtypes + return func + + return decorator + + +class ArgumentSyntaxError(ValueError): + def __init__(self, message: str, show_usage: bool = True) -> None: + super().__init__(message) + self.message = message + self.show_usage = show_usage + + +class Argument(ABC): + def __init__( + self, name: str, label: str = None, *, required: bool = False, pass_raw: bool = False + ) -> None: + self.name = name + self.label = label or name + self.required = required + self.pass_raw = pass_raw + + @abstractmethod + def match(self, val: str, **kwargs) -> Tuple[str, Any]: + pass + + def __call__(self, func: Union[CommandHandler, CommandHandlerFunc]) -> CommandHandler: + if not isinstance(func, CommandHandler): + func = CommandHandler(func) + func.__mb_arguments__.append(self) + return func + + +class RegexArgument(Argument): + def __init__( + self, + name: str, + label: str = None, + *, + required: bool = False, + pass_raw: bool = False, + matches: str = None, + ) -> None: + super().__init__(name, label, required=required, pass_raw=pass_raw) + matches = f"^{matches}" if self.pass_raw else f"^{matches}$" + self.regex = re.compile(matches) + + def match(self, val: str, **kwargs) -> Tuple[str, Any]: + orig_val = val + if not self.pass_raw: + val = re.split(r"\s", val, 1)[0] + match = self.regex.match(val) + if match: + return ( + orig_val[: match.start()] + orig_val[match.end() :], + match.groups() or val[match.start() : match.end()], + ) + return orig_val, None + + +class CustomArgument(Argument): + def __init__( + self, + name: str, + label: str = None, + *, + required: bool = False, + pass_raw: bool = False, + matcher: Callable[[str], Any], + ) -> None: + super().__init__(name, label, required=required, pass_raw=pass_raw) + self.matcher = matcher + + def match(self, val: str, **kwargs) -> Tuple[str, Any]: + if self.pass_raw: + return self.matcher(val) + orig_val = val + val = re.split(r"\s", val, 1)[0] + res = self.matcher(val) + if res is not None: + return orig_val[len(val) :], res + return orig_val, None + + +class SimpleArgument(Argument): + def match(self, val: str, **kwargs) -> Tuple[str, Any]: + if self.pass_raw: + return "", val + res = re.split(r"\s", val, 1)[0] + return val[len(res) :], res + + +def argument( + name: str, + label: str = None, + *, + required: bool = True, + matches: Optional[str] = None, + parser: Optional[Callable[[str], Any]] = None, + pass_raw: bool = False, +) -> CommandHandlerDecorator: + if matches: + return RegexArgument(name, label, required=required, matches=matches, pass_raw=pass_raw) + elif parser: + return CustomArgument(name, label, required=required, matcher=parser, pass_raw=pass_raw) + else: + return SimpleArgument(name, label, required=required, pass_raw=pass_raw) + + +def passive( + regex: Union[str, Pattern], + *, + msgtypes: Sequence[MessageType] = (MessageType.TEXT,), + field: Callable[[MaubotMessageEvent], str] = lambda evt: evt.content.body, + event_type: EventType = EventType.ROOM_MESSAGE, + multiple: bool = False, + case_insensitive: bool = False, + multiline: bool = False, + dot_all: bool = False, +) -> PassiveCommandHandlerDecorator: + if not isinstance(regex, Pattern): + flags = re.RegexFlag.UNICODE + if case_insensitive: + flags |= re.IGNORECASE + if multiline: + flags |= re.MULTILINE + if dot_all: + flags |= re.DOTALL + regex = re.compile(regex, flags=flags) + + def decorator(func: CommandHandlerFunc) -> CommandHandlerFunc: + combine = None + if hasattr(func, "__mb_passive_orig__"): + combine = func + func = func.__mb_passive_orig__ + + @event.on(event_type) + @functools.wraps(func) + async def replacement(self, evt: MaubotMessageEvent = None) -> None: + if not evt and isinstance(self, MaubotMessageEvent): + evt = self + self = None + if evt.sender == evt.client.mxid: + return + elif msgtypes and evt.content.msgtype not in msgtypes: + return + data = field(evt) + if multiple: + val = [ + (data[match.pos : match.endpos], *match.groups()) + for match in regex.finditer(data) + ] + else: + match = regex.search(data) + if match: + val = (data[match.pos : match.endpos], *match.groups()) + else: + val = None + if val: + if self: + await func(self, evt, val) + else: + await func(evt, val) + + if combine: + orig_replacement = replacement + + @event.on(event_type) + @functools.wraps(func) + async def replacement(self, evt: MaubotMessageEvent = None) -> None: + await asyncio.gather(combine(self, evt), orig_replacement(self, evt)) + + replacement.__mb_passive_orig__ = func + + return replacement + + return decorator diff --git a/maubot-src/maubot/handlers/event.py b/maubot-src/maubot/handlers/event.py new file mode 100644 index 0000000..9be89b1 --- /dev/null +++ b/maubot-src/maubot/handlers/event.py @@ -0,0 +1,44 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import Callable, NewType + +from mautrix.client import EventHandler, InternalEventType +from mautrix.types import EventType + +EventHandlerDecorator = NewType("EventHandlerDecorator", Callable[[EventHandler], EventHandler]) + + +def on(var: EventType | InternalEventType | EventHandler) -> EventHandlerDecorator | EventHandler: + def decorator(func: EventHandler) -> EventHandler: + func.__mb_event_handler__ = True + if isinstance(var, (EventType, InternalEventType)): + if hasattr(func, "__mb_event_types__"): + func.__mb_event_types__.add(var) + else: + func.__mb_event_types__ = {var} + else: + func.__mb_event_types__ = {EventType.ALL} + + return func + + return decorator if isinstance(var, (EventType, InternalEventType)) else decorator(var) + + +def off(func: EventHandler) -> EventHandler: + func.__mb_event_handler__ = False + return func diff --git a/maubot-src/maubot/handlers/web.py b/maubot-src/maubot/handlers/web.py new file mode 100644 index 0000000..f170124 --- /dev/null +++ b/maubot-src/maubot/handlers/web.py @@ -0,0 +1,66 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from typing import Any, Awaitable, Callable + +from aiohttp import hdrs, web + +WebHandler = Callable[[web.Request], Awaitable[web.StreamResponse]] +WebHandlerDecorator = Callable[[WebHandler], WebHandler] + + +def head(path: str, **kwargs: Any) -> WebHandlerDecorator: + return handle(hdrs.METH_HEAD, path, **kwargs) + + +def options(path: str, **kwargs: Any) -> WebHandlerDecorator: + return handle(hdrs.METH_OPTIONS, path, **kwargs) + + +def get(path: str, **kwargs: Any) -> WebHandlerDecorator: + return handle(hdrs.METH_GET, path, **kwargs) + + +def post(path: str, **kwargs: Any) -> WebHandlerDecorator: + return handle(hdrs.METH_POST, path, **kwargs) + + +def put(path: str, **kwargs: Any) -> WebHandlerDecorator: + return handle(hdrs.METH_PUT, path, **kwargs) + + +def patch(path: str, **kwargs: Any) -> WebHandlerDecorator: + return handle(hdrs.METH_PATCH, path, **kwargs) + + +def delete(path: str, **kwargs: Any) -> WebHandlerDecorator: + return handle(hdrs.METH_DELETE, path, **kwargs) + + +def view(path: str, **kwargs: Any) -> WebHandlerDecorator: + return handle(hdrs.METH_ANY, path, **kwargs) + + +def handle(method: str, path: str, **kwargs) -> WebHandlerDecorator: + def decorator(handler: WebHandler) -> WebHandler: + try: + handlers = getattr(handler, "__mb_web_handler__") + except AttributeError: + handlers = [] + setattr(handler, "__mb_web_handler__", handlers) + handlers.append((method, path, kwargs)) + return handler + + return decorator diff --git a/maubot-src/maubot/instance.py b/maubot-src/maubot/instance.py new file mode 100644 index 0000000..8427e3c --- /dev/null +++ b/maubot-src/maubot/instance.py @@ -0,0 +1,533 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, AsyncGenerator, cast +from collections import defaultdict +import asyncio +import inspect +import io +import logging +import os.path + +from ruamel.yaml import YAML +from ruamel.yaml.comments import CommentedMap + +from mautrix.types import UserID +from mautrix.util import background_task +from mautrix.util.async_db import Database, Scheme, UpgradeTable +from mautrix.util.async_getter_lock import async_getter_lock +from mautrix.util.config import BaseProxyConfig, RecursiveDict +from mautrix.util.logging import TraceLogger + +from .client import Client +from .db import DatabaseEngine, Instance as DBInstance +from .lib.optionalalchemy import Engine, MetaData, create_engine +from .lib.plugin_db import ProxyPostgresDatabase +from .loader import DatabaseType, PluginLoader, ZippedPluginLoader +from .plugin_base import Plugin + +if TYPE_CHECKING: + from .__main__ import Maubot + from .server import PluginWebApp + +log: TraceLogger = cast(TraceLogger, logging.getLogger("maubot.instance")) +db_log: TraceLogger = cast(TraceLogger, logging.getLogger("maubot.instance_db")) + +yaml = YAML() +yaml.indent(4) +yaml.width = 200 + + +class PluginInstance(DBInstance): + maubot: "Maubot" = None + cache: dict[str, PluginInstance] = {} + plugin_directories: list[str] = [] + _async_get_locks: dict[Any, asyncio.Lock] = defaultdict(lambda: asyncio.Lock()) + + log: logging.Logger + loader: PluginLoader | None + client: Client | None + plugin: Plugin | None + config: BaseProxyConfig | None + base_cfg: RecursiveDict[CommentedMap] | None + base_cfg_str: str | None + inst_db: sql.engine.Engine | Database | None + inst_db_tables: dict | None + inst_webapp: PluginWebApp | None + inst_webapp_url: str | None + started: bool + + def __init__( + self, + id: str, + type: str, + enabled: bool, + primary_user: UserID, + config: str = "", + database_engine: DatabaseEngine | None = None, + ) -> None: + super().__init__( + id=id, + type=type, + enabled=bool(enabled), + primary_user=primary_user, + config_str=config, + database_engine=database_engine, + ) + + def __hash__(self) -> int: + return hash(self.id) + + @classmethod + def init_cls(cls, maubot: "Maubot") -> None: + cls.maubot = maubot + + def postinit(self) -> None: + self.log = log.getChild(self.id) + self.cache[self.id] = self + self.config = None + self.started = False + self.loader = None + self.client = None + self.plugin = None + self.inst_db = None + self.inst_db_tables = None + self.inst_webapp = None + self.inst_webapp_url = None + self.base_cfg = None + self.base_cfg_str = None + + def to_dict(self) -> dict: + return { + "id": self.id, + "type": self.type, + "enabled": self.enabled, + "started": self.started, + "primary_user": self.primary_user, + "config": self.config_str, + "base_config": self.base_cfg_str, + "database": ( + self.inst_db is not None and self.maubot.config["api_features.instance_database"] + ), + "database_interface": self.loader.meta.database_type_str if self.loader else "unknown", + "database_engine": self.database_engine_str, + } + + def _introspect_sqlalchemy(self) -> dict: + metadata = MetaData() + metadata.reflect(self.inst_db) + return { + table.name: { + "columns": { + column.name: { + "type": str(column.type), + "unique": column.unique or False, + "default": column.default, + "nullable": column.nullable, + "primary": column.primary_key, + } + for column in table.columns + }, + } + for table in metadata.tables.values() + } + + async def _introspect_sqlite(self) -> dict: + q = """ + SELECT + m.name AS table_name, + p.cid AS col_id, + p.name AS column_name, + p.type AS data_type, + p.pk AS is_primary, + p.dflt_value AS column_default, + p.[notnull] AS is_nullable + FROM sqlite_master m + LEFT JOIN pragma_table_info((m.name)) p + WHERE m.type = 'table' + ORDER BY table_name, col_id + """ + data = await self.inst_db.fetch(q) + tables = defaultdict(lambda: {"columns": {}}) + for column in data: + table_name = column["table_name"] + col_name = column["column_name"] + tables[table_name]["columns"][col_name] = { + "type": column["data_type"], + "nullable": bool(column["is_nullable"]), + "default": column["column_default"], + "primary": bool(column["is_primary"]), + # TODO uniqueness? + } + return tables + + async def _introspect_postgres(self) -> dict: + assert isinstance(self.inst_db, ProxyPostgresDatabase) + q = """ + SELECT col.table_name, col.column_name, col.data_type, col.is_nullable, col.column_default, + tc.constraint_type + FROM information_schema.columns col + LEFT JOIN information_schema.constraint_column_usage ccu + ON ccu.column_name=col.column_name + LEFT JOIN information_schema.table_constraints tc + ON col.table_name=tc.table_name + AND col.table_schema=tc.table_schema + AND ccu.constraint_name=tc.constraint_name + AND ccu.constraint_schema=tc.constraint_schema + AND tc.constraint_type IN ('PRIMARY KEY', 'UNIQUE') + WHERE col.table_schema=$1 + """ + data = await self.inst_db.fetch(q, self.inst_db.schema_name) + tables = defaultdict(lambda: {"columns": {}}) + for column in data: + table_name = column["table_name"] + col_name = column["column_name"] + tables[table_name]["columns"].setdefault( + col_name, + { + "type": column["data_type"], + "nullable": column["is_nullable"], + "default": column["column_default"], + "primary": False, + "unique": False, + }, + ) + if column["constraint_type"] == "PRIMARY KEY": + tables[table_name]["columns"][col_name]["primary"] = True + elif column["constraint_type"] == "UNIQUE": + tables[table_name]["columns"][col_name]["unique"] = True + return tables + + async def get_db_tables(self) -> dict: + if self.inst_db_tables is None: + if isinstance(self.inst_db, Engine): + self.inst_db_tables = self._introspect_sqlalchemy() + elif self.inst_db.scheme == Scheme.SQLITE: + self.inst_db_tables = await self._introspect_sqlite() + else: + self.inst_db_tables = await self._introspect_postgres() + return self.inst_db_tables + + async def load(self) -> bool: + if not self.loader: + try: + self.loader = PluginLoader.find(self.type) + except KeyError: + self.log.error(f"Failed to find loader for type {self.type}") + await self.update_enabled(False) + return False + if not self.client: + self.client = await Client.get(self.primary_user) + if not self.client: + self.log.error(f"Failed to get client for user {self.primary_user}") + await self.update_enabled(False) + return False + if self.loader.meta.webapp: + self.enable_webapp() + self.log.debug("Plugin instance dependencies loaded") + self.loader.references.add(self) + self.client.references.add(self) + return True + + def enable_webapp(self) -> None: + self.inst_webapp, self.inst_webapp_url = self.maubot.server.get_instance_subapp(self.id) + + def disable_webapp(self) -> None: + self.maubot.server.remove_instance_webapp(self.id) + self.inst_webapp = None + self.inst_webapp_url = None + + @property + def _sqlite_db_path(self) -> str: + return os.path.join(self.maubot.config["plugin_databases.sqlite"], f"{self.id}.db") + + async def delete(self) -> None: + if self.loader is not None: + self.loader.references.remove(self) + if self.client is not None: + self.client.references.remove(self) + try: + del self.cache[self.id] + except KeyError: + pass + await super().delete() + if self.inst_db: + await self.stop_database() + await self.delete_database() + if self.inst_webapp: + self.disable_webapp() + + def load_config(self) -> CommentedMap: + return yaml.load(self.config_str) + + def save_config(self, data: RecursiveDict[CommentedMap]) -> None: + buf = io.StringIO() + yaml.dump(data, buf) + val = buf.getvalue() + if val != self.config_str: + self.config_str = val + self.log.debug("Creating background task to save updated config") + background_task.create(self.update()) + + async def start_database( + self, upgrade_table: UpgradeTable | None = None, actually_start: bool = True + ) -> None: + if self.loader.meta.database_type == DatabaseType.SQLALCHEMY: + if self.database_engine is None: + await self.update_db_engine(DatabaseEngine.SQLITE) + elif self.database_engine == DatabaseEngine.POSTGRES: + raise RuntimeError( + "Instance database engine is marked as Postgres, but plugin uses legacy " + "database interface, which doesn't support postgres." + ) + self.inst_db = create_engine(f"sqlite:///{self._sqlite_db_path}") + elif self.loader.meta.database_type == DatabaseType.ASYNCPG: + if self.database_engine is None: + if os.path.exists(self._sqlite_db_path) or not self.maubot.plugin_postgres_db: + await self.update_db_engine(DatabaseEngine.SQLITE) + else: + await self.update_db_engine(DatabaseEngine.POSTGRES) + instance_db_log = db_log.getChild(self.id) + if self.database_engine == DatabaseEngine.POSTGRES: + if not self.maubot.plugin_postgres_db: + raise RuntimeError( + "Instance database engine is marked as Postgres, but this maubot isn't " + "configured to support Postgres for plugin databases" + ) + self.inst_db = ProxyPostgresDatabase( + pool=self.maubot.plugin_postgres_db, + instance_id=self.id, + max_conns=self.maubot.config["plugin_databases.postgres_max_conns_per_plugin"], + upgrade_table=upgrade_table, + log=instance_db_log, + ) + else: + self.inst_db = Database.create( + f"sqlite:{self._sqlite_db_path}", + upgrade_table=upgrade_table, + log=instance_db_log, + ) + if actually_start: + await self.inst_db.start() + else: + raise RuntimeError(f"Unrecognized database type {self.loader.meta.database_type}") + + async def stop_database(self) -> None: + if isinstance(self.inst_db, Database): + await self.inst_db.stop() + elif isinstance(self.inst_db, Engine): + self.inst_db.dispose() + else: + raise RuntimeError(f"Unknown database type {type(self.inst_db).__name__}") + + async def delete_database(self) -> None: + if self.loader.meta.database_type == DatabaseType.SQLALCHEMY: + ZippedPluginLoader.trash(self._sqlite_db_path, reason="deleted") + elif self.loader.meta.database_type == DatabaseType.ASYNCPG: + if self.inst_db is None: + await self.start_database(None, actually_start=False) + if isinstance(self.inst_db, ProxyPostgresDatabase): + await self.inst_db.delete() + else: + ZippedPluginLoader.trash(self._sqlite_db_path, reason="deleted") + else: + raise RuntimeError(f"Unrecognized database type {self.loader.meta.database_type}") + self.inst_db = None + + async def start(self) -> None: + if self.started: + self.log.warning("Ignoring start() call to already started plugin") + return + elif not self.enabled: + self.log.warning("Plugin disabled, not starting.") + return + if not self.client or not self.loader: + self.log.warning("Missing plugin instance dependencies, attempting to load...") + if not await self.load(): + return + cls = await self.loader.load() + if self.loader.meta.webapp and self.inst_webapp is None: + self.log.debug("Enabling webapp after plugin meta reload") + self.enable_webapp() + elif not self.loader.meta.webapp and self.inst_webapp is not None: + self.log.debug("Disabling webapp after plugin meta reload") + self.disable_webapp() + if self.loader.meta.database: + try: + await self.start_database(cls.get_db_upgrade_table()) + except Exception: + self.log.exception("Failed to start instance database") + await self.update_enabled(False) + return + config_class = cls.get_config_class() + if config_class: + try: + base = await self.loader.read_file("base-config.yaml") + self.base_cfg = RecursiveDict(yaml.load(base.decode("utf-8")), CommentedMap) + buf = io.StringIO() + yaml.dump(self.base_cfg._data, buf) + self.base_cfg_str = buf.getvalue() + except (FileNotFoundError, KeyError): + self.base_cfg = None + self.base_cfg_str = None + if self.base_cfg: + base_cfg_func = self.base_cfg.clone + else: + + def base_cfg_func() -> None: + return None + + self.config = config_class(self.load_config, base_cfg_func, self.save_config) + self.plugin = cls( + client=self.client.client, + loop=self.maubot.loop, + http=self.client.http_client, + instance_id=self.id, + log=self.log, + config=self.config, + database=self.inst_db, + loader=self.loader, + webapp=self.inst_webapp, + webapp_url=self.inst_webapp_url, + ) + try: + await self.plugin.internal_start() + except Exception: + self.log.exception("Failed to start instance") + await self.update_enabled(False) + return + self.started = True + self.inst_db_tables = None + self.log.info( + f"Started instance of {self.loader.meta.id} v{self.loader.meta.version} " + f"with user {self.client.id}" + ) + + async def stop(self) -> None: + if not self.started: + self.log.warning("Ignoring stop() call to non-running plugin") + return + self.log.debug("Stopping plugin instance...") + self.started = False + try: + await self.plugin.internal_stop() + except Exception: + self.log.exception("Failed to stop instance") + self.plugin = None + if self.inst_db: + try: + await self.stop_database() + except Exception: + self.log.exception("Failed to stop instance database") + self.inst_db_tables = None + + async def update_id(self, new_id: str | None) -> None: + if new_id is not None and new_id.lower() != self.id: + await super().update_id(new_id.lower()) + + async def update_config(self, config: str | None) -> None: + if config is None or self.config_str == config: + return + self.config_str = config + if self.started and self.plugin is not None: + res = self.plugin.on_external_config_update() + if inspect.isawaitable(res): + await res + await self.update() + + async def update_primary_user(self, primary_user: UserID | None) -> bool: + if primary_user is None or primary_user == self.primary_user: + return True + client = await Client.get(primary_user) + if not client: + return False + await self.stop() + self.primary_user = client.id + if self.client: + self.client.references.remove(self) + self.client = client + self.client.references.add(self) + await self.update() + await self.start() + self.log.debug(f"Primary user switched to {self.client.id}") + return True + + async def update_type(self, type: str | None) -> bool: + if type is None or type == self.type: + return True + try: + loader = PluginLoader.find(type) + except KeyError: + return False + await self.stop() + self.type = loader.meta.id + if self.loader: + self.loader.references.remove(self) + self.loader = loader + self.loader.references.add(self) + await self.update() + await self.start() + self.log.debug(f"Type switched to {self.loader.meta.id}") + return True + + async def update_started(self, started: bool) -> None: + if started is not None and started != self.started: + await (self.start() if started else self.stop()) + + async def update_enabled(self, enabled: bool) -> None: + if enabled is not None and enabled != self.enabled: + self.enabled = enabled + await self.update() + + async def update_db_engine(self, db_engine: DatabaseEngine | None) -> None: + if db_engine is not None and db_engine != self.database_engine: + self.database_engine = db_engine + await self.update() + + @classmethod + @async_getter_lock + async def get( + cls, instance_id: str, *, type: str | None = None, primary_user: UserID | None = None + ) -> PluginInstance | None: + try: + return cls.cache[instance_id] + except KeyError: + pass + + instance = cast(cls, await super().get(instance_id)) + if instance is not None: + instance.postinit() + return instance + + if type and primary_user: + instance = cls(instance_id, type=type, enabled=True, primary_user=primary_user) + await instance.insert() + instance.postinit() + return instance + + return None + + @classmethod + async def all(cls) -> AsyncGenerator[PluginInstance, None]: + instances = await super().all() + instance: PluginInstance + for instance in instances: + try: + yield cls.cache[instance.id] + except KeyError: + instance.postinit() + yield instance diff --git a/maubot-src/maubot/lib/__init__.py b/maubot-src/maubot/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/maubot-src/maubot/lib/color_log.py b/maubot-src/maubot/lib/color_log.py new file mode 100644 index 0000000..8c36ed5 --- /dev/null +++ b/maubot-src/maubot/lib/color_log.py @@ -0,0 +1,49 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from mautrix.util.logging.color import ( + MAU_COLOR, + MXID_COLOR, + PREFIX, + RESET, + ColorFormatter as BaseColorFormatter, +) + +INST_COLOR = PREFIX + "35m" # magenta +LOADER_COLOR = PREFIX + "36m" # blue + + +class ColorFormatter(BaseColorFormatter): + def _color_name(self, module: str) -> str: + client = "maubot.client" + if module.startswith(client + "."): + suffix = "" + if module.endswith(".crypto"): + suffix = f".{MAU_COLOR}crypto{RESET}" + module = module[: -len(".crypto")] + module = module[len(client) + 1 :] + return f"{MAU_COLOR}{client}{RESET}.{MXID_COLOR}{module}{RESET}{suffix}" + instance = "maubot.instance" + if module.startswith(instance + "."): + return f"{MAU_COLOR}{instance}{RESET}.{INST_COLOR}{module[len(instance) + 1:]}{RESET}" + instance_db = "maubot.instance_db" + if module.startswith(instance_db + "."): + return f"{MAU_COLOR}{instance_db}{RESET}.{INST_COLOR}{module[len(instance_db) + 1:]}{RESET}" + loader = "maubot.loader" + if module.startswith(loader + "."): + return f"{MAU_COLOR}{instance}{RESET}.{LOADER_COLOR}{module[len(loader) + 1:]}{RESET}" + if module.startswith("maubot."): + return f"{MAU_COLOR}{module}{RESET}" + return super()._color_name(module) diff --git a/maubot-src/maubot/lib/future_awaitable.py b/maubot-src/maubot/lib/future_awaitable.py new file mode 100644 index 0000000..388eae9 --- /dev/null +++ b/maubot-src/maubot/lib/future_awaitable.py @@ -0,0 +1,9 @@ +from typing import Any, Awaitable, Callable, Generator + + +class FutureAwaitable: + def __init__(self, func: Callable[[], Awaitable[None]]) -> None: + self._func = func + + def __await__(self) -> Generator[Any, None, None]: + return self._func().__await__() diff --git a/maubot-src/maubot/lib/optionalalchemy.py b/maubot-src/maubot/lib/optionalalchemy.py new file mode 100644 index 0000000..ba94271 --- /dev/null +++ b/maubot-src/maubot/lib/optionalalchemy.py @@ -0,0 +1,19 @@ +try: + from sqlalchemy import MetaData, asc, create_engine, desc + from sqlalchemy.engine import Engine + from sqlalchemy.exc import IntegrityError, OperationalError +except ImportError: + + class FakeError(Exception): + pass + + class FakeType: + def __init__(self, *args, **kwargs): + raise Exception("SQLAlchemy is not installed") + + def create_engine(*args, **kwargs): + raise Exception("SQLAlchemy is not installed") + + MetaData = Engine = FakeType + IntegrityError = OperationalError = FakeError + asc = desc = lambda a: a diff --git a/maubot-src/maubot/lib/plugin_db.py b/maubot-src/maubot/lib/plugin_db.py new file mode 100644 index 0000000..af21619 --- /dev/null +++ b/maubot-src/maubot/lib/plugin_db.py @@ -0,0 +1,100 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from contextlib import asynccontextmanager +import asyncio + +from mautrix.util.async_db import Database, PostgresDatabase, Scheme, UpgradeTable +from mautrix.util.async_db.connection import LoggingConnection +from mautrix.util.logging import TraceLogger + +remove_double_quotes = str.maketrans({'"': "_"}) + + +class ProxyPostgresDatabase(Database): + scheme = Scheme.POSTGRES + _underlying_pool: PostgresDatabase + schema_name: str + _quoted_schema: str + _default_search_path: str + _conn_sema: asyncio.Semaphore + _max_conns: int + + def __init__( + self, + pool: PostgresDatabase, + instance_id: str, + max_conns: int, + upgrade_table: UpgradeTable | None, + log: TraceLogger | None = None, + ) -> None: + super().__init__(pool.url, upgrade_table=upgrade_table, log=log) + self._underlying_pool = pool + # Simple accidental SQL injection prevention. + # Doesn't have to be perfect, since plugin instance IDs can only be set by admins anyway. + self.schema_name = f"mbp_{instance_id.translate(remove_double_quotes)}" + self._quoted_schema = f'"{self.schema_name}"' + self._default_search_path = '"$user", public' + self._conn_sema = asyncio.BoundedSemaphore(max_conns) + self._max_conns = max_conns + + async def start(self) -> None: + async with self._underlying_pool.acquire_direct() as conn: + self._default_search_path = await conn.fetchval("SHOW search_path") + self.log.trace(f"Found default search path: {self._default_search_path}") + await conn.execute(f"CREATE SCHEMA IF NOT EXISTS {self._quoted_schema}") + await super().start() + + async def stop(self) -> None: + for _ in range(self._max_conns): + try: + await asyncio.wait_for(self._conn_sema.acquire(), timeout=3) + except asyncio.TimeoutError: + self.log.warning( + "Failed to drain plugin database connection pool, " + "the plugin may be leaking database connections" + ) + break + + async def delete(self) -> None: + self.log.info(f"Deleting schema {self.schema_name} and all data in it") + try: + await self._underlying_pool.execute( + f"DROP SCHEMA IF EXISTS {self._quoted_schema} CASCADE" + ) + except Exception: + self.log.warning("Failed to delete schema", exc_info=True) + + @asynccontextmanager + async def acquire_direct(self) -> LoggingConnection: + conn: LoggingConnection + async with self._conn_sema, self._underlying_pool.acquire_direct() as conn: + await conn.execute(f"SET search_path = {self._quoted_schema}") + try: + yield conn + finally: + if not conn.wrapped.is_closed(): + try: + await conn.execute(f"SET search_path = {self._default_search_path}") + except Exception: + self.log.exception("Error resetting search_path after use") + await conn.wrapped.close() + else: + self.log.debug("Connection was closed after use, not resetting search_path") + + +__all__ = ["ProxyPostgresDatabase"] diff --git a/maubot-src/maubot/lib/state_store.py b/maubot-src/maubot/lib/state_store.py new file mode 100644 index 0000000..81fb5fd --- /dev/null +++ b/maubot-src/maubot/lib/state_store.py @@ -0,0 +1,27 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from mautrix.client.state_store.asyncpg import PgStateStore as BasePgStateStore + +try: + from mautrix.crypto import StateStore as CryptoStateStore + + class PgStateStore(BasePgStateStore, CryptoStateStore): + pass + +except ImportError as e: + PgStateStore = BasePgStateStore + +__all__ = ["PgStateStore"] diff --git a/maubot-src/maubot/lib/zipimport.py b/maubot-src/maubot/lib/zipimport.py new file mode 100644 index 0000000..e7b77db --- /dev/null +++ b/maubot-src/maubot/lib/zipimport.py @@ -0,0 +1,794 @@ +# The pure Python implementation of zipimport in Python 3.8+. Slightly modified to allow clearing +# the zip directory cache to bypass https://bugs.python.org/issue19081 +# +# https://github.com/python/cpython/blob/5a5ce064b3baadcb79605c5a42ee3d0aee57cdfc/Lib/zipimport.py +# See license at https://github.com/python/cpython/blob/master/LICENSE + +"""zipimport provides support for importing Python modules from Zip archives. + +This module exports three objects: +- zipimporter: a class; its constructor takes a path to a Zip archive. +- ZipImportError: exception raised by zipimporter objects. It's a + subclass of ImportError, so it can be caught as ImportError, too. +- _zip_directory_cache: a dict, mapping archive paths to zip directory + info dicts, as used in zipimporter._files. + +It is usually not needed to use the zipimport module explicitly; it is +used by the builtin import mechanism for sys.path items that are paths +to Zip archives. +""" + +from importlib import _bootstrap # for _verbose_message +from importlib import _bootstrap_external +import marshal # for loads +import sys # for modules +import time # for mktime + +import _imp # for check_hash_based_pycs +import _io # for open + +__all__ = ["ZipImportError", "zipimporter"] + + +def _unpack_uint32(data): + """Convert 4 bytes in little-endian to an integer.""" + assert len(data) == 4 + return int.from_bytes(data, "little") + + +def _unpack_uint16(data): + """Convert 2 bytes in little-endian to an integer.""" + assert len(data) == 2 + return int.from_bytes(data, "little") + + +path_sep = _bootstrap_external.path_sep +alt_path_sep = _bootstrap_external.path_separators[1:] + + +class ZipImportError(ImportError): + pass + + +# _read_directory() cache +_zip_directory_cache = {} + +_module_type = type(sys) + +END_CENTRAL_DIR_SIZE = 22 +STRING_END_ARCHIVE = b"PK\x05\x06" +MAX_COMMENT_LEN = (1 << 16) - 1 + + +class zipimporter: + """zipimporter(archivepath) -> zipimporter object + + Create a new zipimporter instance. 'archivepath' must be a path to + a zipfile, or to a specific path inside a zipfile. For example, it can be + '/tmp/myimport.zip', or '/tmp/myimport.zip/mydirectory', if mydirectory is a + valid directory inside the archive. + + 'ZipImportError is raised if 'archivepath' doesn't point to a valid Zip + archive. + + The 'archive' attribute of zipimporter objects contains the name of the + zipfile targeted. + """ + + # Split the "subdirectory" from the Zip archive path, lookup a matching + # entry in sys.path_importer_cache, fetch the file directory from there + # if found, or else read it from the archive. + def __init__(self, path): + if not isinstance(path, str): + import os + + path = os.fsdecode(path) + if not path: + raise ZipImportError("archive path is empty", path=path) + if alt_path_sep: + path = path.replace(alt_path_sep, path_sep) + + prefix = [] + while True: + try: + st = _bootstrap_external._path_stat(path) + except (OSError, ValueError): + # On Windows a ValueError is raised for too long paths. + # Back up one path element. + dirname, basename = _bootstrap_external._path_split(path) + if dirname == path: + raise ZipImportError("not a Zip file", path=path) + path = dirname + prefix.append(basename) + else: + # it exists + if (st.st_mode & 0o170000) != 0o100000: # stat.S_ISREG + # it's a not file + raise ZipImportError("not a Zip file", path=path) + break + + try: + files = _zip_directory_cache[path] + except KeyError: + files = _read_directory(path) + _zip_directory_cache[path] = files + self._files = files + self.archive = path + # a prefix directory following the ZIP file path. + self.prefix = _bootstrap_external._path_join(*prefix[::-1]) + if self.prefix: + self.prefix += path_sep + + def reset_cache(self): + self._files = _read_directory(self.archive) + _zip_directory_cache[self.archive] = self._files + + def remove_cache(self): + try: + del _zip_directory_cache[self.archive] + except KeyError: + pass + + # Check whether we can satisfy the import of the module named by + # 'fullname', or whether it could be a portion of a namespace + # package. Return self if we can load it, a string containing the + # full path if it's a possible namespace portion, None if we + # can't load it. + def find_loader(self, fullname, path=None): + """find_loader(fullname, path=None) -> self, str or None. + + Search for a module specified by 'fullname'. 'fullname' must be the + fully qualified (dotted) module name. It returns the zipimporter + instance itself if the module was found, a string containing the + full path name if it's possibly a portion of a namespace package, + or None otherwise. The optional 'path' argument is ignored -- it's + there for compatibility with the importer protocol. + """ + mi = _get_module_info(self, fullname) + if mi is not None: + # This is a module or package. + return self, [] + + # Not a module or regular package. See if this is a directory, and + # therefore possibly a portion of a namespace package. + + # We're only interested in the last path component of fullname + # earlier components are recorded in self.prefix. + modpath = _get_module_path(self, fullname) + if _is_dir(self, modpath): + # This is possibly a portion of a namespace + # package. Return the string representing its path, + # without a trailing separator. + return None, [f"{self.archive}{path_sep}{modpath}"] + + return None, [] + + # Check whether we can satisfy the import of the module named by + # 'fullname'. Return self if we can, None if we can't. + def find_module(self, fullname, path=None): + """find_module(fullname, path=None) -> self or None. + + Search for a module specified by 'fullname'. 'fullname' must be the + fully qualified (dotted) module name. It returns the zipimporter + instance itself if the module was found, or None if it wasn't. + The optional 'path' argument is ignored -- it's there for compatibility + with the importer protocol. + """ + return self.find_loader(fullname, path)[0] + + def get_code(self, fullname): + """get_code(fullname) -> code object. + + Return the code object for the specified module. Raise ZipImportError + if the module couldn't be found. + """ + code, ispackage, modpath = _get_module_code(self, fullname) + return code + + def get_data(self, pathname): + """get_data(pathname) -> string with file data. + + Return the data associated with 'pathname'. Raise OSError if + the file wasn't found. + """ + if alt_path_sep: + pathname = pathname.replace(alt_path_sep, path_sep) + + key = pathname + if pathname.startswith(self.archive + path_sep): + key = pathname[len(self.archive + path_sep) :] + + try: + toc_entry = self._files[key] + except KeyError: + raise OSError(0, "", key) + return _get_data(self.archive, toc_entry) + + # Return a string matching __file__ for the named module + def get_filename(self, fullname): + """get_filename(fullname) -> filename string. + + Return the filename for the specified module. + """ + # Deciding the filename requires working out where the code + # would come from if the module was actually loaded + code, ispackage, modpath = _get_module_code(self, fullname) + return modpath + + def get_source(self, fullname): + """get_source(fullname) -> source string. + + Return the source code for the specified module. Raise ZipImportError + if the module couldn't be found, return None if the archive does + contain the module, but has no source for it. + """ + mi = _get_module_info(self, fullname) + if mi is None: + raise ZipImportError(f"can't find module {fullname!r}", name=fullname) + + path = _get_module_path(self, fullname) + if mi: + fullpath = _bootstrap_external._path_join(path, "__init__.py") + else: + fullpath = f"{path}.py" + + try: + toc_entry = self._files[fullpath] + except KeyError: + # we have the module, but no source + return None + return _get_data(self.archive, toc_entry).decode() + + # Return a bool signifying whether the module is a package or not. + def is_package(self, fullname): + """is_package(fullname) -> bool. + + Return True if the module specified by fullname is a package. + Raise ZipImportError if the module couldn't be found. + """ + mi = _get_module_info(self, fullname) + if mi is None: + raise ZipImportError(f"can't find module {fullname!r}", name=fullname) + return mi + + # Load and return the module named by 'fullname'. + def load_module(self, fullname): + """load_module(fullname) -> module. + + Load the module specified by 'fullname'. 'fullname' must be the + fully qualified (dotted) module name. It returns the imported + module, or raises ZipImportError if it wasn't found. + """ + code, ispackage, modpath = _get_module_code(self, fullname) + mod = sys.modules.get(fullname) + if mod is None or not isinstance(mod, _module_type): + mod = _module_type(fullname) + sys.modules[fullname] = mod + mod.__loader__ = self + + try: + if ispackage: + # add __path__ to the module *before* the code gets + # executed + path = _get_module_path(self, fullname) + fullpath = _bootstrap_external._path_join(self.archive, path) + mod.__path__ = [fullpath] + + if not hasattr(mod, "__builtins__"): + mod.__builtins__ = __builtins__ + _bootstrap_external._fix_up_module(mod.__dict__, fullname, modpath) + exec(code, mod.__dict__) + except: + del sys.modules[fullname] + raise + + try: + mod = sys.modules[fullname] + except KeyError: + raise ImportError(f"Loaded module {fullname!r} not found in sys.modules") + _bootstrap._verbose_message("import {} # loaded from Zip {}", fullname, modpath) + return mod + + def get_resource_reader(self, fullname): + """Return the ResourceReader for a package in a zip file. + + If 'fullname' is a package within the zip file, return the + 'ResourceReader' object for the package. Otherwise return None. + """ + try: + if not self.is_package(fullname): + return None + except ZipImportError: + return None + if not _ZipImportResourceReader._registered: + from importlib.abc import ResourceReader + + ResourceReader.register(_ZipImportResourceReader) + _ZipImportResourceReader._registered = True + return _ZipImportResourceReader(self, fullname) + + def __repr__(self): + return f'' + + +# _zip_searchorder defines how we search for a module in the Zip +# archive: we first search for a package __init__, then for +# non-package .pyc, and .py entries. The .pyc entries +# are swapped by initzipimport() if we run in optimized mode. Also, +# '/' is replaced by path_sep there. +_zip_searchorder = ( + (path_sep + "__init__.pyc", True, True), + (path_sep + "__init__.py", False, True), + (".pyc", True, False), + (".py", False, False), +) + + +# Given a module name, return the potential file path in the +# archive (without extension). +def _get_module_path(self, fullname): + return self.prefix + fullname.rpartition(".")[2] + + +# Does this path represent a directory? +def _is_dir(self, path): + # See if this is a "directory". If so, it's eligible to be part + # of a namespace package. We test by seeing if the name, with an + # appended path separator, exists. + dirpath = path + path_sep + # If dirpath is present in self._files, we have a directory. + return dirpath in self._files + + +# Return some information about a module. +def _get_module_info(self, fullname): + path = _get_module_path(self, fullname) + for suffix, isbytecode, ispackage in _zip_searchorder: + fullpath = path + suffix + if fullpath in self._files: + return ispackage + return None + + +# implementation + + +# _read_directory(archive) -> files dict (new reference) +# +# Given a path to a Zip archive, build a dict, mapping file names +# (local to the archive, using SEP as a separator) to toc entries. +# +# A toc_entry is a tuple: +# +# (__file__, # value to use for __file__, available for all files, +# # encoded to the filesystem encoding +# compress, # compression kind; 0 for uncompressed +# data_size, # size of compressed data on disk +# file_size, # size of decompressed data +# file_offset, # offset of file header from start of archive +# time, # mod time of file (in dos format) +# date, # mod data of file (in dos format) +# crc, # crc checksum of the data +# ) +# +# Directories can be recognized by the trailing path_sep in the name, +# data_size and file_offset are 0. +def _read_directory(archive): + try: + fp = _io.open(archive, "rb") + except OSError: + raise ZipImportError(f"can't open Zip file: {archive!r}", path=archive) + + with fp: + try: + fp.seek(-END_CENTRAL_DIR_SIZE, 2) + header_position = fp.tell() + buffer = fp.read(END_CENTRAL_DIR_SIZE) + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + if len(buffer) != END_CENTRAL_DIR_SIZE: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + if buffer[:4] != STRING_END_ARCHIVE: + # Bad: End of Central Dir signature + # Check if there's a comment. + try: + fp.seek(0, 2) + file_size = fp.tell() + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + max_comment_start = max(file_size - MAX_COMMENT_LEN - END_CENTRAL_DIR_SIZE, 0) + try: + fp.seek(max_comment_start) + data = fp.read() + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + pos = data.rfind(STRING_END_ARCHIVE) + if pos < 0: + raise ZipImportError(f"not a Zip file: {archive!r}", path=archive) + buffer = data[pos : pos + END_CENTRAL_DIR_SIZE] + if len(buffer) != END_CENTRAL_DIR_SIZE: + raise ZipImportError(f"corrupt Zip file: {archive!r}", path=archive) + header_position = file_size - len(data) + pos + + header_size = _unpack_uint32(buffer[12:16]) + header_offset = _unpack_uint32(buffer[16:20]) + if header_position < header_size: + raise ZipImportError(f"bad central directory size: {archive!r}", path=archive) + if header_position < header_offset: + raise ZipImportError(f"bad central directory offset: {archive!r}", path=archive) + header_position -= header_size + arc_offset = header_position - header_offset + if arc_offset < 0: + raise ZipImportError( + f"bad central directory size or offset: {archive!r}", path=archive + ) + + files = {} + # Start of Central Directory + count = 0 + try: + fp.seek(header_position) + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + while True: + buffer = fp.read(46) + if len(buffer) < 4: + raise EOFError("EOF read where not expected") + # Start of file header + if buffer[:4] != b"PK\x01\x02": + break # Bad: Central Dir File Header + if len(buffer) != 46: + raise EOFError("EOF read where not expected") + flags = _unpack_uint16(buffer[8:10]) + compress = _unpack_uint16(buffer[10:12]) + time = _unpack_uint16(buffer[12:14]) + date = _unpack_uint16(buffer[14:16]) + crc = _unpack_uint32(buffer[16:20]) + data_size = _unpack_uint32(buffer[20:24]) + file_size = _unpack_uint32(buffer[24:28]) + name_size = _unpack_uint16(buffer[28:30]) + extra_size = _unpack_uint16(buffer[30:32]) + comment_size = _unpack_uint16(buffer[32:34]) + file_offset = _unpack_uint32(buffer[42:46]) + header_size = name_size + extra_size + comment_size + if file_offset > header_offset: + raise ZipImportError(f"bad local header offset: {archive!r}", path=archive) + file_offset += arc_offset + + try: + name = fp.read(name_size) + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + if len(name) != name_size: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + # On Windows, calling fseek to skip over the fields we don't use is + # slower than reading the data because fseek flushes stdio's + # internal buffers. See issue #8745. + try: + if len(fp.read(header_size - name_size)) != header_size - name_size: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + + if flags & 0x800: + # UTF-8 file names extension + name = name.decode() + else: + # Historical ZIP filename encoding + try: + name = name.decode("ascii") + except UnicodeDecodeError: + name = name.decode("latin1").translate(cp437_table) + + name = name.replace("/", path_sep) + path = _bootstrap_external._path_join(archive, name) + t = (path, compress, data_size, file_size, file_offset, time, date, crc) + files[name] = t + count += 1 + _bootstrap._verbose_message("zipimport: found {} names in {!r}", count, archive) + return files + + +# During bootstrap, we may need to load the encodings +# package from a ZIP file. But the cp437 encoding is implemented +# in Python in the encodings package. +# +# Break out of this dependency by using the translation table for +# the cp437 encoding. +cp437_table = ( + # ASCII part, 8 rows x 16 chars + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + " !\"#$%&'()*+,-./" + "0123456789:;<=>?" + "@ABCDEFGHIJKLMNO" + "PQRSTUVWXYZ[\\]^_" + "`abcdefghijklmno" + "pqrstuvwxyz{|}~\x7f" + # non-ASCII part, 16 rows x 8 chars + "\xc7\xfc\xe9\xe2\xe4\xe0\xe5\xe7" + "\xea\xeb\xe8\xef\xee\xec\xc4\xc5" + "\xc9\xe6\xc6\xf4\xf6\xf2\xfb\xf9" + "\xff\xd6\xdc\xa2\xa3\xa5\u20a7\u0192" + "\xe1\xed\xf3\xfa\xf1\xd1\xaa\xba" + "\xbf\u2310\xac\xbd\xbc\xa1\xab\xbb" + "\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556" + "\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510" + "\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f" + "\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567" + "\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b" + "\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580" + "\u03b1\xdf\u0393\u03c0\u03a3\u03c3\xb5\u03c4" + "\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229" + "\u2261\xb1\u2265\u2264\u2320\u2321\xf7\u2248" + "\xb0\u2219\xb7\u221a\u207f\xb2\u25a0\xa0" +) + +_importing_zlib = False + + +# Return the zlib.decompress function object, or NULL if zlib couldn't +# be imported. The function is cached when found, so subsequent calls +# don't import zlib again. +def _get_decompress_func(): + global _importing_zlib + if _importing_zlib: + # Someone has a zlib.py[co] in their Zip file + # let's avoid a stack overflow. + _bootstrap._verbose_message("zipimport: zlib UNAVAILABLE") + raise ZipImportError("can't decompress data; zlib not available") + + _importing_zlib = True + try: + from zlib import decompress + except Exception: + _bootstrap._verbose_message("zipimport: zlib UNAVAILABLE") + raise ZipImportError("can't decompress data; zlib not available") + finally: + _importing_zlib = False + + _bootstrap._verbose_message("zipimport: zlib available") + return decompress + + +# Given a path to a Zip file and a toc_entry, return the (uncompressed) data. +def _get_data(archive, toc_entry): + datapath, compress, data_size, file_size, file_offset, time, date, crc = toc_entry + if data_size < 0: + raise ZipImportError("negative data size") + + with _io.open(archive, "rb") as fp: + # Check to make sure the local file header is correct + try: + fp.seek(file_offset) + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + buffer = fp.read(30) + if len(buffer) != 30: + raise EOFError("EOF read where not expected") + + if buffer[:4] != b"PK\x03\x04": + # Bad: Local File Header + raise ZipImportError(f"bad local file header: {archive!r}", path=archive) + + name_size = _unpack_uint16(buffer[26:28]) + extra_size = _unpack_uint16(buffer[28:30]) + header_size = 30 + name_size + extra_size + file_offset += header_size # Start of file data + try: + fp.seek(file_offset) + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + raw_data = fp.read(data_size) + if len(raw_data) != data_size: + raise OSError("zipimport: can't read data") + + if compress == 0: + # data is not compressed + return raw_data + + # Decompress with zlib + try: + decompress = _get_decompress_func() + except Exception: + raise ZipImportError("can't decompress data; zlib not available") + return decompress(raw_data, -15) + + +# Lenient date/time comparison function. The precision of the mtime +# in the archive is lower than the mtime stored in a .pyc: we +# must allow a difference of at most one second. +def _eq_mtime(t1, t2): + # dostime only stores even seconds, so be lenient + return abs(t1 - t2) <= 1 + + +# Given the contents of a .py[co] file, unmarshal the data +# and return the code object. Return None if it the magic word doesn't +# match (we do this instead of raising an exception as we fall back +# to .py if available and we don't want to mask other errors). +def _unmarshal_code(pathname, data, mtime): + if len(data) < 16: + raise ZipImportError("bad pyc data") + + if data[:4] != _bootstrap_external.MAGIC_NUMBER: + _bootstrap._verbose_message("{!r} has bad magic", pathname) + return None # signal caller to try alternative + + flags = _unpack_uint32(data[4:8]) + if flags != 0: + # Hash-based pyc. We currently refuse to handle checked hash-based + # pycs. We could validate hash-based pycs against the source, but it + # seems likely that most people putting hash-based pycs in a zipfile + # will use unchecked ones. + if _imp.check_hash_based_pycs != "never" and ( + flags != 0x1 or _imp.check_hash_based_pycs == "always" + ): + return None + elif mtime != 0 and not _eq_mtime(_unpack_uint32(data[8:12]), mtime): + _bootstrap._verbose_message("{!r} has bad mtime", pathname) + return None # signal caller to try alternative + + # XXX the pyc's size field is ignored; timestamp collisions are probably + # unimportant with zip files. + code = marshal.loads(data[16:]) + if not isinstance(code, _code_type): + raise TypeError(f"compiled module {pathname!r} is not a code object") + return code + + +_code_type = type(_unmarshal_code.__code__) + + +# Replace any occurrences of '\r\n?' in the input string with '\n'. +# This converts DOS and Mac line endings to Unix line endings. +def _normalize_line_endings(source): + source = source.replace(b"\r\n", b"\n") + source = source.replace(b"\r", b"\n") + return source + + +# Given a string buffer containing Python source code, compile it +# and return a code object. +def _compile_source(pathname, source): + source = _normalize_line_endings(source) + return compile(source, pathname, "exec", dont_inherit=True) + + +# Convert the date/time values found in the Zip archive to a value +# that's compatible with the time stamp stored in .pyc files. +def _parse_dostime(d, t): + return time.mktime( + ( + (d >> 9) + 1980, # bits 9..15: year + (d >> 5) & 0xF, # bits 5..8: month + d & 0x1F, # bits 0..4: day + t >> 11, # bits 11..15: hours + (t >> 5) & 0x3F, # bits 8..10: minutes + (t & 0x1F) * 2, # bits 0..7: seconds / 2 + -1, + -1, + -1, + ) + ) + + +# Given a path to a .pyc file in the archive, return the +# modification time of the matching .py file, or 0 if no source +# is available. +def _get_mtime_of_source(self, path): + try: + # strip 'c' or 'o' from *.py[co] + assert path[-1:] in ("c", "o") + path = path[:-1] + toc_entry = self._files[path] + # fetch the time stamp of the .py file for comparison + # with an embedded pyc time stamp + time = toc_entry[5] + date = toc_entry[6] + return _parse_dostime(date, time) + except (KeyError, IndexError, TypeError): + return 0 + + +# Get the code object associated with the module specified by +# 'fullname'. +def _get_module_code(self, fullname): + path = _get_module_path(self, fullname) + for suffix, isbytecode, ispackage in _zip_searchorder: + fullpath = path + suffix + _bootstrap._verbose_message("trying {}{}{}", self.archive, path_sep, fullpath, verbosity=2) + try: + toc_entry = self._files[fullpath] + except KeyError: + pass + else: + modpath = toc_entry[0] + data = _get_data(self.archive, toc_entry) + if isbytecode: + mtime = _get_mtime_of_source(self, fullpath) + code = _unmarshal_code(modpath, data, mtime) + else: + code = _compile_source(modpath, data) + if code is None: + # bad magic number or non-matching mtime + # in byte code, try next + continue + modpath = toc_entry[0] + return code, ispackage, modpath + else: + raise ZipImportError(f"can't find module {fullname!r}", name=fullname) + + +class _ZipImportResourceReader: + """Private class used to support ZipImport.get_resource_reader(). + + This class is allowed to reference all the innards and private parts of + the zipimporter. + """ + + _registered = False + + def __init__(self, zipimporter, fullname): + self.zipimporter = zipimporter + self.fullname = fullname + + def open_resource(self, resource): + fullname_as_path = self.fullname.replace(".", "/") + path = f"{fullname_as_path}/{resource}" + from io import BytesIO + + try: + return BytesIO(self.zipimporter.get_data(path)) + except OSError: + raise FileNotFoundError(path) + + def resource_path(self, resource): + # All resources are in the zip file, so there is no path to the file. + # Raising FileNotFoundError tells the higher level API to extract the + # binary data and create a temporary file. + raise FileNotFoundError + + def is_resource(self, name): + # Maybe we could do better, but if we can get the data, it's a + # resource. Otherwise it isn't. + fullname_as_path = self.fullname.replace(".", "/") + path = f"{fullname_as_path}/{name}" + try: + self.zipimporter.get_data(path) + except OSError: + return False + return True + + def contents(self): + # This is a bit convoluted, because fullname will be a module path, + # but _files is a list of file names relative to the top of the + # archive's namespace. We want to compare file paths to find all the + # names of things inside the module represented by fullname. So we + # turn the module path of fullname into a file path relative to the + # top of the archive, and then we iterate through _files looking for + # names inside that "directory". + from pathlib import Path + + fullname_path = Path(self.zipimporter.get_filename(self.fullname)) + relative_path = fullname_path.relative_to(self.zipimporter.archive) + # Don't forget that fullname names a package, so its path will include + # __init__.py, which we want to ignore. + assert relative_path.name == "__init__.py" + package_path = relative_path.parent + subdirs_seen = set() + for filename in self.zipimporter._files: + try: + relative = Path(filename).relative_to(package_path) + except ValueError: + continue + # If the path of the file (which is relative to the top of the zip + # namespace), relative to the package given when the resource + # reader was created, has a parent, then it's a name in a + # subdirectory and thus we skip it. + parent_name = relative.parent.name + if len(parent_name) == 0: + yield relative.name + elif parent_name not in subdirs_seen: + subdirs_seen.add(parent_name) + yield parent_name diff --git a/maubot-src/maubot/loader/__init__.py b/maubot-src/maubot/loader/__init__.py new file mode 100644 index 0000000..d61be5c --- /dev/null +++ b/maubot-src/maubot/loader/__init__.py @@ -0,0 +1,3 @@ +from .abc import BasePluginLoader, IDConflictError, PluginClass, PluginLoader +from .meta import DatabaseType, PluginMeta +from .zip import MaubotZipImportError, ZippedPluginLoader diff --git a/maubot-src/maubot/loader/abc.py b/maubot-src/maubot/loader/abc.py new file mode 100644 index 0000000..c2c71b2 --- /dev/null +++ b/maubot-src/maubot/loader/abc.py @@ -0,0 +1,98 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import TYPE_CHECKING, TypeVar +from abc import ABC, abstractmethod +import asyncio + +from ..plugin_base import Plugin +from .meta import PluginMeta + +if TYPE_CHECKING: + from ..instance import PluginInstance + +PluginClass = TypeVar("PluginClass", bound=Plugin) + + +class IDConflictError(Exception): + pass + + +class BasePluginLoader(ABC): + meta: PluginMeta + + @property + @abstractmethod + def source(self) -> str: + pass + + def sync_read_file(self, path: str) -> bytes: + raise NotImplementedError("This loader doesn't support synchronous operations") + + @abstractmethod + async def read_file(self, path: str) -> bytes: + pass + + def sync_list_files(self, directory: str) -> list[str]: + raise NotImplementedError("This loader doesn't support synchronous operations") + + @abstractmethod + async def list_files(self, directory: str) -> list[str]: + pass + + +class PluginLoader(BasePluginLoader, ABC): + id_cache: dict[str, PluginLoader] = {} + + meta: PluginMeta + references: set[PluginInstance] + + def __init__(self): + self.references = set() + + @classmethod + def find(cls, plugin_id: str) -> PluginLoader: + return cls.id_cache[plugin_id] + + def to_dict(self) -> dict: + return { + "id": self.meta.id, + "version": str(self.meta.version), + "instances": [instance.to_dict() for instance in self.references], + } + + async def stop_instances(self) -> None: + await asyncio.gather( + *[instance.stop() for instance in self.references if instance.started] + ) + + async def start_instances(self) -> None: + await asyncio.gather( + *[instance.start() for instance in self.references if instance.enabled] + ) + + @abstractmethod + async def load(self) -> type[PluginClass]: + pass + + @abstractmethod + async def reload(self) -> type[PluginClass]: + pass + + @abstractmethod + async def delete(self) -> None: + pass diff --git a/maubot-src/maubot/loader/meta.py b/maubot-src/maubot/loader/meta.py new file mode 100644 index 0000000..d368e24 --- /dev/null +++ b/maubot-src/maubot/loader/meta.py @@ -0,0 +1,69 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from typing import List, Optional + +from attr import dataclass +from packaging.version import InvalidVersion, Version + +from mautrix.types import ( + ExtensibleEnum, + SerializableAttrs, + SerializerError, + deserializer, + serializer, +) + +from ..__meta__ import __version__ + + +@serializer(Version) +def serialize_version(version: Version) -> str: + return str(version) + + +@deserializer(Version) +def deserialize_version(version: str) -> Version: + try: + return Version(version) + except InvalidVersion as e: + raise SerializerError("Invalid version") from e + + +class DatabaseType(ExtensibleEnum): + SQLALCHEMY = "sqlalchemy" + ASYNCPG = "asyncpg" + + +@dataclass +class PluginMeta(SerializableAttrs): + id: str + version: Version + modules: List[str] + main_class: str + + maubot: Version = Version(__version__) + database: bool = False + database_type: DatabaseType = DatabaseType.SQLALCHEMY + config: bool = False + webapp: bool = False + license: str = "" + extra_files: List[str] = [] + dependencies: List[str] = [] + soft_dependencies: List[str] = [] + + @property + def database_type_str(self) -> Optional[str]: + return self.database_type.value if self.database else None diff --git a/maubot-src/maubot/loader/zip.py b/maubot-src/maubot/loader/zip.py new file mode 100644 index 0000000..8642183 --- /dev/null +++ b/maubot-src/maubot/loader/zip.py @@ -0,0 +1,310 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from time import time +from zipfile import BadZipFile, ZipFile +import logging +import os +import sys + +from packaging.version import Version +from ruamel.yaml import YAML, YAMLError + +from mautrix.types import SerializerError + +from ..__meta__ import __version__ +from ..config import Config +from ..lib.zipimport import ZipImportError, zipimporter +from ..plugin_base import Plugin +from .abc import IDConflictError, PluginClass, PluginLoader +from .meta import DatabaseType, PluginMeta + +current_version = Version(__version__) +yaml = YAML() + + +class MaubotZipImportError(Exception): + pass + + +class MaubotZipMetaError(MaubotZipImportError): + pass + + +class MaubotZipPreLoadError(MaubotZipImportError): + pass + + +class MaubotZipLoadError(MaubotZipImportError): + pass + + +class ZippedPluginLoader(PluginLoader): + path_cache: dict[str, ZippedPluginLoader] = {} + log: logging.Logger = logging.getLogger("maubot.loader.zip") + trash_path: str = "delete" + directories: list[str] = [] + + path: str | None + meta: PluginMeta | None + main_class: str | None + main_module: str | None + _loaded: type[PluginClass] | None + _importer: zipimporter | None + _file: ZipFile | None + + def __init__(self, path: str) -> None: + super().__init__() + self.path = path + self.meta = None + self.main_class = None + self.main_module = None + self._loaded = None + self._importer = None + self._file = None + self._load_meta() + self._run_preload_checks(self._get_importer()) + try: + existing = self.id_cache[self.meta.id] + raise IDConflictError( + f"Plugin with id {self.meta.id} already loaded from {existing.source}" + ) + except KeyError: + pass + self.path_cache[self.path] = self + self.id_cache[self.meta.id] = self + self.log.debug(f"Preloaded plugin {self.meta.id} from {self.path}") + + def to_dict(self) -> dict: + return {**super().to_dict(), "path": self.path} + + @classmethod + def get(cls, path: str) -> ZippedPluginLoader: + path = os.path.abspath(path) + try: + return cls.path_cache[path] + except KeyError: + return cls(path) + + @property + def source(self) -> str: + return self.path + + def __repr__(self) -> str: + return ( + "" + ) + + def sync_read_file(self, path: str) -> bytes: + return self._file.read(path) + + async def read_file(self, path: str) -> bytes: + return self.sync_read_file(path) + + def sync_list_files(self, directory: str) -> list[str]: + directory = directory.rstrip("/") + return [ + file.filename + for file in self._file.filelist + if os.path.dirname(file.filename) == directory + ] + + async def list_files(self, directory: str) -> list[str]: + return self.sync_list_files(directory) + + @staticmethod + def _read_meta(source) -> tuple[ZipFile, PluginMeta]: + try: + file = ZipFile(source) + data = file.read("maubot.yaml") + except FileNotFoundError as e: + raise MaubotZipMetaError("Maubot plugin not found") from e + except BadZipFile as e: + raise MaubotZipMetaError("File is not a maubot plugin") from e + except KeyError as e: + raise MaubotZipMetaError("File does not contain a maubot plugin definition") from e + try: + meta_dict = yaml.load(data) + except (YAMLError, KeyError, IndexError, ValueError) as e: + raise MaubotZipMetaError("Maubot plugin definition file is not valid YAML") from e + try: + meta = PluginMeta.deserialize(meta_dict) + except SerializerError as e: + raise MaubotZipMetaError("Maubot plugin definition in file is invalid") from e + if meta.maubot > current_version: + raise MaubotZipMetaError( + f"Plugin requires maubot {meta.maubot}, but this instance is {current_version}" + ) + return file, meta + + @classmethod + def verify_meta(cls, source) -> tuple[str, Version, DatabaseType | None]: + _, meta = cls._read_meta(source) + return meta.id, meta.version, meta.database_type if meta.database else None + + def _load_meta(self) -> None: + file, meta = self._read_meta(self.path) + if self.meta and meta.id != self.meta.id: + raise MaubotZipMetaError("Maubot plugin ID changed during reload") + self.meta = meta + if "/" in meta.main_class: + self.main_module, self.main_class = meta.main_class.split("/")[:2] + else: + self.main_module = meta.modules[-1] + self.main_class = meta.main_class + self._file = file + + def _get_importer(self, reset_cache: bool = False) -> zipimporter: + try: + if not self._importer or self._importer.archive != self.path: + self._importer = zipimporter(self.path) + if reset_cache: + self._importer.reset_cache() + return self._importer + except ZipImportError as e: + raise MaubotZipMetaError("File not found or not a maubot plugin") from e + + def _run_preload_checks(self, importer: zipimporter) -> None: + try: + code = importer.get_code(self.main_module.replace(".", "/")) + if self.main_class not in code.co_names: + raise MaubotZipPreLoadError( + f"Main class {self.main_class} not in {self.main_module}" + ) + except ZipImportError as e: + raise MaubotZipPreLoadError(f"Main module {self.main_module} not found in file") from e + for module in self.meta.modules: + try: + importer.find_module(module) + except ZipImportError as e: + raise MaubotZipPreLoadError(f"Module {module} not found in file") from e + + async def load(self, reset_cache: bool = False) -> type[PluginClass]: + try: + return self._load(reset_cache) + except MaubotZipImportError: + self.log.exception(f"Failed to load {self.meta.id} v{self.meta.version}") + raise + + def _load(self, reset_cache: bool = False) -> type[PluginClass]: + if self._loaded is not None and not reset_cache: + return self._loaded + self._load_meta() + importer = self._get_importer(reset_cache=reset_cache) + self._run_preload_checks(importer) + if reset_cache: + self.log.debug(f"Re-preloaded plugin {self.meta.id} from {self.path}") + for module in self.meta.modules: + try: + importer.load_module(module) + except ZipImportError: + raise MaubotZipLoadError(f"Module {module} not found in file") + except Exception: + raise MaubotZipLoadError(f"Failed to load module {module}") + try: + main_mod = sys.modules[self.main_module] + except KeyError as e: + raise MaubotZipLoadError(f"Main module {self.main_module} of plugin not found") from e + try: + plugin = getattr(main_mod, self.main_class) + except AttributeError as e: + raise MaubotZipLoadError(f"Main class {self.main_class} of plugin not found") from e + if not issubclass(plugin, Plugin): + raise MaubotZipLoadError("Main class of plugin does not extend maubot.Plugin") + self._loaded = plugin + self.log.debug(f"Loaded and imported plugin {self.meta.id} from {self.path}") + return plugin + + async def reload(self, new_path: str | None = None) -> type[PluginClass]: + self._unload() + if new_path is not None and new_path != self.path: + try: + del self.path_cache[self.path] + except KeyError: + pass + self.path = new_path + self.path_cache[self.path] = self + return await self.load(reset_cache=True) + + def _unload(self) -> None: + for name, mod in list(sys.modules.items()): + if (getattr(mod, "__file__", "") or "").startswith(self.path): + del sys.modules[name] + self._loaded = None + self.log.debug(f"Unloaded plugin {self.meta.id} at {self.path}") + + async def delete(self) -> None: + self._unload() + try: + del self.path_cache[self.path] + except KeyError: + pass + try: + del self.id_cache[self.meta.id] + except KeyError: + pass + if self._importer: + self._importer.remove_cache() + self._importer = None + self._loaded = None + self.trash(self.path, reason="delete") + self.meta = None + self.path = None + + @classmethod + def trash(cls, file_path: str, new_name: str | None = None, reason: str = "error") -> None: + if cls.trash_path == "delete": + try: + os.remove(file_path) + except FileNotFoundError: + pass + else: + new_name = new_name or f"{int(time())}-{reason}-{os.path.basename(file_path)}" + try: + os.rename(file_path, os.path.abspath(os.path.join(cls.trash_path, new_name))) + except OSError as e: + cls.log.warning(f"Failed to rename {file_path}: {e} - trying to delete") + try: + os.remove(file_path) + except FileNotFoundError: + pass + + @classmethod + def load_all(cls): + cls.log.debug("Preloading plugins...") + for directory in cls.directories: + for file in os.listdir(directory): + if not file.endswith(".mbp"): + continue + path = os.path.abspath(os.path.join(directory, file)) + try: + cls.get(path) + except MaubotZipImportError: + cls.log.exception(f"Failed to load plugin at {path}, trashing...") + cls.trash(path) + except IDConflictError: + cls.log.error(f"Duplicate plugin ID at {path}, trashing...") + cls.trash(path) + + +def init(config: Config) -> None: + ZippedPluginLoader.trash_path = config["plugin_directories.trash"] + ZippedPluginLoader.directories = config["plugin_directories.load"] + ZippedPluginLoader.load_all() diff --git a/maubot-src/maubot/management/__init__.py b/maubot-src/maubot/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/maubot-src/maubot/management/api/__init__.py b/maubot-src/maubot/management/api/__init__.py new file mode 100644 index 0000000..c2e5f24 --- /dev/null +++ b/maubot-src/maubot/management/api/__init__.py @@ -0,0 +1,48 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from asyncio import AbstractEventLoop +import importlib + +from aiohttp import web + +from ...config import Config +from .auth import check_token +from .base import get_config, routes, set_config +from .middleware import auth, error + + +@routes.get("/features") +def features(request: web.Request) -> web.Response: + data = get_config()["api_features"] + err = check_token(request) + if err is None: + return web.json_response(data) + else: + return web.json_response( + { + "login": data["login"], + } + ) + + +def init(cfg: Config, loop: AbstractEventLoop) -> web.Application: + set_config(cfg) + for pkg, enabled in cfg["api_features"].items(): + if enabled: + importlib.import_module(f"maubot.management.api.{pkg}") + app = web.Application(loop=loop, middlewares=[auth, error], client_max_size=100 * 1024 * 1024) + app.add_routes(routes) + return app diff --git a/maubot-src/maubot/management/api/auth.py b/maubot-src/maubot/management/api/auth.py new file mode 100644 index 0000000..0abc3ad --- /dev/null +++ b/maubot-src/maubot/management/api/auth.py @@ -0,0 +1,76 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from time import time + +from aiohttp import web + +from mautrix.types import UserID +from mautrix.util.signed_token import sign_token, verify_token + +from .base import get_config, routes +from .responses import resp + + +def is_valid_token(token: str) -> bool: + data = verify_token(get_config()["server.unshared_secret"], token) + if not data: + return False + return get_config().is_admin(data.get("user_id", None)) + + +def create_token(user: UserID) -> str: + return sign_token( + get_config()["server.unshared_secret"], + { + "user_id": user, + "created_at": int(time()), + }, + ) + + +def get_token(request: web.Request) -> str: + token = request.headers.get("Authorization", "") + if not token or not token.startswith("Bearer "): + token = request.query.get("access_token", "") + else: + token = token[len("Bearer ") :] + return token + + +def check_token(request: web.Request) -> web.Response | None: + token = get_token(request) + if not token: + return resp.no_token + elif not is_valid_token(token): + return resp.invalid_token + return None + + +@routes.post("/auth/ping") +async def ping(request: web.Request) -> web.Response: + token = get_token(request) + if not token: + return resp.no_token + + data = verify_token(get_config()["server.unshared_secret"], token) + if not data: + return resp.invalid_token + user = data.get("user_id", None) + if not get_config().is_admin(user): + return resp.invalid_token + return resp.pong(user, get_config()["api_features"]) diff --git a/maubot-src/maubot/management/api/base.py b/maubot-src/maubot/management/api/base.py new file mode 100644 index 0000000..3d7693a --- /dev/null +++ b/maubot-src/maubot/management/api/base.py @@ -0,0 +1,40 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +import asyncio + +from aiohttp import web + +from ...__meta__ import __version__ +from ...config import Config + +routes: web.RouteTableDef = web.RouteTableDef() +_config: Config | None = None + + +def set_config(config: Config) -> None: + global _config + _config = config + + +def get_config() -> Config: + return _config + + +@routes.get("/version") +async def version(_: web.Request) -> web.Response: + return web.json_response({"version": __version__}) diff --git a/maubot-src/maubot/management/api/client.py b/maubot-src/maubot/management/api/client.py new file mode 100644 index 0000000..0f80584 --- /dev/null +++ b/maubot-src/maubot/management/api/client.py @@ -0,0 +1,217 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from json import JSONDecodeError +import logging + +from aiohttp import web + +from mautrix.client import Client as MatrixClient +from mautrix.errors import MatrixConnectionError, MatrixInvalidToken, MatrixRequestError +from mautrix.types import FilterID, SyncToken, UserID + +from ...client import Client +from .base import routes +from .responses import resp + +log = logging.getLogger("maubot.server.client") + + +@routes.get("/clients") +async def get_clients(_: web.Request) -> web.Response: + return resp.found([client.to_dict() for client in Client.cache.values()]) + + +@routes.get("/client/{id}") +async def get_client(request: web.Request) -> web.Response: + user_id = request.match_info.get("id", None) + client = await Client.get(user_id) + if not client: + return resp.client_not_found + return resp.found(client.to_dict()) + + +async def _create_client(user_id: UserID | None, data: dict) -> web.Response: + homeserver = data.get("homeserver", None) + access_token = data.get("access_token", None) + device_id = data.get("device_id", None) + new_client = MatrixClient( + mxid="@not:a.mxid", + base_url=homeserver, + token=access_token, + client_session=Client.http_client, + ) + try: + whoami = await new_client.whoami() + except MatrixInvalidToken as e: + return resp.bad_client_access_token + except MatrixRequestError: + log.warning(f"Failed to get whoami from {homeserver} for new client", exc_info=True) + return resp.bad_client_access_details + except MatrixConnectionError: + log.warning(f"Failed to connect to {homeserver} for new client", exc_info=True) + return resp.bad_client_connection_details + if user_id is None: + existing_client = await Client.get(whoami.user_id) + if existing_client is not None: + return resp.user_exists + elif whoami.user_id != user_id: + return resp.mxid_mismatch(whoami.user_id) + elif whoami.device_id and device_id and whoami.device_id != device_id: + return resp.device_id_mismatch(whoami.device_id) + client = await Client.get( + whoami.user_id, homeserver=homeserver, access_token=access_token, device_id=device_id + ) + client.enabled = data.get("enabled", True) + client.sync = data.get("sync", True) + await client.update_autojoin(data.get("autojoin", True), save=False) + await client.update_online(data.get("online", True), save=False) + client.displayname = data.get("displayname", "disable") + client.avatar_url = data.get("avatar_url", "disable") + await client.update() + await client.start() + return resp.created(client.to_dict()) + + +async def _update_client(client: Client, data: dict, is_login: bool = False) -> web.Response: + try: + await client.update_access_details( + data.get("access_token"), data.get("homeserver"), data.get("device_id") + ) + except MatrixInvalidToken: + return resp.bad_client_access_token + except MatrixRequestError: + log.warning( + f"Failed to get whoami from homeserver to update client details", exc_info=True + ) + return resp.bad_client_access_details + except MatrixConnectionError: + log.warning(f"Failed to connect to homeserver to update client details", exc_info=True) + return resp.bad_client_connection_details + except ValueError as e: + str_err = str(e) + if str_err.startswith("MXID mismatch"): + return resp.mxid_mismatch(str(e)[len("MXID mismatch: ") :]) + elif str_err.startswith("Device ID mismatch"): + return resp.device_id_mismatch(str(e)[len("Device ID mismatch: ") :]) + await client.update_avatar_url(data.get("avatar_url"), save=False) + await client.update_displayname(data.get("displayname"), save=False) + await client.update_started(data.get("started")) + await client.update_enabled(data.get("enabled"), save=False) + await client.update_autojoin(data.get("autojoin"), save=False) + await client.update_online(data.get("online"), save=False) + await client.update_sync(data.get("sync"), save=False) + await client.update() + return resp.updated(client.to_dict(), is_login=is_login) + + +async def _create_or_update_client( + user_id: UserID, data: dict, is_login: bool = False +) -> web.Response: + client = await Client.get(user_id) + if not client: + return await _create_client(user_id, data) + else: + return await _update_client(client, data, is_login=is_login) + + +@routes.post("/client/new") +async def create_client(request: web.Request) -> web.Response: + try: + data = await request.json() + except JSONDecodeError: + return resp.body_not_json + return await _create_client(None, data) + + +@routes.put("/client/{id}") +async def update_client(request: web.Request) -> web.Response: + user_id = request.match_info["id"] + try: + data = await request.json() + except JSONDecodeError: + return resp.body_not_json + return await _create_or_update_client(user_id, data) + + +@routes.delete("/client/{id}") +async def delete_client(request: web.Request) -> web.Response: + user_id = request.match_info["id"] + client = await Client.get(user_id) + if not client: + return resp.client_not_found + if len(client.references) > 0: + return resp.client_in_use + if client.started: + await client.stop() + await client.delete() + return resp.deleted + + +@routes.post("/client/{id}/clearcache") +async def clear_client_cache(request: web.Request) -> web.Response: + user_id = request.match_info["id"] + client = await Client.get(user_id) + if not client: + return resp.client_not_found + await client.clear_cache() + return resp.ok + + +@routes.post("/client/{id}/verify") +async def verify_client(request: web.Request) -> web.Response: + user_id = request.match_info["id"] + client = await Client.get(user_id) + if not client: + return resp.client_not_found + try: + req = await request.json() + except Exception: + return resp.body_not_json + try: + await client.crypto.verify_with_recovery_key(req["recovery_key"]) + client.trust_state = await client.crypto.resolve_trust( + client.crypto.own_identity, + allow_fetch=False, + ) + log.debug(f"Trust state after verifying {client.id}: {client.trust_state}") + except Exception as e: + log.exception("Failed to verify client with recovery key") + return resp.internal_crypto_error(str(e)) + return resp.ok + + +@routes.post("/client/{id}/generate_recovery_key") +async def generate_recovery_key(request: web.Request) -> web.Response: + user_id = request.match_info["id"] + client = await Client.get(user_id) + if not client: + return resp.client_not_found + try: + keys = await client.crypto.get_own_cross_signing_public_keys() + if keys: + return resp.client_has_keys + key = await client.crypto.generate_recovery_key() + client.trust_state = await client.crypto.resolve_trust( + client.crypto.own_identity, + allow_fetch=False, + ) + log.debug(f"Trust state generating recovery key for {client.id}: {client.trust_state}") + except Exception as e: + log.exception("Failed to generate recovery key for client") + return resp.internal_crypto_error(str(e)) + return resp.created({"success": True, "recovery_key": key}) diff --git a/maubot-src/maubot/management/api/client_auth.py b/maubot-src/maubot/management/api/client_auth.py new file mode 100644 index 0000000..4e5e201 --- /dev/null +++ b/maubot-src/maubot/management/api/client_auth.py @@ -0,0 +1,273 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import NamedTuple +from http import HTTPStatus +from json import JSONDecodeError +import asyncio +import hashlib +import hmac +import random +import string + +from aiohttp import web +from yarl import URL + +from mautrix.api import Method, Path, SynapseAdminPath +from mautrix.client import ClientAPI +from mautrix.errors import MatrixRequestError +from mautrix.types import LoginResponse, LoginType + +from .base import get_config, routes +from .client import _create_client, _create_or_update_client +from .responses import resp + + +def known_homeservers() -> dict[str, dict[str, str]]: + return get_config()["homeservers"] + + +@routes.get("/client/auth/servers") +async def get_known_servers(_: web.Request) -> web.Response: + return web.json_response({key: value["url"] for key, value in known_homeservers().items()}) + + +class AuthRequestInfo(NamedTuple): + server_name: str + client: ClientAPI + secret: str + username: str + password: str + user_type: str + device_name: str + update_client: bool + sso: bool + + +truthy_strings = ("1", "true", "yes") + + +async def read_client_auth_request( + request: web.Request, +) -> tuple[AuthRequestInfo | None, web.Response | None]: + server_name = request.match_info.get("server", None) + server = known_homeservers().get(server_name, None) + if not server: + return None, resp.server_not_found + try: + body = await request.json() + except JSONDecodeError: + return None, resp.body_not_json + sso = request.query.get("sso", "").lower() in truthy_strings + try: + username = body["username"] + password = body["password"] + except KeyError: + if not sso: + return None, resp.username_or_password_missing + username = password = None + try: + base_url = server["url"] + except KeyError: + return None, resp.invalid_server + return ( + AuthRequestInfo( + server_name=server_name, + client=ClientAPI(base_url=base_url), + secret=server.get("secret"), + username=username, + password=password, + user_type=body.get("user_type", "bot"), + device_name=body.get("device_name", "Maubot"), + update_client=request.query.get("update_client", "").lower() in truthy_strings, + sso=sso, + ), + None, + ) + + +def generate_mac( + secret: str, + nonce: str, + username: str, + password: str, + admin: bool = False, + user_type: str = None, +) -> str: + mac = hmac.new(key=secret.encode("utf-8"), digestmod=hashlib.sha1) + mac.update(nonce.encode("utf-8")) + mac.update(b"\x00") + mac.update(username.encode("utf-8")) + mac.update(b"\x00") + mac.update(password.encode("utf-8")) + mac.update(b"\x00") + mac.update(b"admin" if admin else b"notadmin") + if user_type is not None: + mac.update(b"\x00") + mac.update(user_type.encode("utf8")) + return mac.hexdigest() + + +@routes.post("/client/auth/{server}/register") +async def register(request: web.Request) -> web.Response: + req, err = await read_client_auth_request(request) + if err is not None: + return err + if req.sso: + return resp.registration_no_sso + elif not req.secret: + return resp.registration_secret_not_found + path = SynapseAdminPath.v1.register + res = await req.client.api.request(Method.GET, path) + content = { + "nonce": res["nonce"], + "username": req.username, + "password": req.password, + "admin": False, + "user_type": req.user_type, + } + content["mac"] = generate_mac(**content, secret=req.secret) + try: + raw_res = await req.client.api.request(Method.POST, path, content=content) + except MatrixRequestError as e: + return web.json_response( + { + "errcode": e.errcode, + "error": e.message, + "http_status": e.http_status, + }, + status=HTTPStatus.INTERNAL_SERVER_ERROR, + ) + login_res = LoginResponse.deserialize(raw_res) + if req.update_client: + return await _create_client( + login_res.user_id, + { + "homeserver": str(req.client.api.base_url), + "access_token": login_res.access_token, + "device_id": login_res.device_id, + }, + ) + return web.json_response(login_res.serialize()) + + +@routes.post("/client/auth/{server}/login") +async def login(request: web.Request) -> web.Response: + req, err = await read_client_auth_request(request) + if err is not None: + return err + if req.sso: + return await _do_sso(req) + else: + return await _do_login(req) + + +async def _do_sso(req: AuthRequestInfo) -> web.Response: + flows = await req.client.get_login_flows() + if not flows.supports_type(LoginType.SSO): + return resp.sso_not_supported + waiter_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=16)) + cfg = get_config() + public_url = ( + URL(cfg["server.public_url"]) + / "_matrix/maubot/v1/client/auth_external_sso/complete" + / waiter_id + ) + sso_url = req.client.api.base_url.with_path(str(Path.v3.login.sso.redirect)).with_query( + {"redirectUrl": str(public_url)} + ) + sso_waiters[waiter_id] = req, asyncio.get_running_loop().create_future() + return web.json_response({"sso_url": str(sso_url), "id": waiter_id}) + + +async def _do_login(req: AuthRequestInfo, login_token: str | None = None) -> web.Response: + device_id = "".join(random.choices(string.ascii_uppercase + string.digits, k=8)) + device_id = f"maubot_{device_id}" + try: + if req.sso: + res = await req.client.login( + token=login_token, + login_type=LoginType.TOKEN, + device_id=device_id, + store_access_token=False, + initial_device_display_name=req.device_name, + ) + else: + res = await req.client.login( + identifier=req.username, + login_type=LoginType.PASSWORD, + password=req.password, + device_id=device_id, + initial_device_display_name=req.device_name, + store_access_token=False, + ) + except MatrixRequestError as e: + return web.json_response( + { + "errcode": e.errcode, + "error": e.message, + }, + status=e.http_status, + ) + if req.update_client: + return await _create_or_update_client( + res.user_id, + { + "homeserver": str(req.client.api.base_url), + "access_token": res.access_token, + "device_id": res.device_id, + }, + is_login=True, + ) + return web.json_response(res.serialize()) + + +sso_waiters: dict[str, tuple[AuthRequestInfo, asyncio.Future]] = {} + + +@routes.post("/client/auth/{server}/sso/{id}/wait") +async def wait_sso(request: web.Request) -> web.Response: + waiter_id = request.match_info["id"] + req, fut = sso_waiters[waiter_id] + try: + login_token = await fut + finally: + sso_waiters.pop(waiter_id, None) + return await _do_login(req, login_token) + + +@routes.get("/client/auth_external_sso/complete/{id}") +async def complete_sso(request: web.Request) -> web.Response: + try: + _, fut = sso_waiters[request.match_info["id"]] + except KeyError: + return web.Response(status=404, text="Invalid session ID\n") + if fut.cancelled(): + return web.Response(status=200, text="The login was cancelled from the Maubot client\n") + elif fut.done(): + return web.Response(status=200, text="The login token was already received\n") + try: + fut.set_result(request.query["loginToken"]) + except KeyError: + return web.Response(status=400, text="Missing loginToken query parameter\n") + except asyncio.InvalidStateError: + return web.Response(status=500, text="Invalid state\n") + return web.Response( + status=200, + text="Login token received, please return to your Maubot client. " + "This tab can be closed.\n", + ) diff --git a/maubot-src/maubot/management/api/client_proxy.py b/maubot-src/maubot/management/api/client_proxy.py new file mode 100644 index 0000000..3fa682b --- /dev/null +++ b/maubot-src/maubot/management/api/client_proxy.py @@ -0,0 +1,56 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from aiohttp import client as http, web + +from ...client import Client +from .base import routes +from .responses import resp + +PROXY_CHUNK_SIZE = 32 * 1024 + + +@routes.view("/proxy/{id}/{path:_matrix/.+}") +async def proxy(request: web.Request) -> web.StreamResponse: + user_id = request.match_info.get("id", None) + client = await Client.get(user_id) + if not client: + return resp.client_not_found + + path = request.match_info.get("path", None) + query = request.query.copy() + try: + del query["access_token"] + except KeyError: + pass + headers = request.headers.copy() + del headers["Host"] + headers["Authorization"] = f"Bearer {client.access_token}" + if "X-Forwarded-For" not in headers: + peer = request.transport.get_extra_info("peername") + if peer is not None: + host, port = peer + headers["X-Forwarded-For"] = f"{host}:{port}" + + data = await request.read() + async with http.request( + request.method, f"{client.homeserver}/{path}", headers=headers, params=query, data=data + ) as proxy_resp: + response = web.StreamResponse(status=proxy_resp.status, headers=proxy_resp.headers) + await response.prepare(request) + async for chunk in proxy_resp.content.iter_chunked(PROXY_CHUNK_SIZE): + await response.write(chunk) + await response.write_eof() + return response diff --git a/maubot-src/maubot/management/api/dev_open.py b/maubot-src/maubot/management/api/dev_open.py new file mode 100644 index 0000000..2881d46 --- /dev/null +++ b/maubot-src/maubot/management/api/dev_open.py @@ -0,0 +1,57 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from string import Template +import asyncio +import re + +from aiohttp import web +from ruamel.yaml import YAML + +from .base import routes + +enabled = False + + +@routes.get("/debug/open") +async def check_enabled(_: web.Request) -> web.Response: + return web.json_response({"enabled": enabled}) + + +try: + yaml = YAML() + + with open(".dev-open-cfg.yaml", "r") as file: + cfg = yaml.load(file) + editor_command = Template(cfg["editor"]) + pathmap = [(re.compile(item["find"]), item["replace"]) for item in cfg["pathmap"]] + + @routes.post("/debug/open") + async def open_file(request: web.Request) -> web.Response: + data = await request.json() + try: + path = data["path"] + for find, replace in pathmap: + path = find.sub(replace, path) + cmd = editor_command.substitute(path=path, line=data["line"]) + except (KeyError, ValueError): + return web.Response(status=400) + res = await asyncio.create_subprocess_shell(cmd) + stdout, stderr = await res.communicate() + return web.json_response({"return": res.returncode, "stdout": stdout, "stderr": stderr}) + + enabled = True +except Exception: + pass diff --git a/maubot-src/maubot/management/api/instance.py b/maubot-src/maubot/management/api/instance.py new file mode 100644 index 0000000..4043221 --- /dev/null +++ b/maubot-src/maubot/management/api/instance.py @@ -0,0 +1,97 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from json import JSONDecodeError + +from aiohttp import web + +from ...client import Client +from ...instance import PluginInstance +from ...loader import PluginLoader +from .base import routes +from .responses import resp + + +@routes.get("/instances") +async def get_instances(_: web.Request) -> web.Response: + return resp.found([instance.to_dict() for instance in PluginInstance.cache.values()]) + + +@routes.get("/instance/{id}") +async def get_instance(request: web.Request) -> web.Response: + instance_id = request.match_info["id"].lower() + instance = await PluginInstance.get(instance_id) + if not instance: + return resp.instance_not_found + return resp.found(instance.to_dict()) + + +async def _create_instance(instance_id: str, data: dict) -> web.Response: + plugin_type = data.get("type") + primary_user = data.get("primary_user") + if not plugin_type: + return resp.plugin_type_required + elif not primary_user: + return resp.primary_user_required + elif not await Client.get(primary_user): + return resp.primary_user_not_found + try: + PluginLoader.find(plugin_type) + except KeyError: + return resp.plugin_type_not_found + instance = await PluginInstance.get(instance_id, type=plugin_type, primary_user=primary_user) + instance.enabled = data.get("enabled", True) + instance.config_str = data.get("config") or "" + await instance.update() + await instance.load() + await instance.start() + return resp.created(instance.to_dict()) + + +async def _update_instance(instance: PluginInstance, data: dict) -> web.Response: + if not await instance.update_primary_user(data.get("primary_user")): + return resp.primary_user_not_found + await instance.update_id(data.get("id")) + await instance.update_enabled(data.get("enabled")) + await instance.update_config(data.get("config")) + await instance.update_started(data.get("started")) + await instance.update_type(data.get("type")) + return resp.updated(instance.to_dict()) + + +@routes.put("/instance/{id}") +async def update_instance(request: web.Request) -> web.Response: + instance_id = request.match_info["id"].lower() + instance = await PluginInstance.get(instance_id) + try: + data = await request.json() + except JSONDecodeError: + return resp.body_not_json + if not instance: + return await _create_instance(instance_id, data) + else: + return await _update_instance(instance, data) + + +@routes.delete("/instance/{id}") +async def delete_instance(request: web.Request) -> web.Response: + instance_id = request.match_info["id"].lower() + instance = await PluginInstance.get(instance_id) + if not instance: + return resp.instance_not_found + if instance.started: + await instance.stop() + await instance.delete() + return resp.deleted diff --git a/maubot-src/maubot/management/api/instance_database.py b/maubot-src/maubot/management/api/instance_database.py new file mode 100644 index 0000000..2f8c37a --- /dev/null +++ b/maubot-src/maubot/management/api/instance_database.py @@ -0,0 +1,161 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from datetime import datetime + +from aiohttp import web +from asyncpg import PostgresError +import aiosqlite + +from mautrix.util.async_db import Database + +from ...instance import PluginInstance +from ...lib.optionalalchemy import Engine, IntegrityError, OperationalError, asc, desc +from .base import routes +from .responses import resp + + +@routes.get("/instance/{id}/database") +async def get_database(request: web.Request) -> web.Response: + instance_id = request.match_info["id"].lower() + instance = await PluginInstance.get(instance_id) + if not instance: + return resp.instance_not_found + elif not instance.inst_db: + return resp.plugin_has_no_database + return web.json_response(await instance.get_db_tables()) + + +@routes.get("/instance/{id}/database/{table}") +async def get_table(request: web.Request) -> web.Response: + instance_id = request.match_info["id"].lower() + instance = await PluginInstance.get(instance_id) + if not instance: + return resp.instance_not_found + elif not instance.inst_db: + return resp.plugin_has_no_database + tables = await instance.get_db_tables() + try: + table = tables[request.match_info.get("table", "")] + except KeyError: + return resp.table_not_found + try: + order = [tuple(order.split(":")) for order in request.query.getall("order")] + order = [ + ( + (asc if sort.lower() == "asc" else desc)(table.columns[column]) + if sort + else table.columns[column] + ) + for column, sort in order + ] + except KeyError: + order = [] + limit = int(request.query.get("limit", "100")) + if isinstance(instance.inst_db, Engine): + return _execute_query_sqlalchemy(instance, table.select().order_by(*order).limit(limit)) + + +@routes.post("/instance/{id}/database/query") +async def query(request: web.Request) -> web.Response: + instance_id = request.match_info["id"].lower() + instance = await PluginInstance.get(instance_id) + if not instance: + return resp.instance_not_found + elif not instance.inst_db: + return resp.plugin_has_no_database + data = await request.json() + try: + sql_query = data["query"] + except KeyError: + return resp.query_missing + rows_as_dict = data.get("rows_as_dict", False) + if isinstance(instance.inst_db, Engine): + return _execute_query_sqlalchemy(instance, sql_query, rows_as_dict) + elif isinstance(instance.inst_db, Database): + try: + return await _execute_query_asyncpg(instance, sql_query, rows_as_dict) + except (PostgresError, aiosqlite.Error) as e: + return resp.sql_error(e, sql_query) + else: + return resp.unsupported_plugin_database + + +def check_type(val): + if isinstance(val, datetime): + return val.isoformat() + return val + + +async def _execute_query_asyncpg( + instance: PluginInstance, sql_query: str, rows_as_dict: bool = False +) -> web.Response: + data = {"ok": True, "query": sql_query} + if sql_query.upper().startswith("SELECT"): + res = await instance.inst_db.fetch(sql_query) + data["rows"] = [ + ( + {key: check_type(value) for key, value in row.items()} + if rows_as_dict + else [check_type(value) for value in row] + ) + for row in res + ] + if len(res) > 0: + # TODO can we find column names when there are no rows? + data["columns"] = list(res[0].keys()) + else: + res = await instance.inst_db.execute(sql_query) + if isinstance(res, str): + data["status_msg"] = res + elif isinstance(res, aiosqlite.Cursor): + data["rowcount"] = res.rowcount + # data["inserted_primary_key"] = res.lastrowid + else: + data["status_msg"] = "unknown status" + return web.json_response(data) + + +def _execute_query_sqlalchemy( + instance: PluginInstance, sql_query: str, rows_as_dict: bool = False +) -> web.Response: + assert isinstance(instance.inst_db, Engine) + try: + res = instance.inst_db.execute(sql_query) + except IntegrityError as e: + return resp.sql_integrity_error(e, sql_query) + except OperationalError as e: + return resp.sql_operational_error(e, sql_query) + data = { + "ok": True, + "query": str(sql_query), + } + if res.returns_rows: + data["rows"] = [ + ( + {key: check_type(value) for key, value in row.items()} + if rows_as_dict + else [check_type(value) for value in row] + ) + for row in res + ] + data["columns"] = res.keys() + else: + data["rowcount"] = res.rowcount + if res.is_insert: + data["inserted_primary_key"] = res.inserted_primary_key + return web.json_response(data) diff --git a/maubot-src/maubot/management/api/log.py b/maubot-src/maubot/management/api/log.py new file mode 100644 index 0000000..14c80cd --- /dev/null +++ b/maubot-src/maubot/management/api/log.py @@ -0,0 +1,172 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from collections import deque +from datetime import datetime +import asyncio +import logging + +from aiohttp import web, web_ws + +from mautrix.util import background_task + +from .auth import is_valid_token +from .base import routes + +BUILTIN_ATTRS = { + "args", + "asctime", + "created", + "exc_info", + "exc_text", + "filename", + "funcName", + "levelname", + "levelno", + "lineno", + "module", + "msecs", + "message", + "msg", + "name", + "pathname", + "process", + "processName", + "relativeCreated", + "stack_info", + "thread", + "threadName", +} +INCLUDE_ATTRS = { + "filename", + "funcName", + "levelname", + "levelno", + "lineno", + "module", + "name", + "pathname", +} +EXCLUDE_ATTRS = BUILTIN_ATTRS - INCLUDE_ATTRS +MAX_LINES = 2048 + + +class LogCollector(logging.Handler): + lines: deque[dict] + formatter: logging.Formatter + listeners: list[web.WebSocketResponse] + loop: asyncio.AbstractEventLoop + + def __init__(self, level=logging.NOTSET) -> None: + super().__init__(level) + self.lines = deque(maxlen=MAX_LINES) + self.formatter = logging.Formatter() + self.listeners = [] + + def emit(self, record: logging.LogRecord) -> None: + try: + self._emit(record) + except Exception as e: + print("Logging error:", e) + + def _emit(self, record: logging.LogRecord) -> None: + # JSON conversion based on Marsel Mavletkulov's json-log-formatter (MIT license) + # https://github.com/marselester/json-log-formatter + content = { + name: value for name, value in record.__dict__.items() if name not in EXCLUDE_ATTRS + } + content["id"] = str(record.relativeCreated) + content["msg"] = record.getMessage() + content["time"] = datetime.fromtimestamp(record.created) + + if record.exc_info: + content["exc_info"] = self.formatter.formatException(record.exc_info) + + for name, value in content.items(): + if isinstance(value, datetime): + content[name] = value.astimezone().isoformat() + asyncio.run_coroutine_threadsafe(self.send(content), loop=self.loop) + self.lines.append(content) + + async def send(self, record: dict) -> None: + for ws in self.listeners: + try: + await ws.send_json(record) + except Exception as e: + print("Log sending error:", e) + + +handler = LogCollector() +log = logging.getLogger("maubot.server.websocket") +sockets = [] + + +def init(loop: asyncio.AbstractEventLoop) -> None: + logging.root.addHandler(handler) + handler.loop = loop + + +async def stop_all() -> None: + log.debug("Closing log listener websockets") + logging.root.removeHandler(handler) + for socket in sockets: + try: + await socket.close(code=1012) + except Exception: + pass + + +@routes.get("/logs") +async def log_websocket(request: web.Request) -> web.WebSocketResponse: + ws = web.WebSocketResponse() + await ws.prepare(request) + sockets.append(ws) + log.debug(f"Connection from {request.remote} opened") + authenticated = False + + async def close_if_not_authenticated(): + await asyncio.sleep(5) + if not authenticated: + await ws.close(code=4000) + log.debug(f"Connection from {request.remote} terminated due to no authentication") + + background_task.create(close_if_not_authenticated()) + + try: + msg: web_ws.WSMessage + async for msg in ws: + if msg.type != web.WSMsgType.TEXT: + continue + if is_valid_token(msg.data): + await ws.send_json({"auth_success": True}) + await ws.send_json({"history": list(handler.lines)}) + if not authenticated: + log.debug(f"Connection from {request.remote} authenticated") + handler.listeners.append(ws) + authenticated = True + elif not authenticated: + await ws.send_json({"auth_success": False}) + except Exception: + try: + await ws.close() + except Exception: + pass + if authenticated: + handler.listeners.remove(ws) + log.debug(f"Connection from {request.remote} closed") + sockets.remove(ws) + return ws diff --git a/maubot-src/maubot/management/api/login.py b/maubot-src/maubot/management/api/login.py new file mode 100644 index 0000000..bfb2f6a --- /dev/null +++ b/maubot-src/maubot/management/api/login.py @@ -0,0 +1,41 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import json + +from aiohttp import web + +from .auth import create_token +from .base import get_config, routes +from .responses import resp + + +@routes.post("/auth/login") +async def login(request: web.Request) -> web.Response: + try: + data = await request.json() + except json.JSONDecodeError: + return resp.body_not_json + secret = data.get("secret") + if secret and get_config()["server.unshared_secret"] == secret: + user = data.get("user") or "root" + return resp.logged_in(create_token(user)) + + username = data.get("username") + password = data.get("password") + if get_config().check_password(username, password): + return resp.logged_in(create_token(username)) + + return resp.bad_auth diff --git a/maubot-src/maubot/management/api/middleware.py b/maubot-src/maubot/management/api/middleware.py new file mode 100644 index 0000000..17141fa --- /dev/null +++ b/maubot-src/maubot/management/api/middleware.py @@ -0,0 +1,78 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from typing import Awaitable, Callable +import base64 +import logging + +from aiohttp import web + +from .auth import check_token +from .base import get_config +from .responses import resp + +Handler = Callable[[web.Request], Awaitable[web.Response]] +log = logging.getLogger("maubot.server") + + +@web.middleware +async def auth(request: web.Request, handler: Handler) -> web.Response: + subpath = request.path[len("/_matrix/maubot/v1") :] + if ( + subpath.startswith("/auth/") + or subpath.startswith("/client/auth_external_sso/complete/") + or subpath == "/features" + or subpath == "/logs" + ): + return await handler(request) + err = check_token(request) + if err is not None: + return err + return await handler(request) + + +@web.middleware +async def error(request: web.Request, handler: Handler) -> web.Response: + try: + return await handler(request) + except web.HTTPException as ex: + if ex.status_code == 404: + return resp.path_not_found + elif ex.status_code == 405: + return resp.method_not_allowed + return web.json_response( + { + "httpexception": { + "headers": {key: value for key, value in ex.headers.items()}, + "class": type(ex).__name__, + "body": ex.text or base64.b64encode(ex.body), + }, + "error": f"Unhandled HTTP {ex.status}: {ex.text[:128] or 'non-text response'}", + "errcode": f"unhandled_http_{ex.status}", + }, + status=ex.status, + ) + except Exception: + log.exception("Error in handler") + return resp.internal_server_error + + +req_no = 0 + + +def get_req_no(): + global req_no + req_no += 1 + return req_no diff --git a/maubot-src/maubot/management/api/plugin.py b/maubot-src/maubot/management/api/plugin.py new file mode 100644 index 0000000..94d8d9d --- /dev/null +++ b/maubot-src/maubot/management/api/plugin.py @@ -0,0 +1,64 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import traceback + +from aiohttp import web + +from ...loader import MaubotZipImportError, PluginLoader +from .base import routes +from .responses import resp + + +@routes.get("/plugins") +async def get_plugins(_) -> web.Response: + return resp.found([plugin.to_dict() for plugin in PluginLoader.id_cache.values()]) + + +@routes.get("/plugin/{id}") +async def get_plugin(request: web.Request) -> web.Response: + plugin_id = request.match_info["id"] + plugin = PluginLoader.id_cache.get(plugin_id) + if not plugin: + return resp.plugin_not_found + return resp.found(plugin.to_dict()) + + +@routes.delete("/plugin/{id}") +async def delete_plugin(request: web.Request) -> web.Response: + plugin_id = request.match_info["id"] + plugin = PluginLoader.id_cache.get(plugin_id) + if not plugin: + return resp.plugin_not_found + elif len(plugin.references) > 0: + return resp.plugin_in_use + await plugin.delete() + return resp.deleted + + +@routes.post("/plugin/{id}/reload") +async def reload_plugin(request: web.Request) -> web.Response: + plugin_id = request.match_info["id"] + plugin = PluginLoader.id_cache.get(plugin_id) + if not plugin: + return resp.plugin_not_found + + await plugin.stop_instances() + try: + await plugin.reload() + except MaubotZipImportError as e: + return resp.plugin_reload_error(str(e), traceback.format_exc()) + await plugin.start_instances() + return resp.ok diff --git a/maubot-src/maubot/management/api/plugin_upload.py b/maubot-src/maubot/management/api/plugin_upload.py new file mode 100644 index 0000000..4cd2c47 --- /dev/null +++ b/maubot-src/maubot/management/api/plugin_upload.py @@ -0,0 +1,145 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from io import BytesIO +from time import time +import logging +import os.path +import re +import traceback + +from aiohttp import web +from packaging.version import Version + +from ...loader import DatabaseType, MaubotZipImportError, PluginLoader, ZippedPluginLoader +from .base import get_config, routes +from .responses import resp + +try: + import sqlalchemy + + has_alchemy = True +except ImportError: + has_alchemy = False + +log = logging.getLogger("maubot.server.upload") + + +@routes.put("/plugin/{id}") +async def put_plugin(request: web.Request) -> web.Response: + plugin_id = request.match_info["id"] + content = await request.read() + file = BytesIO(content) + try: + pid, version, db_type = ZippedPluginLoader.verify_meta(file) + except MaubotZipImportError as e: + return resp.plugin_import_error(str(e), traceback.format_exc()) + if db_type == DatabaseType.SQLALCHEMY and not has_alchemy: + return resp.sqlalchemy_not_installed + if pid != plugin_id: + return resp.pid_mismatch + plugin = PluginLoader.id_cache.get(plugin_id, None) + if not plugin: + return await upload_new_plugin(content, pid, version) + elif isinstance(plugin, ZippedPluginLoader): + return await upload_replacement_plugin(plugin, content, version) + else: + return resp.unsupported_plugin_loader + + +@routes.post("/plugins/upload") +async def upload_plugin(request: web.Request) -> web.Response: + content = await request.read() + file = BytesIO(content) + try: + pid, version, db_type = ZippedPluginLoader.verify_meta(file) + except MaubotZipImportError as e: + return resp.plugin_import_error(str(e), traceback.format_exc()) + if db_type == DatabaseType.SQLALCHEMY and not has_alchemy: + return resp.sqlalchemy_not_installed + plugin = PluginLoader.id_cache.get(pid, None) + if not plugin: + return await upload_new_plugin(content, pid, version) + elif not request.query.get("allow_override"): + return resp.plugin_exists + elif isinstance(plugin, ZippedPluginLoader): + return await upload_replacement_plugin(plugin, content, version) + else: + return resp.unsupported_plugin_loader + + +async def upload_new_plugin(content: bytes, pid: str, version: Version) -> web.Response: + path = os.path.join(get_config()["plugin_directories.upload"], f"{pid}-v{version}.mbp") + with open(path, "wb") as p: + p.write(content) + try: + plugin = ZippedPluginLoader.get(path) + except MaubotZipImportError as e: + ZippedPluginLoader.trash(path) + return resp.plugin_import_error(str(e), traceback.format_exc()) + return resp.created(plugin.to_dict()) + + +async def upload_replacement_plugin( + plugin: ZippedPluginLoader, content: bytes, new_version: Version +) -> web.Response: + dirname = os.path.dirname(plugin.path) + old_filename = os.path.basename(plugin.path) + if str(plugin.meta.version) in old_filename: + replacement = ( + str(new_version) + if plugin.meta.version != new_version + else f"{new_version}-ts{int(time() * 1000)}" + ) + filename = re.sub( + f"{re.escape(str(plugin.meta.version))}(-ts[0-9]+)?", replacement, old_filename + ) + else: + filename = old_filename.rstrip(".mbp") + filename = f"{filename}-v{new_version}.mbp" + path = os.path.join(dirname, filename) + with open(path, "wb") as p: + p.write(content) + old_path = plugin.path + await plugin.stop_instances() + try: + await plugin.reload(new_path=path) + except MaubotZipImportError as e: + log.exception(f"Error loading updated version of {plugin.meta.id}, rolling back") + try: + await plugin.reload(new_path=old_path) + await plugin.start_instances() + except MaubotZipImportError: + log.warning(f"Failed to roll back update of {plugin.meta.id}", exc_info=True) + finally: + ZippedPluginLoader.trash(path, reason="failed_update") + return resp.plugin_import_error(str(e), traceback.format_exc()) + try: + await plugin.start_instances() + except Exception as e: + log.exception(f"Error starting {plugin.meta.id} instances after update, rolling back") + try: + await plugin.stop_instances() + await plugin.reload(new_path=old_path) + await plugin.start_instances() + except Exception: + log.warning(f"Failed to roll back update of {plugin.meta.id}", exc_info=True) + finally: + ZippedPluginLoader.trash(path, reason="failed_update") + return resp.plugin_reload_error(str(e), traceback.format_exc()) + + log.debug(f"Successfully updated {plugin.meta.id}, moving old version to trash") + ZippedPluginLoader.trash(old_path, reason="update") + return resp.updated(plugin.to_dict()) diff --git a/maubot-src/maubot/management/api/responses.py b/maubot-src/maubot/management/api/responses.py new file mode 100644 index 0000000..37844c7 --- /dev/null +++ b/maubot-src/maubot/management/api/responses.py @@ -0,0 +1,510 @@ +# maubot - A plugin-based Matrix bot system. +# Copyright (C) 2022 Tulir Asokan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General 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 General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import annotations + +from typing import TYPE_CHECKING +from http import HTTPStatus + +from aiohttp import web +from asyncpg import PostgresError +import aiosqlite + +if TYPE_CHECKING: + from sqlalchemy.exc import IntegrityError, OperationalError + + +class _Response: + @property + def body_not_json(self) -> web.Response: + return web.json_response( + { + "error": "Request body is not JSON", + "errcode": "body_not_json", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def plugin_type_required(self) -> web.Response: + return web.json_response( + { + "error": "Plugin type is required when creating plugin instances", + "errcode": "plugin_type_required", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def primary_user_required(self) -> web.Response: + return web.json_response( + { + "error": "Primary user is required when creating plugin instances", + "errcode": "primary_user_required", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def bad_client_access_token(self) -> web.Response: + return web.json_response( + { + "error": "Invalid access token", + "errcode": "bad_client_access_token", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def bad_client_access_details(self) -> web.Response: + return web.json_response( + { + "error": "Invalid homeserver or access token", + "errcode": "bad_client_access_details", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def bad_client_connection_details(self) -> web.Response: + return web.json_response( + { + "error": "Could not connect to homeserver", + "errcode": "bad_client_connection_details", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + def mxid_mismatch(self, found: str) -> web.Response: + return web.json_response( + { + "error": ( + "The Matrix user ID of the client and the user ID of the access token don't " + f"match. Access token is for user {found}" + ), + "errcode": "mxid_mismatch", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + def device_id_mismatch(self, found: str) -> web.Response: + return web.json_response( + { + "error": ( + "The Matrix device ID of the client and the device ID of the access token " + f"don't match. Access token is for device {found}" + ), + "errcode": "mxid_mismatch", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def pid_mismatch(self) -> web.Response: + return web.json_response( + { + "error": "The ID in the path does not match the ID of the uploaded plugin", + "errcode": "pid_mismatch", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def username_or_password_missing(self) -> web.Response: + return web.json_response( + { + "error": "Username or password missing", + "errcode": "username_or_password_missing", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def query_missing(self) -> web.Response: + return web.json_response( + { + "error": "Query missing", + "errcode": "query_missing", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @staticmethod + def sql_error(error: PostgresError | aiosqlite.Error, query: str) -> web.Response: + return web.json_response( + { + "ok": False, + "query": query, + "error": str(error), + "errcode": "sql_error", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @staticmethod + def sql_operational_error(error: OperationalError, query: str) -> web.Response: + return web.json_response( + { + "ok": False, + "query": query, + "error": str(error.orig), + "full_error": str(error), + "errcode": "sql_operational_error", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @staticmethod + def sql_integrity_error(error: IntegrityError, query: str) -> web.Response: + return web.json_response( + { + "ok": False, + "query": query, + "error": str(error.orig), + "full_error": str(error), + "errcode": "sql_integrity_error", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def bad_auth(self) -> web.Response: + return web.json_response( + { + "error": "Invalid username or password", + "errcode": "invalid_auth", + }, + status=HTTPStatus.UNAUTHORIZED, + ) + + @property + def no_token(self) -> web.Response: + return web.json_response( + { + "error": "Authorization token missing", + "errcode": "auth_token_missing", + }, + status=HTTPStatus.UNAUTHORIZED, + ) + + @property + def invalid_token(self) -> web.Response: + return web.json_response( + { + "error": "Invalid authorization token", + "errcode": "auth_token_invalid", + }, + status=HTTPStatus.UNAUTHORIZED, + ) + + @property + def plugin_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Plugin not found", + "errcode": "plugin_not_found", + }, + status=HTTPStatus.NOT_FOUND, + ) + + @property + def client_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Client not found", + "errcode": "client_not_found", + }, + status=HTTPStatus.NOT_FOUND, + ) + + @property + def primary_user_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Client for given primary user not found", + "errcode": "primary_user_not_found", + }, + status=HTTPStatus.NOT_FOUND, + ) + + @property + def instance_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Plugin instance not found", + "errcode": "instance_not_found", + }, + status=HTTPStatus.NOT_FOUND, + ) + + @property + def plugin_type_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Given plugin type not found", + "errcode": "plugin_type_not_found", + }, + status=HTTPStatus.NOT_FOUND, + ) + + @property + def path_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Resource not found", + "errcode": "resource_not_found", + }, + status=HTTPStatus.NOT_FOUND, + ) + + @property + def server_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Registration target server not found", + "errcode": "server_not_found", + }, + status=HTTPStatus.NOT_FOUND, + ) + + @property + def registration_secret_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Config does not have a registration secret for that server", + "errcode": "registration_secret_not_found", + }, + status=HTTPStatus.NOT_FOUND, + ) + + @property + def registration_no_sso(self) -> web.Response: + return web.json_response( + { + "error": "The register operation is only for registering with a password", + "errcode": "registration_no_sso", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def sso_not_supported(self) -> web.Response: + return web.json_response( + { + "error": "That server does not seem to support single sign-on", + "errcode": "sso_not_supported", + }, + status=HTTPStatus.FORBIDDEN, + ) + + @property + def plugin_has_no_database(self) -> web.Response: + return web.json_response( + { + "error": "Given plugin does not have a database", + "errcode": "plugin_has_no_database", + } + ) + + @property + def unsupported_plugin_database(self) -> web.Response: + return web.json_response( + { + "error": "The database type is not supported by this API", + "errcode": "unsupported_plugin_database", + } + ) + + @property + def sqlalchemy_not_installed(self) -> web.Response: + return web.json_response( + { + "error": "This plugin requires a legacy database, but SQLAlchemy is not installed", + "errcode": "unsupported_plugin_database", + }, + status=HTTPStatus.NOT_IMPLEMENTED, + ) + + @property + def table_not_found(self) -> web.Response: + return web.json_response( + { + "error": "Given table not found in plugin database", + "errcode": "table_not_found", + } + ) + + @property + def method_not_allowed(self) -> web.Response: + return web.json_response( + { + "error": "Method not allowed", + "errcode": "method_not_allowed", + }, + status=HTTPStatus.METHOD_NOT_ALLOWED, + ) + + @property + def user_exists(self) -> web.Response: + return web.json_response( + { + "error": "There is already a client with the user ID of that token", + "errcode": "user_exists", + }, + status=HTTPStatus.CONFLICT, + ) + + @property + def plugin_exists(self) -> web.Response: + return web.json_response( + { + "error": "A plugin with the same ID as the uploaded plugin already exists", + "errcode": "plugin_exists", + }, + status=HTTPStatus.CONFLICT, + ) + + @property + def plugin_in_use(self) -> web.Response: + return web.json_response( + { + "error": "Plugin instances of this type still exist", + "errcode": "plugin_in_use", + }, + status=HTTPStatus.PRECONDITION_FAILED, + ) + + @property + def client_in_use(self) -> web.Response: + return web.json_response( + { + "error": "Plugin instances with this client as their primary user still exist", + "errcode": "client_in_use", + }, + status=HTTPStatus.PRECONDITION_FAILED, + ) + + @staticmethod + def plugin_import_error(error: str, stacktrace: str) -> web.Response: + return web.json_response( + { + "error": error, + "stacktrace": stacktrace, + "errcode": "plugin_invalid", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @staticmethod + def plugin_reload_error(error: str, stacktrace: str) -> web.Response: + return web.json_response( + { + "error": error, + "stacktrace": stacktrace, + "errcode": "plugin_reload_fail", + }, + status=HTTPStatus.INTERNAL_SERVER_ERROR, + ) + + @property + def internal_server_error(self) -> web.Response: + return web.json_response( + { + "error": "Internal server error", + "errcode": "internal_server_error", + }, + status=HTTPStatus.INTERNAL_SERVER_ERROR, + ) + + @property + def invalid_server(self) -> web.Response: + return web.json_response( + { + "error": "Invalid registration server object in maubot configuration", + "errcode": "invalid_server", + }, + status=HTTPStatus.INTERNAL_SERVER_ERROR, + ) + + @property + def unsupported_plugin_loader(self) -> web.Response: + return web.json_response( + { + "error": "Existing plugin with same ID uses unsupported plugin loader", + "errcode": "unsupported_plugin_loader", + }, + status=HTTPStatus.BAD_REQUEST, + ) + + @property + def client_has_keys(self) -> web.Response: + return web.json_response( + { + "error": "Client already has cross-signing keys", + "errcode": "client_has_keys", + }, + status=HTTPStatus.CONFLICT, + ) + + def internal_crypto_error(self, message: str) -> web.Response: + return web.json_response( + { + "error": f"Internal crypto error: {message}", + "errcode": "internal_crypto_error", + }, + status=HTTPStatus.INTERNAL_SERVER_ERROR, + ) + + @property + def not_implemented(self) -> web.Response: + return web.json_response( + { + "error": "Not implemented", + "errcode": "not_implemented", + }, + status=HTTPStatus.NOT_IMPLEMENTED, + ) + + @property + def ok(self) -> web.Response: + return web.json_response( + {"success": True}, + status=HTTPStatus.OK, + ) + + @property + def deleted(self) -> web.Response: + return web.Response(status=HTTPStatus.NO_CONTENT) + + @staticmethod + def found(data: dict) -> web.Response: + return web.json_response(data, status=HTTPStatus.OK) + + @staticmethod + def updated(data: dict, is_login: bool = False) -> web.Response: + return web.json_response(data, status=HTTPStatus.ACCEPTED if is_login else HTTPStatus.OK) + + def logged_in(self, token: str) -> web.Response: + return self.found({"token": token}) + + def pong(self, user: str, features: dict) -> web.Response: + return self.found({"username": user, "features": features}) + + @staticmethod + def created(data: dict) -> web.Response: + return web.json_response(data, status=HTTPStatus.CREATED) + + +resp = _Response() diff --git a/maubot-src/maubot/management/api/spec.md b/maubot-src/maubot/management/api/spec.md new file mode 100644 index 0000000..88978ab --- /dev/null +++ b/maubot-src/maubot/management/api/spec.md @@ -0,0 +1,2 @@ +# Maubot Management API +This document has been moved to docs.mau.fi: diff --git a/maubot-src/maubot/management/api/spec.yaml b/maubot-src/maubot/management/api/spec.yaml new file mode 100644 index 0000000..8529599 --- /dev/null +++ b/maubot-src/maubot/management/api/spec.yaml @@ -0,0 +1,728 @@ +openapi: 3.0.0 +info: + title: Maubot Management + version: 0.1.0 + description: The API to manage a [maubot](https://github.com/maubot/maubot) instance + license: + name: GNU Affero General Public License version 3 + url: 'https://github.com/maubot/maubot/blob/master/LICENSE' +security: +- bearer: [] +servers: +- url: /_matrix/maubot/v1 + +paths: + /auth/login: + post: + operationId: login + summary: Log in with the unshared secret or username+password + tags: [Authentication] + requestBody: + content: + application/json: + schema: + type: object + description: Set either username+password or secret. + properties: + secret: + type: string + description: The unshared server secret for root login + username: + type: string + description: The username for normal login + password: + type: string + description: The password for normal login + responses: + 200: + description: Logged in successfully + content: + application/json: + schema: + type: object + properties: + token: + type: string + 401: + description: Invalid credentials + /auth/ping: + post: + operationId: ping + summary: Check if the given token is valid + tags: [Authentication] + responses: + 200: + description: Token is OK + content: + application/json: + schema: + type: object + properties: + username: + type: string + 401: + description: Token is not OK + + /plugins: + get: + operationId: get_plugins + summary: Get the list of installed plugins + tags: [Plugins] + responses: + 200: + description: The list of plugins + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Plugin' + 401: + $ref: '#/components/responses/Unauthorized' + /plugins/upload: + post: + operationId: upload_plugin + summary: Upload a new plugin + description: Upload a new plugin. If the plugin already exists, enabled instances will be restarted. + tags: [Plugins] + parameters: + - name: allow_override + in: query + description: Set to allow overriding existing plugins + required: false + schema: + type: boolean + default: false + requestBody: + content: + application/zip: + schema: + type: string + format: binary + example: The plugin maubot archive (.mbp) + responses: + 200: + description: Plugin uploaded and replaced current version successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Plugin' + 201: + description: New plugin uploaded successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Plugin' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 409: + description: Plugin already exists and allow_override was not specified. + '/plugin/{id}': + parameters: + - name: id + in: path + description: The ID of the plugin to get + required: true + schema: + type: string + get: + operationId: get_plugin + summary: Get information about a specific plugin + tags: [Plugins] + responses: + 200: + description: Plugin found + content: + application/json: + schema: + $ref: '#/components/schemas/Plugin' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/PluginNotFound' + delete: + operationId: delete_plugin + summary: Delete a plugin + description: Delete a plugin. All instances of the plugin must be deleted before deleting the plugin. + tags: [Plugins] + responses: + 204: + description: Plugin deleted + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/PluginNotFound' + 412: + description: One or more plugin instances of this type exist + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + operationId: put_plugin + summary: Upload a new or replacement plugin + description: | + Upload a new or replacement plugin with the specified ID. + A HTTP 400 will be returned if the ID of the uploaded plugin + doesn't match the ID in the path. If the plugin already + exists, enabled instances will be restarted. + tags: [Plugins] + requestBody: + content: + application/zip: + schema: + type: string + format: binary + example: The plugin maubot archive (.mbp) + responses: + 200: + description: Plugin uploaded and replaced current version successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Plugin' + 201: + description: New plugin uploaded successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Plugin' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + /plugin/{id}/reload: + parameters: + - name: id + in: path + description: The ID of the plugin to get + required: true + schema: + type: string + post: + operationId: reload_plugin + summary: Reload a plugin from disk + tags: [Plugins] + responses: + 200: + description: Plugin reloaded + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/PluginNotFound' + + /instances: + get: + operationId: get_instances + summary: Get all plugin instances + tags: [Plugin instances] + responses: + 200: + description: The list of instances + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PluginInstance' + 401: + $ref: '#/components/responses/Unauthorized' + '/instance/{id}': + parameters: + - name: id + in: path + description: The ID of the instance to get + required: true + schema: + type: string + get: + operationId: get_instance + summary: Get information about a specific plugin instance + tags: [Plugin instances] + responses: + 200: + description: Plugin instance found + content: + application/json: + schema: + $ref: '#/components/schemas/PluginInstance' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/InstanceNotFound' + delete: + operationId: delete_instance + summary: Delete a specific plugin instance + tags: [Plugin instances] + responses: + 204: + description: Plugin instance deleted + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/InstanceNotFound' + put: + operationId: update_instance + summary: Create a plugin instance or edit the details of an existing plugin instance + tags: [Plugin instances] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PluginInstance' + responses: + 200: + description: Plugin instance edited + 201: + description: Plugin instance created + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + description: The referenced client or plugin type could not be found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + '/clients': + get: + operationId: get_clients + summary: Get the list of Matrix clients + tags: [Clients] + responses: + 200: + description: The list of plugins + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/MatrixClient' + 401: + $ref: '#/components/responses/Unauthorized' + /client/new: + post: + operationId: create_client + summary: Create a Matrix client + tags: [Clients] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + responses: + 201: + description: Client created + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/ClientNotFound' + 409: + description: There is already a client with the user ID of that token. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '/client/{id}': + parameters: + - name: id + in: path + description: The Matrix user ID of the client to get + required: true + schema: + type: string + get: + operationId: get_client + summary: Get information about a specific Matrix client + tags: [Clients] + responses: + 200: + description: Client found + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/ClientNotFound' + put: + operationId: update_client + summary: Create or update a Matrix client + tags: [Clients] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + responses: + 202: + description: Client updated + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + 201: + description: Client created + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + delete: + operationId: delete_client + summary: Delete a Matrix client + tags: [Clients] + responses: + 204: + description: Client deleted + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/ClientNotFound' + 412: + description: One or more plugin instances with this as their primary client exist + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '/client/{id}/clearcache': + parameters: + - name: id + in: path + description: The Matrix user ID of the client to change + required: true + schema: + type: string + put: + operationId: clear_client_cache + summary: Clear the sync/state cache of a Matrix client + tags: [Clients] + responses: + 200: + description: Cache cleared + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/ClientNotFound' + /client/auth/servers: + get: + operationId: get_client_auth_servers + summary: Get the list of servers you can register or log in on via the maubot server + tags: [Clients] + responses: + 200: + description: OK + content: + application/json: + schema: + type: object + description: Key-value map from server name to homeserver URL + additionalProperties: + type: string + description: The homeserver URL + example: + maunium.net: https://maunium.net + example.com: https://matrix.example.org + 401: + $ref: '#/components/responses/Unauthorized' + '/client/auth/{server}/register': + parameters: + - name: server + in: path + description: The server name to register the account on. + required: true + schema: + type: string + - name: update_client + in: query + description: Should maubot store the access details in a Client instead of returning them? + required: false + schema: + type: boolean + post: + operationId: client_auth_register + summary: | + Register a new account on the given Matrix server using the shared registration + secret configured into the maubot server. + tags: [Clients] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixAuthentication' + responses: + 200: + description: Registration successful + content: + application/json: + schema: + type: object + properties: + access_token: + type: string + example: syt_123_456_789 + user_id: + type: string + example: '@putkiteippi:maunium.net' + device_id: + type: string + example: maubot_F00BAR12 + 201: + description: Client created (when update_client is true) + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + 401: + $ref: '#/components/responses/Unauthorized' + 409: + description: | + There is already a client with the user ID of that token. + This should usually not happen, because the user ID was just created. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 500: + $ref: '#/components/responses/MatrixServerError' + '/client/auth/{server}/login': + parameters: + - name: server + in: path + description: The server name to log in to. + required: true + schema: + type: string + - name: update_client + in: query + description: Should maubot store the access details in a Client instead of returning them? + required: false + schema: + type: boolean + post: + operationId: client_auth_login + summary: Log in to the given Matrix server via the maubot server + tags: [Clients] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixAuthentication' + responses: + 200: + description: Login successful + content: + application/json: + schema: + type: object + properties: + user_id: + type: string + example: '@putkiteippi:maunium.net' + access_token: + type: string + example: syt_123_456_789 + device_id: + type: string + example: maubot_F00BAR12 + 201: + description: Client created (when update_client is true) + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + 202: + description: Client updated (when update_client is true) + content: + application/json: + schema: + $ref: '#/components/schemas/MatrixClient' + 401: + $ref: '#/components/responses/Unauthorized' + 500: + $ref: '#/components/responses/MatrixServerError' + +components: + responses: + Unauthorized: + description: Invalid or missing access token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + PluginNotFound: + description: Plugin not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + ClientNotFound: + description: Client not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + InstanceNotFound: + description: Plugin instance not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + BadRequest: + description: Bad request (e.g. bad request body) + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + MatrixServerError: + description: The Matrix server returned an error + content: + application/json: + schema: + type: object + properties: + errcode: + type: string + description: The `errcode` returned by the server. + error: + type: string + description: The human-readable error returned by the server. + http_status: + type: integer + description: The HTTP status returned by the server. + + securitySchemes: + bearer: + type: http + scheme: bearer + description: Required authentication for all endpoints + schemas: + Error: + type: object + properties: + error: + type: string + description: A human-readable error message + errcode: + type: string + description: A simple error code + Plugin: + type: object + properties: + id: + type: string + example: xyz.maubot.jesaribot + version: + type: string + example: 2.0.0 + instances: + type: array + items: + $ref: '#/components/schemas/PluginInstance' + PluginInstance: + type: object + properties: + id: + type: string + example: jesaribot + type: + type: string + example: xyz.maubot.jesaribot + enabled: + type: boolean + example: true + started: + type: boolean + example: true + primary_user: + type: string + example: '@putkiteippi:maunium.net' + config: + type: string + example: "YAML" + MatrixClient: + type: object + properties: + id: + type: string + example: '@putkiteippi:maunium.net' + readOnly: true + description: The Matrix user ID of this client. + homeserver: + type: string + example: 'https://maunium.net' + description: The homeserver URL for this client. + access_token: + type: string + description: The Matrix access token for this client. + device_id: + type: string + description: The Matrix device ID corresponding to the access token. + fingerprint: + type: string + description: The encryption device fingerprint for verification. + enabled: + type: boolean + example: true + description: Whether or not this client is enabled. + started: + type: boolean + example: true + description: Whether or not this client and its instances have been started. + sync: + type: boolean + example: true + description: Whether or not syncing is enabled on this client. + sync_ok: + type: boolean + example: true + description: Whether or not the previous sync was successful on this client. + autojoin: + type: boolean + example: true + description: Whether or not this client should automatically join rooms when invited. + displayname: + type: string + example: J. E. Saarinen + description: The display name for this client. + avatar_url: + type: string + example: 'mxc://maunium.net/FsPQQTntCCqhJMFtwArmJdaU' + description: The content URI of the avatar for this client. + instances: + type: array + readOnly: true + items: + $ref: '#/components/schemas/PluginInstance' + MatrixAuthentication: + type: object + properties: + username: + type: string + example: putkiteippi + description: The user ID localpart to register/log in as. + password: + type: string + example: p455w0rd + description: The password for/of the user. diff --git a/maubot-src/maubot/management/frontend/.eslintrc.json b/maubot-src/maubot/management/frontend/.eslintrc.json new file mode 100644 index 0000000..8451d44 --- /dev/null +++ b/maubot-src/maubot/management/frontend/.eslintrc.json @@ -0,0 +1,67 @@ +{ + "extends": "react-app", + "plugins": [ + "import" + ], + "rules": { + "indent": ["error", 4, { + "ignoredNodes": [ + "JSXAttribute", + "JSXSpreadAttribute" + ], + "FunctionDeclaration": {"parameters": "first"}, + "FunctionExpression": {"parameters": "first"}, + "CallExpression": {"arguments": "first"}, + "ArrayExpression": "first", + "ObjectExpression": "first", + "ImportDeclaration": "first" + }], + "react/jsx-indent-props": ["error", "first"], + "object-curly-newline": ["error", { + "consistent": true + }], + "object-curly-spacing": ["error", "always", { + "arraysInObjects": false, + "objectsInObjects": false + }], + "array-bracket-spacing": ["error", "never"], + "one-var": ["error", { + "initialized": "never", + "uninitialized": "always" + }], + "one-var-declaration-per-line": ["error", "initializations"], + "quotes": ["error", "double"], + "semi": ["error", "never"], + "comma-dangle": ["error", "always-multiline"], + "max-len": ["warn", 100], + "space-before-function-paren": ["error", { + "anonymous": "never", + "named": "never", + "asyncArrow": "always" + }], + "func-style": ["warn", "declaration", {"allowArrowFunctions": true}], + "id-length": ["warn", {"max": 40, "exceptions": ["i", "j", "x", "y", "_"]}], + "arrow-body-style": ["error", "as-needed"], + "new-cap": ["warn", { + "newIsCap": true, + "capIsNew": true + }], + "no-empty": ["error", { + "allowEmptyCatch": true + }], + "eol-last": ["error", "always"], + "no-console": "off", + "import/no-nodejs-modules": "error", + "import/order": ["warn", { + "groups": [ + "builtin", + "external", + "internal", + "parent", + "sibling", + "index" + ], + "newlines-between": "never" + }] + } +} diff --git a/maubot-src/maubot/management/frontend/.gitignore b/maubot-src/maubot/management/frontend/.gitignore new file mode 100644 index 0000000..97c5f10 --- /dev/null +++ b/maubot-src/maubot/management/frontend/.gitignore @@ -0,0 +1,5 @@ +/node_modules +/build +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/maubot-src/maubot/management/frontend/.sass-lint.yml b/maubot-src/maubot/management/frontend/.sass-lint.yml new file mode 100644 index 0000000..61fdcfc --- /dev/null +++ b/maubot-src/maubot/management/frontend/.sass-lint.yml @@ -0,0 +1,27 @@ +options: + merge-default-rules: false + formatter: html + max-warnings: 50 + +files: + include: 'src/style/**/*.sass' + +rules: + extends-before-mixins: 2 + extends-before-declarations: 2 + placeholder-in-extend: 2 + mixins-before-declarations: + - 2 + - exclude: + - breakpoint + - mq + no-warn: 1 + no-debug: 1 + hex-notation: + - 2 + - style: uppercase + indentation: + - 2 + - size: 4 + property-sort-order: + - 0 diff --git a/maubot-src/maubot/management/frontend/package.json b/maubot-src/maubot/management/frontend/package.json new file mode 100644 index 0000000..294c1f7 --- /dev/null +++ b/maubot-src/maubot/management/frontend/package.json @@ -0,0 +1,40 @@ +{ + "name": "maubot-manager", + "version": "0.1.1", + "private": true, + "author": "Tulir Asokan", + "license": "AGPL-3.0-or-later", + "repository": { + "type": "git", + "url": "git+https://github.com/maubot/maubot.git" + }, + "bugs": { + "url": "https://github.com/maubot/maubot/issues" + }, + "homepage": ".", + "dependencies": { + "react": "^17.0.2", + "react-ace": "^9.4.1", + "react-contextmenu": "^2.14.0", + "react-dom": "^17.0.2", + "react-json-tree": "^0.16.1", + "react-router-dom": "^5.3.0", + "react-scripts": "5.0.0", + "react-select": "^5.2.1", + "sass": "^1.34.1" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "browserslist": [ + "last 2 firefox versions", + "last 2 and_ff versions", + "last 2 chrome versions", + "last 2 and_chr versions", + "last 1 safari versions", + "last 1 ios_saf versions" + ] +} diff --git a/maubot-src/maubot/management/frontend/public/favicon.png b/maubot-src/maubot/management/frontend/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..43fab1b46aabf4a47fe171fa4489807bae7a4ccd GIT binary patch literal 13551 zcmeIZRa6~M@Gd$VcXtRLTsBT{f(3U8?(Xhv+&#hF2_6Wp0RlmS2X}V}&PEQu|2Yr$ z;lA9p&f|TWSu@k!)74d9RefC@t)e7@jzWS0006q|CrLE`0KMIU03?LBi@s}xB>-?Y z%SwuCcrTsiB4&^cdF-!;jen4_7o#H}rX>;sL*S^ei)drY&fM33H~R~uQj2E-7J6TH zC!Ddwmraw9bxQ)8%`g4E(j=LZ=@=0JS}}91*c^g|L24G>eXt-`z)jsE`SqCl#PwLj z;%Z>e`SEFHUfx;WT5V95@6FNIc%p~~mS%4wpdWl03J)=1K|=-lb%+Rnhz2kVfM#Z* z0}%cCSr35Y!c9QNM5z5RyU6pmI}hJC$jlhGZz;>KkHFrEB;nzdbK zW6~>eeGDTqQ;@Lh_jlGlVlzFjJdHFl#X>1S^;|DSLh@{?f6)$nW7K7Uoti_ zDn?B*WP|M%6zSQyr!KkTXIE#+ds5?Hj&2CapJOliU&D}lCEnV~x->uZEz8GVSwFv% zAKu&`7yFgf8X@d{VNNq=)G251NbUTI8&)fBsEu9;$n!6iujUMGVb9Q$s!ID~4vOM3 ztV_S0%`2YSuN!$CT={0I+vZKMc={AX?4$uAB6FQObR)d+Jj8=Z;v(PA`vg+CZf38{ zRP^~=siB!QqzK{vzJKvqz@HQRVt$DJ)qQmO!)14q4LZu}!)VRylrZJ`Jh^CjM?MzB zg|RC2Bam_Lw&gC2-mwZ=#>v6Z1=k6zrCT!U02!^$kNTlt@krR_20%fG1yInxXg6@b zb~lE)O?9Gt7sTBTut^JnheV@}?tPuwOucb$?w0M&SJzY+wflCs@mv0~n_IpQrgtEG zB!!HLbr@yAv$Qmpq}Fo)I?V!)3g8lAC26YWC_XG6{tK|PVmGiqqLosW_A#d;`G2Zx z6t?7ds@kjtQwut*@)@f1h7fp4IV=&M(#o&CzEJw3atM}^3?xBFFgH`o-h<(nuZr{;>|TS##P<-_;V<{EU(I!D7p zGWE@^O4TiVT*lU|KwxB4fQ#4!1ctyv8emuegg2|xg249z1i&wpdVr`GrdJ0<0KmRY zkGU7d7(fNg;B^2rV~}w*fC>Sz0CD)n|9|8EF9O?>t@mS?IxC}XpcN2uJ;htj;bmWR zh!L1FNQvZvcDjH*_=`1r z#%2G13)1UBRzz7Y5Xm^Wi8Bg*ANyXjQ^_;xBRhc}Su7=-nOKxq4_0WP7xhha=}<0< z5m)ltV)w?tKtkd|^7hDz+#8H@sR;1?RU%YJVL_zBdRzBuN&wu& zg^R$*Y$8_6HMnGw-HqT;Cm1cDU+H@2UOK!NKKIrir4~p9FZ@lnZH9RiFd{>z)lwK3 z8C}$n02F^E(;ofrxQHdhq67=}yz8bdqd_XBra0pjdGCXIW)4f>F3Ia~ad3WTCW&Em z7+e_$8rZde9KxUgd(`gi;Egadl)Su%937v&pPw{Vn6HjvK6QPseyk$!BMQD7j`=5y zu^0=?So3g~98&{e+@)bMV^`aC`UC)`CmpjLn>_^}B%DTFA z-@*2ds?c@;LF)zl+}1t;>vwX+X?i_P+t`+-H7jkS67tYihh8EW-s!9M z@4vrM3)X2O_vE6bd#`S(MPOkb1%EtduX@2%f>c5F>@I5HXpiKV<0k@zSKZF8($ovf zAY17eo$coOW~ny5wTpdsOc(-Cwaz*RFX?6%w<9`J@}gT#^H3qota83t9wiCL+VL=n zC#Vy0#l}~eACuC-XoTn6cOli-R>k2QOun{?a4B`(sqejO#Y~fSSWs_@$ zwoguK3xg5%Xl?I)?vOLdzc~-AMG(S}p15kXPE6?)8b=obs=(c1*&?xRQ@&b{h}I%;$% za>%=Tgd-%5EF3d%40z%0Z4A|x2WLkm%ATE0w(HqWJ@VX|{}fM`S!yqnTK|4p3A_vV zl9$YA)bHbcBS&LkV_)zm;kJHVLc`R|D4_|Z%=YR(4B>)tmYaQ%$XcSnXc=5gx5)S9 zH%87mU`iHeO73l7nqIP47FkL362PsfXo?#dVJ@{1{Tps5e_9yeeltB-4>h;gpRDm( zF+1|USUX?2)l-Mo8a65kydQVo+u;xhy44tXjw4G8=n|e@MCKqun~4*foZ5Y{XFOA9 zU5JA3g?xgUT;>z=xJiFrR%Kq#n8#8(CI!u0+ItmN3ttb*9~H;UdM+9{d2>lpO%R^? zG)0^2*$Lll|IWmfIecoHF}aidq)_4~a^<5w6e|rlE08UtA>N&pq}gqnv6Cs$*L1zc zn%o5k0e>a?!`)`rmP}hIss(hs&;#101v36~H(0U&2}yQEV~5vH5uR>}+h>FY>)=pU zL3-`(vlHtX2R%a^o}sq9k3rnR2^?HqJk|KYwF3MLOmD{GDt9EgnsPk9;vAeXM;_O@ z9+2-h`6YGAUhiE<%UN)wg3*4$-FjK@OZS_cEG=dnyw>a+Z}!72RFuhE0;9OY z01+6ZKJyl&Hy4LQ4;a>c98%6tw^MnqaBZt<{bPraKvtQ5X&Z1DZ7fevH|u}EO62Ms zt@xmF(LZhWTAU2=t87HNI; zSj6gxq{|TV`F7k$a;2`RGlYQMi1@-uHXaoV6HVa+=7F$2=H%3z6Gk&!JKg5gp90B5H{R7?B&CO=P)uA-shF zVYqhN`@MF=@dN&>_XShrvE%XKSxT}~C<11joQVtac%C+m-OKM^&0gzY46HWA zOr#2V`a61jgiVcv+BvmX{5vYQ3kA=6^K!B8LLWp4?g-}-Ec@DK=+R&6qQFAS>SCw0 z!+lz~@NWRK3Ab@yiMm5Dl6ZO1vSWlqgxT{c=~?2;?%iAa6OzkjHT?=TesZup-Z#jbR7EYV~LXvTRIb;5X_6xTT`SBn#gHi^ht zk+4~> zeYfLk5TpVYIQymN#Ao2V1>ZhDIZlvZ4F~KAjNLj*;v(4ZJr*@E6v2;^T$AL8`em)0 zP3BSYqf9wOm5DcTP?;gWO-&jGT-=mIQpY_i&R2zU1QX&)z-A!6i@(>e0Ya!gS^i$wDf5jNfqp;#g6 zkb&KKe!ZiHq+p(ap&gM7B(K1&3m$jPVfYQUlL1;fIwVaB43`&8jfo=o*t9|aZntvf zVJTFh*DG5B2CKy7MF=s0dh#_}NL2%jeS}U#{ zaktrVlp`2Zp6z#^^r1^PM%=__8UL@C@@Cio#($`z1YlJ+vg|+h!(UN|volqc{`)6y{>a<{PF`NhQn-Qk=dAsB z?t(bd!u9kvSo1!4P>Y*yN1i`PYwxJ3&m1K9iP}Bt9FPn;@fDSHhNMYi*N1+Rx}G== zw#3h}vkdw2E44Pk(}-z)8_vyvfxu)jFX!gl9;tv%}j02m-2JiMh@hw z#U0PzP;n6gA<@^Kk5jY^9M2d6yiRNO>`e} zA&O31(-GVA=+ANfDAr27`B;i|!}wDr{HBv7tx`?Ta~ve8@chUwT?Zr>2wJ_-wOcO4 z#@sdV#>eX-KhlIoFb7+H^4v})zfv(a8~GU28U?sr$^R35Q`&?gsJeB!x2Y859IAL`U@Rp(J(4@ly1+>x zr;as@iU$)=1#NlBaHK(LeXG87#$j-?t6OT@wMhkX60L+C!B4mdMxjN>1Wd4yEsI3c zUONGt^p6&Ub0&#XOhh{^G@fR|R#)!L-~Xclk6gC^|8i5+^D}|Y#0I2r?nOW z-xI?)?f6Bvh}p^3sZY2ybEYL*S=m0q?+C{9GdckB^R4Na`XL9W4gwc6NQ@!(@_5x* z3bH62DMQnZhZUo?KB+XzFBBLnk=2%LfhE1t_b&ZE-)rcSXJ^29)ok&{rYnnp=DIK? zB))5xDAKRAe-=tDZ;uUk5q#w2Wqp%=TD&NBN8sG+d)3(9WV+B#19oWZC)j&DMT<=) zt-i*!A1WM2KdqlUjoE3WxUSj>I`vV1%M(`amL}z47kwIcZ$qg3@xYV`vZNf-ap=IR ztim$p$|DYpW{4}_W>MQ;ejEvx@ zLTMV8X*-G-M4vh~E;9>`?{Oy}%szK~AP)9s|Ge98 z6;?w-O(_&MfHPN<+wGcaayRw#{I@JaXdfK@D0kbr{K&VWVfe}SS)kLhTlfPE$vu7k zrl)<(EQZtujCgdygMnlTstHb4w47r`a6rx>BQRnA=+&?vq`uDHamd?Hol>Woq;mfV zZKwGIz|KHZ-%${GF5A$5ll1p-seCwNio>?Kn|dUTBm}OtDcV;BV~oDawbN z8mtI!ynP=1?SAOUPr?78w9a4Aa#>YXa`XJ`4D0mSan-CKx7%yp^XQD*^Y3`w=Z~6= zd&Be2V^l~CB((+(U$)_jHdk!Ikn>YUFzGiGTh=%j-4Hl&VN)u|R$7>8xf(uWXQaVg z^!L1K6%L(BX&3Yi1U*y*F?1Y;h_kLQPEp&LR#;aL=1@7;b3$0n$30T{_nT1x_N(8KqmQ4( z*Ox5Czzi4GiB*3gYsO?Hd(x@m*;DX8*y&c_h@K-=Aybem5076?x-OQF#aLJ(p&5w1Hunvj{MNdg7K3wD%KSd_l^DZxD2}dRWTf=U~oyPTEEK{5Em3Hs(ww$ zQu@%gm&*=x0SD;D84bOk;3o0JQpFN&n1MRSm;Tw!5_dQ?D2Yozn?ug5FUx(p#j`=dq({6_Z;W{QE;m|#MDW^fL2^mi`+x*+3A zi8sjXM+BaoneXB^Y%?Tc4rSX8_47n<_b_`2es<8DJ#Q1CqZVcjx6~ZWv$j-21>S(a zY+e!@dVb`0ompq_nxwD-LO^&t7>lN%`ptS1kzflCl!;~mXk4GgQwV5f<`7V+rVh^1 zGGD@qJv-tF#;WLK;tu!eyMWH?G4(44-d%p1b~tQd?ZzFt&+>c*HU)RgWoT>E45!Wh&1bZYzWE;|uF5&)O&riVE%bhfe#XRj-L#J#+dvb2e31bmB;T#!87m* zVj4mCxfiJO9EVhgD+c0U>UOW^<{<_(Gg)x1eZiJ+b=Uy_CwKarP73bEid zn0r*92+rjSe2tUp`OTykjq9rzc3Y%sx7|+UzfG0V! z-K!(NriZCp?RP;L$>nwfdNH+P3N+yp;3tCL{Il5+8XKRG|A5u8&C`A^5Y&hk*nrg& zh*ew!$hiG1KfHfWa_6ha2*L^vs^y3I_3+pMtG&`0gA(H(>fJ=_g>};CJ09@;R%V#( z-&K|DhbfKT12GIZ(_gSUh28|HgKi)4K2VU7{+YR4k^n6yc%(h<_W}%0SfFz8iCzs{ z2tZGX0=5nM8tUhzI?A(tu`+VB=-yvc`kk@fYoE7A6LQeE%j{HqveJ2Z9}qX#=N3U% zq02Rq)dATXGXgvAOMG*2*dnbnEq`{vpRKz@ETN^JIyvGbrX?Kvf(;qZ=A+-E_n^s+ z?Aff%bs@y{@V~gN+l`;MT$xj1$7hpEGWiA5WzH@2zO>1Gkkvev!%&orD5cvD3I+YP zL=-}HFQ}OoH3WJI!HwU!CE=uLfNsvkA9;9C*YAFjc%)rd1Nq&~lq+7Qm~g(9GtXPg zPL=1$lsjiok$op<@m?f6pfL*2+=@JIynC&e%S(*Ce&bvI!LV83`h zVS3|n6CicNqFaCPI6y+5_^vGCs+%HI#W)O(LezCwRFZ$;^DuZD-XDm(JuT`B4u+f# z3kPF)D!7RJJ%}fpm1oJyN|BuV2&a+%#zWTMEGkY!r*t!p?Rx(%d$Kq-{=1IEOhxH& z#{g$+R&(DjIxUkufoa|KnsJT^A2{Ua1XX9N>pWE&8Bb)}CF~zSsh*JdNqveEvn~T4 zHX@swnN%e9F>D&y93r}d}sp8C4acYr~4-PJmpIowCDH#njFMCNvK5e%97 z#&lu8YUnwWVHy5+Gy>gk!&_wn5PN~d{G)DnRuwHT%>&|S4=QolpKYQim$eK(vu241 z&n}S(;0rJ|_bgrH?!SBtAkBUgr*~bh{dwhiX!$jaZMWzRm$#{)pg-50b#6Es*OWfL zSJs~#Ap%ZRtejbI-XTs(^gtkvY*y)GjJSl1z|Bmwhv#AWk9k~3&4lAqEyH9`P4|$- zDYH!bOse{{|4ZU&5BjIk$QeKU-CC!>{qV#~x@P~kkYtIr`yuDC+g=)pI0I}jdCET4fy4VP<%Hq-H9*hkqx^I6sMS6Ff-$ln{XP?N#>w7XkY{j{IDB4kUWyV0SL4iz?=l_w%4`}1s*En&S*OdOC3uJ3l>MYpu_GD8b z8m6~==gRC*PVKvBxkx+CIdmo6oGHM31_PmsG7{6jX!Uw3qCCHcOB&S}mkjgex_in0 zC75rXSrOAeBC4kW&Ojjl#M>z0eXl<31y@03AGpE!!BqI2=s%m`fdaEtS}~u6D;MkZ zr@?N0TQ`kN0!VtZzg>KMCq>0Mm0Hz&b@9(4&P-uJB5sM7i9|z;Cx@My1WlkoD3EVY zIR81sUCg>KegIR7f@Q4YYt>o7NlpXmov@*wiqc{A_cxNtrkO*bdgHTHsu<~Dxf*Y= znvmIO@yMAOoTTyjpHnKOVMiyrcMi;y>3r8@g)sG(ilmEwje11#DQYW9eqNBQKinw8 zx)Lva@)6PkA+`RS@PG08c#E9pOR5Ff9yU0?6yCmiFL!{FwfbC;&~Q-mJm;n~}_7FWaq|`k$MTW(a-`ZG<7jm=~RevRJc;Y>W&nW#K<}l;q?RHizfM z`Dn>PPaRmP@(Yhn+)LFG1*4f}1YVR>?W+d=>ivNBK13!x=B)THJ`>i?!~7k$dwmLp z$bIld-SAu2J!tSt{C3_yegJE+{NuDMX;Bj!ng1?As!SpnTV>X{Q0W&A95d$@T9RUv zU67@aSj%d3alRbA3E0`5UB5j9C3c+tc@`G_-_xQxryB19I~In}6>9q0CoZcA!f=W! zTS+!p(SXxAK%7(?1Vp_ow=g%=z#0qV5u~fU?R1oul%%)~Bp(o1iezCO2!?YW-ORx3 zV6`5m&8@%>#|d5__wqq>xig5r&T$8APOAzcUFP(+p<9{Ls$9*pe5T4xrKE3}%(rDH zbLzf42NnL_W&;3>z9m>c36|g~FnPl=8ZO2d$oYCQ(7^3oe+)!>RuSg0(Xw6 zoz5jymS^C23SdPGMlK0;mYn8w??YTSO`o^ z0~~lhv_>~$hv*T5B0T^tCBEPg71h_;SuBt5v(9gyqQ$r$*uHdf=g<4Lt zj1b0dUKq9=`R4@t*qEqpHHoIqg_BKly>G=enkX<|FdD19WwuHR^Hkb2RF{i$^J&rs zh`MU5J$w7MZoDgfZ}rtrX(Kpb$-*)ii6mA-#ovbqe;5|!*V;xd0v-P04ChJ8N~5ZS zpSk_ftpAnEwYc-)j?1mSeR{}|uxE?@CrTx+NHPEHd^(P>e}CAk4hx5lSwwT1o%{8L_^VqP{Dl5^%I0e{VRi)^z_{CGF5rh=@g6+skzpAN%-CV@$>whKSa1K_zV#WI~d6u-oKo^q|q?) zl5QNl&DmU>`08-a*YLPH967i7vM8xsJNrERehe#aTP7XuCnfaJw^W__!-sHAPA*14 zK2cM#!HatN=5r2mKxyFi?;fCTgt`T%axn)%j>u#%j;F?LRyD@-MV)le(bpBB8dodX znNM)nz*`QDfN^fNm&m>cH&;YtF75={)SUE7PQsz^6QBixXKoPH8L2pAF}Oou`)Tm- z;mL|XGb0uCh@n`Dak!skWqE$Qnj;o>QYK*Wc&A;G@E|pt)!bqENTHX+U28)hYw&$u z!G-VF{B{Fw4y0{4ixCNW2T?s-LvXqnK0>TI3o0`Hp~mj|R=ZgNQCR=1tet%#BT#>S z2KGWzWDb5ezOg`pKQxvr%X`T+^{;e7I1q^3zhv|A%p??3(p19!Yv0^VvTKO5Vhw)9 zxBQVDYpvF{yG7kn|2K|Y|Ci7~f{52qSdJ)IzYUT^69{}I%tA8z8jlp3HL39TBL6MK z3Jl-}9ndJYo6tn0Mw8f)xm)Dr`nqk;cT2MxsTscU`I_6D%cI^QA@Tf?0|Vy71IbBP zUCS0ieXz#_lV$!d zmrgww+0HQadex2`kN%W1(u8SChyP#@eTtBVh9DFf{9vQYf?`kcjCw@N3T{Q3b-Z$L zFg62RY1jl1{Lw6P#E06MKZlb6xna2h;lm(qKBm>DS^H2<4G)$f9~}^$+*pdoja+eS zP-s~QP_=W9`1tHwyPV?ntHFHc{VpHuWl5IeN%pgWJJz6YPxnRP6Tc!aEHxjUue9 z>N>2$Ag6H0Pf{qLX-7;H4iz0Vg;3~USH-Blxlz|iC0Z(}@F=#ke=)X~IR@+*)@4+` z4|!a2DA({DUJ+;cHerKD^6qQztzLe}lieNY(*Mvn(tZFBRayQ?3-uVAz0d+o8EW#b z6%L0RnJPAov9E7#hRa~g$hi|u@OzB_Rit^L2#@GJaTD1}H0f#iJepQ(H-5*!C*_xJ z*;OnpAYtBK=|s^<)W^KWY)?h^pw_v$Z`n|dHx$-h8X|#-%T*FXk}r_}D~<`fSKV*g z%$$B1Ove$np=Q<<#~u}|Ws*_zU$FfnS!@&Dm==0qw`C!Q9}#%)*==uhO6e&H3W4e0 z4<=b>U}i2Z8r~Cka%yp><(vYEf=p32#AYpj@k$m3#0toGj+r|*W(zmWIgZ73i1@B48*69T?!lOTO;yeYO-ot+L zzsA{*dJ}m&laa z-+K9+cc-O@jSBcGqYHSc`aI8R)_vK`!}LGNz6`M{*IcB0SMR*;z`LwB`-_cc(5W7F5oFSGJd1BFbeqR>}b`VsF&$N-WR!;Z$s?4U=l7jaM^XyI|J3_94+ z(&VQ-o+I%V;YZ&&MUzG?jSdfIeou~^K_&<}5KlFpzr71}0|HMk%ky6w_JpVQ#J=wF}r(z+2e9^JwvFfJE)REC7B9z6X@b1r%LHD(L z!V0hPm@(;2_k2tCu5{~_yuFs(1*n*1BAt&!75xg18#_l|2|%d9*avhg&r^{g0?5Y^ zzC7>8aP8SU8kl;UNS)O}M@fB-J)uSzqD-VZ5!-;Xp?qIsI7XP5$AJ)9dMyNrCclo3 z-P!F^hZ;^j7ZoSSywXU{&|6;F+1|&y^)TeV{$lHNljUKS7G=yCvhcL?h5Pe?Pw(_K z5Ki#|QV5Pu+CD_tdjH5VY+GPd3-$ARwz;83P+zncUAj2kf1xy1ufLi&(J)d+zUN3X zMN|J!yrJjg{O20cw~AG@PhoZs_4VC>i($J#jPfYi`>dvx;@;eM80GD&V6_uh)PXLcILAx* z@{@KzG33p-^Rw#8(xEmHTJ0QaBUMS`j;RuCE{->DQ%X2l)-;hbRP&zYX0-cxts*-c zxFJOXGE+R(q=yQ@=YV+1!aS9vWf2YC5HlFLW!}oLs%OZn#{!1%rc=B})30tWC%koD z*LmIlZs|@*IP(0p^8Qbe599)8sJ`+}cSyXZYu_67E^(7VQeXRG0Ul4+em-z-dGDrX zFu*zb`-Wzcn1#++sH}iWD)gTrT6P{ayEKVx!?RvUmDMOs_ABFnWPS9lsO>9s4qZO2 z?n~tlYEUYyEE-s$p}Z=U>t`4U)8eB_k&IBe^lysYTNf-$A%9;CuFO>{e(-s|pZ5yI zm@Fa_dB-nM-1<3rp1=cE_!nO(4^M^8YW(n*B*ja|pr;8#A+j^U=JaNJ0VeVv;YSh6 zXPxPsjn`I$gZ-g!uo-p}3VS#aCcg+0O^d0VV9xXwsb-8pJzc6;JC6tiGXZV<(K9)lYgJq0c>$g#u)XcoMC}`-% zU?0RBDA}V@7+Cm;Z9KfVfH>bEqocX^<3WAwZR@zdSAtAVzo09I{_4drx@+vmGyGU5 zhty@^t*|~mENaTy6r6g3eUAnII){>4*;?e~!F}F_+tdAyUy|`r_lD53WZ&vT$Zhvl z{@(P8#0}3`Rjc6Et4aDD@!bm7_wjg#7$@S}SJ9joXd-kEZz5Rz>HJctVnQs$J6;Am ze{rx2?>p<=r2+g4dm#o#`8f04yH}_fs7LSIaKpBlIqOCnPu;GjR}zz&s(+CQdI@#vBys84pzF=@z`VBtO9=)| z3{gbT(%F*?m&87|&F=4sxJP7`WZ0sJ0pR?G_0u{8P~Xb>^Auv=pYBaFgZKTcp~O^& z5HbuwP3<%k_&M#duc*w7taB@0WCCE>mb{uoE}*gB7+42$Hm+|lr@GC8XSj!;PYq;4 z-wsxTz9K)19tDX0*~cuaY0TDLMkD*j>wEQ9bR0mrau*KRKZ#ZUtstFs6!V6PuJ#BT z@3*f#IS@i!&;JUlNcmvzniI=lvSsQ?SN`6EaehRMth^oDRrOzg-yLM3mMfaJt@E{^ zJ*fCqRH^&?*yZ-={Sn0^rY{b9R^+<(Z7Ro2hb5tV-)(*y}HvoRVo{n#q=wy4zdzB8LLu z%k#XE|8?SxNPYYcOa+Z130P9n#wTl)#G^7w?I_mlnw;`jXhQY+p-#o3)#Tlb66=f!v{Ulc1iC$EK5_x=?*rG($$ zRLEL4=v&qN9dT61%T@kcxp=?8@?4yla1Wk9(J@E$DMRY>bKe)dJ=M85>MZqS<;veH zaK;(llY(GLD^gt>mDv~c^sI_T`Ifds%E+wwe7~J9p2ecm+q>h5rOdLwMX}i_X3roX zg#4zlrj8JrgB*-@6Q%caV@!o7ad@Ugbb(DCH&dAr1SI61Grt?r5mY-yFpYvPNfT{a z!oqwV0z9_~?NNlOQC{M=9OMj~g7;00l(a4a-%I&uWaLZmX%IF5V1*o2ctF4Fuk?7$ zJKqii-{(OY*sOopX2KM{|L|9l*2Ax?Mm8wk_BNPN8Qw=jn~CYjDUFfBgPaFI2cCWh z_lKzMP!tdn!xaZ=Z%WqU<;yBsKaq;xQ_h*^ec0y5I)~=TX9D(&!A3Z)G1`Ico9TwseTin~nEB^7c#~kK zKnd#7ISP>nTLK1>BG^g(F8zP=`E&l{Y=n+ivy{eNCy586^$%pem4UWT<8k8h`$QOw z_xL|#ze+UP=r99BIGz0W^2a?dCwn{BCrO__;^5|R7gtA3tEDdD7-z^rMtKw*-mOX- zKxXGx+pltip3l~8TWsXdx=MbdmAEd$uD8~i|4pIadft9h+ILo%L9GwNxB29=jx#90 zuZPG1XjzFBeJ%94=fTK#9EdO}Ly&kDreA+acY3WH+D1N@n?Vul*3nA&vM0JQ1Pkg)HXpgl9;r~(R3$k+UbP(itUmY{)6XI-l`=ZMTAwCkpG z!Hc!T7G5JE+!Oo(|IGvXPQ2d%`Sb)kk4yxyWars=nn|5Iwe0KJ20AWormnVMSCf+z z-vs%tZhq#N*z?D&XS4s3x8-X>BjS41jQ5#P%>9X_ndT7Rfbs z4dMy78V>O{p)z@H@Z9Jpfp{bde*Z%>*zhJVVTP5Ambw6Qan|#g>(U0MreT7V($5<- zpXhVR;Ui3>(Jha}mniV=*~W2h%+t3&+ZA7w+YxBusYQnen~Xt1)|BT_{pu_^M1w7f zwoID0b3Rd(#E35qLz|NCa!kH7;8grj9fl5Yg1>8_3a=#|f5}d5SjBjS38R#1q_z9| zyMZFhgf6Eq*+Q&QixBTR>h${3oD&6-X{SW;Swp<{SaRI%ri*LsO_1{790GVRYjfh+ zPHoiA$HkI7Za*dzG49^^B>wLeKa;@UX>I?0)8Uu7HK~S0sm!h=v}Nhfx&a%oj~(rs zO~2%!DR_aR@R30N*s|hvR1C;8%O^C;&X~CU)tL>5;VQ_D(k4<=QibH?KJgBD$qq~N zX%X. +--> + + + + + + + + + + + + Maubot Manager + + + +